Compare commits
	
		
			No commits in common. "bd8270bd5dc814222bb9b5f74820dd9d13714533" and "3271ca514c9243877df5a62cbe8650860da27d7e" have entirely different histories.
		
	
	
		
			bd8270bd5d
			...
			3271ca514c
		
	
		| 
						 | 
				
			
			@ -19,7 +19,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 | 
			
		|||
    - Boolean map (tag)
 | 
			
		||||
    - Member access (e.g. `.objective` to get objective name where int is stored)
 | 
			
		||||
- Return statement
 | 
			
		||||
- internal `print` function
 | 
			
		||||
- Example: barebones compiler
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ FunctionParameterList:
 | 
			
		|||
 | 
			
		||||
```ebnf
 | 
			
		||||
ArrayVariableDeclaration:
 | 
			
		||||
    ('int' | 'bool') '[' integer ']' identifier VariableDeclarationAssignment?
 | 
			
		||||
    ('int' | 'bool') identifier '[' integer ']' VariableDeclarationAssignment?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## ComptimeValueDeclaration
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,11 @@ pub enum Error {
 | 
			
		|||
    #[error(transparent)]
 | 
			
		||||
    LexicalError(#[from] crate::lexical::Error),
 | 
			
		||||
    #[error(transparent)]
 | 
			
		||||
    ParseError(#[from] Box<crate::syntax::error::Error>),
 | 
			
		||||
    ParseError(#[from] crate::syntax::error::Error),
 | 
			
		||||
    #[error(transparent)]
 | 
			
		||||
    SemanticError(#[from] crate::semantic::error::Error),
 | 
			
		||||
    #[error(transparent)]
 | 
			
		||||
    TranspileError(#[from] Box<crate::transpile::TranspileError>),
 | 
			
		||||
    TranspileError(#[from] crate::transpile::TranspileError),
 | 
			
		||||
    #[error("An error occurred: {0}")]
 | 
			
		||||
    Other(String),
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ pub trait FileProvider {
 | 
			
		|||
    /// # Errors
 | 
			
		||||
    /// - If an error occurs while reading the file.
 | 
			
		||||
    /// - If the file does not exist.
 | 
			
		||||
    fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, [u8]>, Error>;
 | 
			
		||||
    fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<[u8]>, Error>;
 | 
			
		||||
 | 
			
		||||
    /// Reads the contents of the file at the given path.
 | 
			
		||||
    ///
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ pub trait FileProvider {
 | 
			
		|||
    /// - If an error occurs while reading the file.
 | 
			
		||||
    /// - If the file does not exist.
 | 
			
		||||
    /// - If the file is not valid UTF-8.
 | 
			
		||||
    fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, str>, Error> {
 | 
			
		||||
    fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<str>, Error> {
 | 
			
		||||
        let bytes = self.read_bytes(path)?;
 | 
			
		||||
        let string = std::str::from_utf8(&bytes)
 | 
			
		||||
            .map_err(|err| {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,14 +57,14 @@ where
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
impl FileProvider for FsProvider {
 | 
			
		||||
    fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, [u8]>, Error> {
 | 
			
		||||
    fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<[u8]>, Error> {
 | 
			
		||||
        let full_path = self.root.join(path);
 | 
			
		||||
        std::fs::read(full_path)
 | 
			
		||||
            .map(Cow::Owned)
 | 
			
		||||
            .map_err(Error::from)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, str>, Error> {
 | 
			
		||||
    fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<str>, Error> {
 | 
			
		||||
        let full_path = self.root.join(path);
 | 
			
		||||
        std::fs::read_to_string(full_path)
 | 
			
		||||
            .map(Cow::Owned)
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +178,7 @@ mod vfs {
 | 
			
		|||
    use shulkerbox::virtual_fs::{VFile, VFolder};
 | 
			
		||||
 | 
			
		||||
    impl FileProvider for VFolder {
 | 
			
		||||
        fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, [u8]>, Error> {
 | 
			
		||||
        fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Cow<[u8]>, Error> {
 | 
			
		||||
            normalize_path_str(path).map_or_else(
 | 
			
		||||
                || Err(Error::from(std::io::ErrorKind::InvalidData)),
 | 
			
		||||
                |path| {
 | 
			
		||||
| 
						 | 
				
			
			@ -189,7 +189,7 @@ mod vfs {
 | 
			
		|||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<'_, str>, Error> {
 | 
			
		||||
        fn read_str<P: AsRef<Path>>(&self, path: P) -> Result<Cow<str>, Error> {
 | 
			
		||||
            normalize_path_str(path).map_or_else(
 | 
			
		||||
                || Err(Error::from(std::io::ErrorKind::InvalidData)),
 | 
			
		||||
                |path| {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ impl SourceFile {
 | 
			
		|||
 | 
			
		||||
    /// Get the [`SourceIterator`] for the source file.
 | 
			
		||||
    #[must_use]
 | 
			
		||||
    pub fn iter(self: &Arc<Self>) -> SourceIterator<'_> {
 | 
			
		||||
    pub fn iter<'a>(self: &'a Arc<Self>) -> SourceIterator<'a> {
 | 
			
		||||
        SourceIterator {
 | 
			
		||||
            source_file: self,
 | 
			
		||||
            iterator: self.content().char_indices().peekable(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -161,7 +161,7 @@ pub enum Token {
 | 
			
		|||
    DocComment(DocComment),
 | 
			
		||||
    CommandLiteral(CommandLiteral),
 | 
			
		||||
    StringLiteral(StringLiteral),
 | 
			
		||||
    MacroStringLiteral(Box<MacroStringLiteral>),
 | 
			
		||||
    MacroStringLiteral(MacroStringLiteral),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SourceElement for Token {
 | 
			
		||||
| 
						 | 
				
			
			@ -325,7 +325,7 @@ pub struct StringLiteral {
 | 
			
		|||
impl StringLiteral {
 | 
			
		||||
    /// Returns the string content without escapement characters, leading and trailing double quotes.
 | 
			
		||||
    #[must_use]
 | 
			
		||||
    pub fn str_content(&self) -> Cow<'_, str> {
 | 
			
		||||
    pub fn str_content(&self) -> Cow<str> {
 | 
			
		||||
        let string = self.span.str();
 | 
			
		||||
        let string = &string[1..string.len() - 1];
 | 
			
		||||
        if string.contains('\\') {
 | 
			
		||||
| 
						 | 
				
			
			@ -740,7 +740,7 @@ impl Token {
 | 
			
		|||
                handler.receive(error::Error::from(UnterminatedDelimitedComment {
 | 
			
		||||
                    span: Span::new(iter.source_file().clone(), start, start + 2).unwrap(),
 | 
			
		||||
                }));
 | 
			
		||||
                Err(TokenizeError::FatalLexicalError)
 | 
			
		||||
                return Err(TokenizeError::FatalLexicalError);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // When there is no second slash and at the start of a line
 | 
			
		||||
| 
						 | 
				
			
			@ -883,14 +883,14 @@ impl Token {
 | 
			
		|||
            }
 | 
			
		||||
            .into())
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(Box::new(MacroStringLiteral {
 | 
			
		||||
            Ok(MacroStringLiteral {
 | 
			
		||||
                starting_backtick,
 | 
			
		||||
                parts,
 | 
			
		||||
                ending_backtick: Punctuation {
 | 
			
		||||
                    span: Self::create_span(start, iter),
 | 
			
		||||
                    punctuation: '`',
 | 
			
		||||
                },
 | 
			
		||||
            })
 | 
			
		||||
            }
 | 
			
		||||
            .into())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ pub fn parse(
 | 
			
		|||
    tracing::info!("Parsing the source code at path: {}", path.display());
 | 
			
		||||
 | 
			
		||||
    let mut parser = Parser::new(&tokens);
 | 
			
		||||
    let program = parser.parse_program(handler).map_err(Box::new)?;
 | 
			
		||||
    let program = parser.parse_program(handler)?;
 | 
			
		||||
 | 
			
		||||
    if handler.has_received() {
 | 
			
		||||
        return Err(Error::other(
 | 
			
		||||
| 
						 | 
				
			
			@ -165,9 +165,8 @@ where
 | 
			
		|||
 | 
			
		||||
    tracing::info!("Transpiling the source code.");
 | 
			
		||||
 | 
			
		||||
    let datapack = Transpiler::new(main_namespace_name, pack_format)
 | 
			
		||||
        .transpile(&programs, handler)
 | 
			
		||||
        .map_err(Box::new)?;
 | 
			
		||||
    let datapack =
 | 
			
		||||
        Transpiler::new(main_namespace_name, pack_format).transpile(&programs, handler)?;
 | 
			
		||||
 | 
			
		||||
    if handler.has_received() {
 | 
			
		||||
        return Err(Error::other(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ pub enum Error {
 | 
			
		|||
 | 
			
		||||
/// An error that occurs when a function declaration is missing.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct UnexpectedExpression(pub Box<Expression>);
 | 
			
		||||
pub struct UnexpectedExpression(pub Expression);
 | 
			
		||||
 | 
			
		||||
impl Display for UnexpectedExpression {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ fn get_global_scope(declarations: &[Declaration]) -> SemanticScope<'static> {
 | 
			
		|||
impl Namespace {
 | 
			
		||||
    /// Analyzes the semantics of the namespace.
 | 
			
		||||
    fn analyze_semantics(&self, handler: &impl Handler<base::Error>) -> Result<(), error::Error> {
 | 
			
		||||
        let name = self.name();
 | 
			
		||||
        let name = self.namespace_name();
 | 
			
		||||
        Self::validate_str(name.str_content().as_ref()).map_err(|invalid_chars| {
 | 
			
		||||
            let err = error::Error::from(InvalidNamespaceName {
 | 
			
		||||
                name: name.clone(),
 | 
			
		||||
| 
						 | 
				
			
			@ -393,22 +393,12 @@ impl Assignment {
 | 
			
		|||
 | 
			
		||||
        if let Some(variable_type) = variable_type {
 | 
			
		||||
            let expected = match variable_type {
 | 
			
		||||
                VariableType::BooleanStorage => ValueType::Boolean,
 | 
			
		||||
                VariableType::BooleanStorage | VariableType::Tag => ValueType::Boolean,
 | 
			
		||||
                VariableType::ScoreboardValue => ValueType::Integer,
 | 
			
		||||
                VariableType::ComptimeValue => {
 | 
			
		||||
                    // TODO: check if the expression is a constant expression
 | 
			
		||||
                    return Ok(());
 | 
			
		||||
                }
 | 
			
		||||
                VariableType::BooleanStorageArray | VariableType::Tag
 | 
			
		||||
                    if matches!(self.destination(), AssignmentDestination::Indexed(..)) =>
 | 
			
		||||
                {
 | 
			
		||||
                    ValueType::Boolean
 | 
			
		||||
                }
 | 
			
		||||
                VariableType::Scoreboard | VariableType::ScoreboardArray
 | 
			
		||||
                    if matches!(self.destination(), AssignmentDestination::Indexed(..)) =>
 | 
			
		||||
                {
 | 
			
		||||
                    ValueType::Integer
 | 
			
		||||
                }
 | 
			
		||||
                _ => {
 | 
			
		||||
                    let err = error::Error::AssignmentError(AssignmentError {
 | 
			
		||||
                        identifier: self.destination().span(),
 | 
			
		||||
| 
						 | 
				
			
			@ -571,7 +561,7 @@ impl Primary {
 | 
			
		|||
                        VariableType::Function | VariableType::InternalFunction => Ok(()),
 | 
			
		||||
                        _ => {
 | 
			
		||||
                            let err = error::Error::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                                Box::new(Expression::Primary(self.clone())),
 | 
			
		||||
                                Expression::Primary(self.clone()),
 | 
			
		||||
                            ));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
| 
						 | 
				
			
			@ -716,14 +706,13 @@ impl Primary {
 | 
			
		|||
                _ => false,
 | 
			
		||||
            },
 | 
			
		||||
            Self::MemberAccess(_) => {
 | 
			
		||||
                // TODO: correct return value after check
 | 
			
		||||
                // TODO:
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
            Self::Identifier(ident) => match scope.get_variable(ident.span.str()) {
 | 
			
		||||
                Some(VariableType::BooleanStorage) => expected == ValueType::Boolean,
 | 
			
		||||
                Some(VariableType::ScoreboardValue) => expected == ValueType::Integer,
 | 
			
		||||
                Some(VariableType::Tag) => expected == ValueType::String,
 | 
			
		||||
                Some(VariableType::ComptimeValue) => true,
 | 
			
		||||
                _ => false,
 | 
			
		||||
            },
 | 
			
		||||
            Self::Prefix(prefixed) => match prefixed.operator() {
 | 
			
		||||
| 
						 | 
				
			
			@ -941,10 +930,9 @@ impl MacroStringLiteral {
 | 
			
		|||
                MacroStringLiteralPart::MacroUsage { identifier, .. } => {
 | 
			
		||||
                    if let Some(variable_type) = scope.get_variable(identifier.span.str()) {
 | 
			
		||||
                        if variable_type != VariableType::MacroParameter {
 | 
			
		||||
                            let err =
 | 
			
		||||
                                error::Error::UnexpectedExpression(UnexpectedExpression(Box::new(
 | 
			
		||||
                                    Expression::Primary(Primary::Identifier(identifier.clone())),
 | 
			
		||||
                                )));
 | 
			
		||||
                            let err = error::Error::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                                Expression::Primary(Primary::Identifier(identifier.clone())),
 | 
			
		||||
                            ));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            errs.push(err);
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ impl<'a> Parser<'a> {
 | 
			
		|||
                            }
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
 | 
			
		||||
                    return Err(err);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
 | 
			
		|||
                expected: SyntaxKind::Punctuation(expected),
 | 
			
		||||
                found: self.get_reading(None).into_token(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            handler.receive(err.clone());
 | 
			
		||||
 | 
			
		||||
            return Err(err);
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,7 @@ impl<'a> Parser<'a> {
 | 
			
		|||
                expected: SyntaxKind::Punctuation(expected),
 | 
			
		||||
                found: self.peek().into_token(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            handler.receive(err.clone());
 | 
			
		||||
            return Err(err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ impl Frame<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Identifier,
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +432,7 @@ impl Frame<'_> {
 | 
			
		|||
                    expected: SyntaxKind::StringLiteral,
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -447,13 +447,13 @@ impl Frame<'_> {
 | 
			
		|||
        handler: &impl Handler<base::Error>,
 | 
			
		||||
    ) -> ParseResult<MacroStringLiteral> {
 | 
			
		||||
        match self.next_significant_token() {
 | 
			
		||||
            Reading::Atomic(Token::MacroStringLiteral(literal)) => Ok(*literal),
 | 
			
		||||
            Reading::Atomic(Token::MacroStringLiteral(literal)) => Ok(literal),
 | 
			
		||||
            found => {
 | 
			
		||||
                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
			
		||||
                    expected: SyntaxKind::MacroStringLiteral,
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -469,13 +469,13 @@ impl Frame<'_> {
 | 
			
		|||
    ) -> ParseResult<AnyStringLiteral> {
 | 
			
		||||
        match self.next_significant_token() {
 | 
			
		||||
            Reading::Atomic(Token::StringLiteral(literal)) => Ok(literal.into()),
 | 
			
		||||
            Reading::Atomic(Token::MacroStringLiteral(literal)) => Ok((*literal).into()),
 | 
			
		||||
            Reading::Atomic(Token::MacroStringLiteral(literal)) => Ok(literal.into()),
 | 
			
		||||
            found => {
 | 
			
		||||
                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
			
		||||
                    expected: SyntaxKind::AnyStringLiteral,
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -499,7 +499,7 @@ impl Frame<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Keyword(expected),
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -530,7 +530,7 @@ impl Frame<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Punctuation(expected),
 | 
			
		||||
                    found: found.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
//! Syntax tree nodes for declarations.
 | 
			
		||||
 | 
			
		||||
#![expect(missing_docs)]
 | 
			
		||||
#![expect(clippy::struct_field_names)]
 | 
			
		||||
#![allow(missing_docs)]
 | 
			
		||||
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -392,7 +391,7 @@ impl Parser<'_> {
 | 
			
		|||
 | 
			
		||||
                declaration
 | 
			
		||||
                    .with_annotation(annotation)
 | 
			
		||||
                    .inspect_err(|err| handler.receive(Box::new(err.clone())))
 | 
			
		||||
                    .inspect_err(|err| handler.receive(err.clone()))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Reading::Atomic(Token::Keyword(from_keyword))
 | 
			
		||||
| 
						 | 
				
			
			@ -442,7 +441,7 @@ impl Parser<'_> {
 | 
			
		|||
                        expected: SyntaxKind::Punctuation('*'),
 | 
			
		||||
                        found: self.stop_at_significant().into_token(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +511,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Declaration,
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +562,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Keyword(KeywordKind::Function),
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -616,7 +615,7 @@ impl Parser<'_> {
 | 
			
		|||
                    ]),
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -666,7 +666,7 @@ impl Parser<'_> {
 | 
			
		|||
                // eat the macro string literal
 | 
			
		||||
                self.forward();
 | 
			
		||||
 | 
			
		||||
                Ok(Primary::MacroStringLiteral(*macro_string_literal))
 | 
			
		||||
                Ok(Primary::MacroStringLiteral(macro_string_literal))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // lua code expression
 | 
			
		||||
| 
						 | 
				
			
			@ -687,7 +687,7 @@ impl Parser<'_> {
 | 
			
		|||
                                expected: syntax::error::SyntaxKind::Identifier,
 | 
			
		||||
                                found: unexpected.into_token(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
| 
						 | 
				
			
			@ -741,7 +741,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: syntax::error::SyntaxKind::Expression,
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -829,7 +829,7 @@ impl Parser<'_> {
 | 
			
		|||
                        expected: syntax::error::SyntaxKind::Operator,
 | 
			
		||||
                        found: Some(Token::Punctuation(punc)),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -838,7 +838,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: syntax::error::SyntaxKind::Operator,
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -388,7 +388,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Punctuation('#'),
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,10 +52,10 @@ pub struct ProgramFile {
 | 
			
		|||
pub struct Namespace {
 | 
			
		||||
    /// The `namespace` keyword.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    keyword: Keyword,
 | 
			
		||||
    namespace_keyword: Keyword,
 | 
			
		||||
    /// The name of the namespace.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    name: StringLiteral,
 | 
			
		||||
    namespace_name: StringLiteral,
 | 
			
		||||
    /// The semicolon.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    semicolon: Punctuation,
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ pub struct Namespace {
 | 
			
		|||
 | 
			
		||||
impl SourceElement for Namespace {
 | 
			
		||||
    fn span(&self) -> Span {
 | 
			
		||||
        self.keyword
 | 
			
		||||
        self.namespace_keyword
 | 
			
		||||
            .span()
 | 
			
		||||
            .join(&self.semicolon.span())
 | 
			
		||||
            .expect("Invalid span")
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ impl Namespace {
 | 
			
		|||
    /// Dissolves the namespace into its components.
 | 
			
		||||
    #[must_use]
 | 
			
		||||
    pub fn dissolve(self) -> (Keyword, StringLiteral, Punctuation) {
 | 
			
		||||
        (self.keyword, self.name, self.semicolon)
 | 
			
		||||
        (self.namespace_keyword, self.namespace_name, self.semicolon)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Validates a namespace string.
 | 
			
		||||
| 
						 | 
				
			
			@ -112,19 +112,19 @@ impl Parser<'_> {
 | 
			
		|||
        tracing::debug!("Parsing program");
 | 
			
		||||
 | 
			
		||||
        let namespace = match self.stop_at_significant() {
 | 
			
		||||
            Reading::Atomic(Token::Keyword(keyword))
 | 
			
		||||
                if keyword.keyword == KeywordKind::Namespace =>
 | 
			
		||||
            Reading::Atomic(Token::Keyword(namespace_keyword))
 | 
			
		||||
                if namespace_keyword.keyword == KeywordKind::Namespace =>
 | 
			
		||||
            {
 | 
			
		||||
                // eat the keyword
 | 
			
		||||
                self.forward();
 | 
			
		||||
 | 
			
		||||
                let name = self.parse_string_literal(handler)?;
 | 
			
		||||
                let namespace_name = self.parse_string_literal(handler)?;
 | 
			
		||||
 | 
			
		||||
                let semicolon = self.parse_punctuation(';', true, handler)?;
 | 
			
		||||
 | 
			
		||||
                Ok(Namespace {
 | 
			
		||||
                    keyword,
 | 
			
		||||
                    name,
 | 
			
		||||
                    namespace_keyword,
 | 
			
		||||
                    namespace_name,
 | 
			
		||||
                    semicolon,
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -133,14 +133,14 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::Keyword(KeywordKind::Namespace),
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }?;
 | 
			
		||||
 | 
			
		||||
        tracing::debug!(
 | 
			
		||||
            "Found namespace '{}', parsing declarations",
 | 
			
		||||
            namespace.name.str_content()
 | 
			
		||||
            namespace.namespace_name.str_content()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let mut declarations = Vec::new();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -493,7 +493,7 @@ impl SingleVariableDeclaration {
 | 
			
		|||
///
 | 
			
		||||
/// ```ebnf
 | 
			
		||||
/// ArrayVariableDeclaration:
 | 
			
		||||
///     ('int' | 'bool') '[' integer ']' identifier VariableDeclarationAssignment?
 | 
			
		||||
///     ('int' | 'bool') identifier '[' integer ']' VariableDeclarationAssignment?
 | 
			
		||||
/// ```
 | 
			
		||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
 | 
			
		||||
| 
						 | 
				
			
			@ -501,6 +501,9 @@ pub struct ArrayVariableDeclaration {
 | 
			
		|||
    /// The type of the variable.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    variable_type: Keyword,
 | 
			
		||||
    /// The identifier of the variable.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    identifier: Identifier,
 | 
			
		||||
    /// The opening bracket of the array.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    open_bracket: Punctuation,
 | 
			
		||||
| 
						 | 
				
			
			@ -510,9 +513,6 @@ pub struct ArrayVariableDeclaration {
 | 
			
		|||
    /// The closing bracket of the array.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    close_bracket: Punctuation,
 | 
			
		||||
    /// The identifier of the variable.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    identifier: Identifier,
 | 
			
		||||
    /// The optional assignment of the variable.
 | 
			
		||||
    #[get = "pub"]
 | 
			
		||||
    assignment: Option<VariableDeclarationAssignment>,
 | 
			
		||||
| 
						 | 
				
			
			@ -798,7 +798,7 @@ pub enum AssignmentDestination {
 | 
			
		|||
    /// Assignment to an identifier.
 | 
			
		||||
    Identifier(Identifier),
 | 
			
		||||
    /// Assignment to an indexed identifier.
 | 
			
		||||
    Indexed(Identifier, Punctuation, Box<Expression>, Punctuation),
 | 
			
		||||
    Indexed(Identifier, Punctuation, Expression, Punctuation),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SourceElement for AssignmentDestination {
 | 
			
		||||
| 
						 | 
				
			
			@ -872,7 +872,7 @@ impl Parser<'_> {
 | 
			
		|||
 | 
			
		||||
                statement
 | 
			
		||||
                    .with_annotation(annotation)
 | 
			
		||||
                    .inspect_err(|err| handler.receive(Box::new(err.clone())))
 | 
			
		||||
                    .inspect_err(|err| handler.receive(err.clone()))
 | 
			
		||||
            }
 | 
			
		||||
            // variable declaration
 | 
			
		||||
            Reading::Atomic(Token::CommandLiteral(command)) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -971,12 +971,7 @@ impl Parser<'_> {
 | 
			
		|||
                                let close = tree.close;
 | 
			
		||||
                                let expression = tree.tree?;
 | 
			
		||||
 | 
			
		||||
                                AssignmentDestination::Indexed(
 | 
			
		||||
                                    identifier,
 | 
			
		||||
                                    open,
 | 
			
		||||
                                    Box::new(expression),
 | 
			
		||||
                                    close,
 | 
			
		||||
                                )
 | 
			
		||||
                                AssignmentDestination::Indexed(identifier, open, expression, close)
 | 
			
		||||
                            }
 | 
			
		||||
                            _ => AssignmentDestination::Identifier(identifier),
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,7 +1036,7 @@ impl Parser<'_> {
 | 
			
		|||
                    ]),
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                return Err(err);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -1058,7 +1053,11 @@ impl Parser<'_> {
 | 
			
		|||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let index = match self.stop_at_significant() {
 | 
			
		||||
        // read identifier
 | 
			
		||||
        self.stop_at_significant();
 | 
			
		||||
        let identifier = self.parse_identifier(handler)?;
 | 
			
		||||
 | 
			
		||||
        match self.stop_at_significant() {
 | 
			
		||||
            Reading::IntoDelimited(punc)
 | 
			
		||||
                if punc.punctuation == '['
 | 
			
		||||
                    && matches!(variable_type.keyword, KeywordKind::Int | KeywordKind::Bool) =>
 | 
			
		||||
| 
						 | 
				
			
			@ -1081,7 +1080,7 @@ impl Parser<'_> {
 | 
			
		|||
                                    expected: SyntaxKind::Integer,
 | 
			
		||||
                                    found: unexpected.into_token(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                            }
 | 
			
		||||
                        };
 | 
			
		||||
| 
						 | 
				
			
			@ -1095,72 +1094,67 @@ impl Parser<'_> {
 | 
			
		|||
                let close_bracket = tree.close;
 | 
			
		||||
                let inner = tree.tree?;
 | 
			
		||||
 | 
			
		||||
                Some((open_bracket, inner, close_bracket))
 | 
			
		||||
            }
 | 
			
		||||
            _ => None,
 | 
			
		||||
        };
 | 
			
		||||
                match inner {
 | 
			
		||||
                    IndexingType::IntegerSize(size) => {
 | 
			
		||||
                        let assignment = self
 | 
			
		||||
                            .try_parse(|p| {
 | 
			
		||||
                                // read equals sign
 | 
			
		||||
                                let equals = p.parse_punctuation('=', true, &VoidHandler)?;
 | 
			
		||||
 | 
			
		||||
        // read identifier
 | 
			
		||||
        self.stop_at_significant();
 | 
			
		||||
        let identifier = self.parse_identifier(handler)?;
 | 
			
		||||
                                // read expression
 | 
			
		||||
                                let expression = p.parse_expression(&VoidHandler)?;
 | 
			
		||||
 | 
			
		||||
        // TODO: allow assignment when map and array literals have been implemented
 | 
			
		||||
        let assignment = if index.is_none() {
 | 
			
		||||
            self.try_parse(|p| {
 | 
			
		||||
                // read equals sign
 | 
			
		||||
                let equals = p.parse_punctuation('=', true, &VoidHandler)?;
 | 
			
		||||
                                Ok(VariableDeclarationAssignment { equals, expression })
 | 
			
		||||
                            })
 | 
			
		||||
                            .ok();
 | 
			
		||||
 | 
			
		||||
                // read expression
 | 
			
		||||
                let expression = p.parse_expression(&VoidHandler)?;
 | 
			
		||||
 | 
			
		||||
                Ok(VariableDeclarationAssignment { equals, expression })
 | 
			
		||||
            })
 | 
			
		||||
            .ok()
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        match index {
 | 
			
		||||
            Some((open_bracket, IndexingType::IntegerSize(size), close_bracket)) => {
 | 
			
		||||
                Ok(VariableDeclaration::Array(ArrayVariableDeclaration {
 | 
			
		||||
                    variable_type,
 | 
			
		||||
                    identifier,
 | 
			
		||||
                    open_bracket,
 | 
			
		||||
                    size,
 | 
			
		||||
                    close_bracket,
 | 
			
		||||
                    assignment,
 | 
			
		||||
                    annotations: VecDeque::new(),
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            Some((open_bracket, IndexingType::None, close_bracket)) => {
 | 
			
		||||
                match variable_type.keyword {
 | 
			
		||||
                    KeywordKind::Int => Ok(VariableDeclaration::Score(ScoreVariableDeclaration {
 | 
			
		||||
                        int_keyword: variable_type,
 | 
			
		||||
                        criteria: criteria_selection,
 | 
			
		||||
                        identifier,
 | 
			
		||||
                        open_bracket,
 | 
			
		||||
                        close_bracket,
 | 
			
		||||
                        assignment: None,
 | 
			
		||||
                        annotations: VecDeque::new(),
 | 
			
		||||
                    })),
 | 
			
		||||
                    KeywordKind::Bool => Ok(VariableDeclaration::Tag(TagVariableDeclaration {
 | 
			
		||||
                        bool_keyword: variable_type,
 | 
			
		||||
                        identifier,
 | 
			
		||||
                        open_bracket,
 | 
			
		||||
                        close_bracket,
 | 
			
		||||
                        target_assignment: None,
 | 
			
		||||
                        annotations: VecDeque::new(),
 | 
			
		||||
                    })),
 | 
			
		||||
                    _ => unreachable!(),
 | 
			
		||||
                        Ok(VariableDeclaration::Array(ArrayVariableDeclaration {
 | 
			
		||||
                            variable_type,
 | 
			
		||||
                            identifier,
 | 
			
		||||
                            open_bracket,
 | 
			
		||||
                            size,
 | 
			
		||||
                            close_bracket,
 | 
			
		||||
                            assignment,
 | 
			
		||||
                            annotations: VecDeque::new(),
 | 
			
		||||
                        }))
 | 
			
		||||
                    }
 | 
			
		||||
                    IndexingType::None => match variable_type.keyword {
 | 
			
		||||
                        KeywordKind::Int => {
 | 
			
		||||
                            Ok(VariableDeclaration::Score(ScoreVariableDeclaration {
 | 
			
		||||
                                int_keyword: variable_type,
 | 
			
		||||
                                criteria: criteria_selection,
 | 
			
		||||
                                identifier,
 | 
			
		||||
                                open_bracket,
 | 
			
		||||
                                close_bracket,
 | 
			
		||||
                                assignment: None,
 | 
			
		||||
                                annotations: VecDeque::new(),
 | 
			
		||||
                            }))
 | 
			
		||||
                        }
 | 
			
		||||
                        KeywordKind::Bool => Ok(VariableDeclaration::Tag(TagVariableDeclaration {
 | 
			
		||||
                            bool_keyword: variable_type,
 | 
			
		||||
                            identifier,
 | 
			
		||||
                            open_bracket,
 | 
			
		||||
                            close_bracket,
 | 
			
		||||
                            target_assignment: None,
 | 
			
		||||
                            annotations: VecDeque::new(),
 | 
			
		||||
                        })),
 | 
			
		||||
                        _ => unreachable!(),
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                if matches!(variable_type.keyword, KeywordKind::Val) {
 | 
			
		||||
            // SingleVariableDeclaration with Assignment
 | 
			
		||||
            Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '=' => {
 | 
			
		||||
                self.forward();
 | 
			
		||||
                let equals = punc;
 | 
			
		||||
                let expression = self.parse_expression(handler)?;
 | 
			
		||||
                let assignment = VariableDeclarationAssignment { equals, expression };
 | 
			
		||||
 | 
			
		||||
                if variable_type.keyword == KeywordKind::Val {
 | 
			
		||||
                    Ok(VariableDeclaration::ComptimeValue(
 | 
			
		||||
                        ComptimeValueDeclaration {
 | 
			
		||||
                            val_keyword: variable_type,
 | 
			
		||||
                            identifier,
 | 
			
		||||
                            assignment,
 | 
			
		||||
                            assignment: Some(assignment),
 | 
			
		||||
                            annotations: VecDeque::new(),
 | 
			
		||||
                        },
 | 
			
		||||
                    ))
 | 
			
		||||
| 
						 | 
				
			
			@ -1168,11 +1162,18 @@ impl Parser<'_> {
 | 
			
		|||
                    Ok(VariableDeclaration::Single(SingleVariableDeclaration {
 | 
			
		||||
                        variable_type,
 | 
			
		||||
                        identifier,
 | 
			
		||||
                        assignment,
 | 
			
		||||
                        assignment: Some(assignment),
 | 
			
		||||
                        annotations: VecDeque::new(),
 | 
			
		||||
                    }))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // SingleVariableDeclaration without Assignment
 | 
			
		||||
            _ => Ok(VariableDeclaration::Single(SingleVariableDeclaration {
 | 
			
		||||
                variable_type,
 | 
			
		||||
                identifier,
 | 
			
		||||
                assignment: None,
 | 
			
		||||
                annotations: VecDeque::new(),
 | 
			
		||||
            })),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,5 @@
 | 
			
		|||
//! Execute block statement syntax tree.
 | 
			
		||||
 | 
			
		||||
#![expect(clippy::struct_field_names)]
 | 
			
		||||
 | 
			
		||||
use derive_more::From;
 | 
			
		||||
use enum_as_inner::EnumAsInner;
 | 
			
		||||
use getset::Getters;
 | 
			
		||||
| 
						 | 
				
			
			@ -826,7 +824,7 @@ impl Parser<'_> {
 | 
			
		|||
                            expected: SyntaxKind::Punctuation('('),
 | 
			
		||||
                            found: unexpected.into_token(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                }?;
 | 
			
		||||
| 
						 | 
				
			
			@ -844,7 +842,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::ExecuteBlock,
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -880,7 +878,7 @@ impl Parser<'_> {
 | 
			
		|||
                    expected: SyntaxKind::ExecuteBlockTail,
 | 
			
		||||
                    found: unexpected.into_token(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,8 +104,6 @@ impl MissingFunctionDeclaration {
 | 
			
		|||
 | 
			
		||||
impl Display for MissingFunctionDeclaration {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        use std::fmt::Write as _;
 | 
			
		||||
 | 
			
		||||
        let message = format!(
 | 
			
		||||
            "no matching function declaration found for invocation of function `{}`",
 | 
			
		||||
            self.span.str()
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +118,7 @@ impl Display for MissingFunctionDeclaration {
 | 
			
		|||
                if i > 0 {
 | 
			
		||||
                    message.push_str(", ");
 | 
			
		||||
                }
 | 
			
		||||
                let _ = write!(message, "`{}`", alternative.identifier_span.str());
 | 
			
		||||
                message.push_str(&format!("`{}`", alternative.identifier_span.str()));
 | 
			
		||||
            }
 | 
			
		||||
            Some(message + "?")
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -400,11 +398,6 @@ pub enum IllegalIndexingReason {
 | 
			
		|||
        /// The length indexed object.
 | 
			
		||||
        length: usize,
 | 
			
		||||
    },
 | 
			
		||||
    /// The index provided is invalid
 | 
			
		||||
    InvalidIndex {
 | 
			
		||||
        /// The invalid index
 | 
			
		||||
        index: Span,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for IllegalIndexingReason {
 | 
			
		||||
| 
						 | 
				
			
			@ -428,9 +421,6 @@ impl Display for IllegalIndexingReason {
 | 
			
		|||
                    "The index {index} is out of bounds for the expression with length {length}."
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            Self::InvalidIndex { index } => {
 | 
			
		||||
                write!(f, "The index {index} is invalid.", index = index.str())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -405,7 +405,7 @@ impl Primary {
 | 
			
		|||
            Self::Lua(lua) => lua
 | 
			
		||||
                .eval_comptime(scope, &VoidHandler)
 | 
			
		||||
                .inspect_err(|err| {
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                })
 | 
			
		||||
                .map_err(|_| NotComptime {
 | 
			
		||||
                    expression: lua.span(),
 | 
			
		||||
| 
						 | 
				
			
			@ -1191,7 +1191,7 @@ impl Transpiler {
 | 
			
		|||
                                    .into(),
 | 
			
		||||
                            },
 | 
			
		||||
                        );
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let prepare_cmd = Command::Raw(format!("tag {entity} remove {tag_name}"));
 | 
			
		||||
| 
						 | 
				
			
			@ -1225,18 +1225,7 @@ impl Transpiler {
 | 
			
		|||
                .parent()
 | 
			
		||||
                .comptime_member_access(member_access, scope, handler)
 | 
			
		||||
                .map_or_else(
 | 
			
		||||
                    |_| {
 | 
			
		||||
                        // TODO: implement non-comptime access
 | 
			
		||||
 | 
			
		||||
                        let err = TranspileError::IllegalIndexing(IllegalIndexing {
 | 
			
		||||
                            expression: member_access.member().span(),
 | 
			
		||||
                            reason: IllegalIndexingReason::InvalidIndex {
 | 
			
		||||
                                index: member_access.member().span(),
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    },
 | 
			
		||||
                    |_| todo!("implement non-comptime member access"),
 | 
			
		||||
                    |value| self.store_comptime_value(&value, target, member_access, handler),
 | 
			
		||||
                ),
 | 
			
		||||
            Primary::Lua(lua) =>
 | 
			
		||||
| 
						 | 
				
			
			@ -1248,7 +1237,7 @@ impl Transpiler {
 | 
			
		|||
                    let err = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                        expression: lua.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,7 +1262,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: target.value_type().into(),
 | 
			
		||||
                        expression: primary.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,7 +1326,7 @@ impl Transpiler {
 | 
			
		|||
                            expression: prefix.span(),
 | 
			
		||||
                            expected_type: target.value_type().into(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -1433,7 +1422,7 @@ impl Transpiler {
 | 
			
		|||
                                expected_type: target.value_type().into(),
 | 
			
		||||
                                expression: primary.span(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    }?;
 | 
			
		||||
| 
						 | 
				
			
			@ -1443,7 +1432,7 @@ impl Transpiler {
 | 
			
		|||
                    let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        identifier: ident.span.clone(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1455,7 +1444,7 @@ impl Transpiler {
 | 
			
		|||
                        reason: IllegalIndexingReason::NotIdentifier,
 | 
			
		||||
                        expression: indexed.object().span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }?;
 | 
			
		||||
                let variable = scope.get_variable(ident.span.str());
 | 
			
		||||
| 
						 | 
				
			
			@ -1477,7 +1466,7 @@ impl Transpiler {
 | 
			
		|||
                                    },
 | 
			
		||||
                                    expression: indexed.index().span(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                Err(err)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1502,7 +1491,7 @@ impl Transpiler {
 | 
			
		|||
                                        },
 | 
			
		||||
                                        expression: indexed.index().span(),
 | 
			
		||||
                                    });
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    handler.receive(err.clone());
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1512,7 +1501,7 @@ impl Transpiler {
 | 
			
		|||
                                    },
 | 
			
		||||
                                    expression: indexed.index().span(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                Err(err)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1541,7 +1530,7 @@ impl Transpiler {
 | 
			
		|||
                                        },
 | 
			
		||||
                                        expression: indexed.index().span(),
 | 
			
		||||
                                    });
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    handler.receive(err.clone());
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1551,7 +1540,7 @@ impl Transpiler {
 | 
			
		|||
                                    },
 | 
			
		||||
                                    expression: indexed.index().span(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                Err(err)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1560,7 +1549,7 @@ impl Transpiler {
 | 
			
		|||
                                expected_type: target.value_type().into(),
 | 
			
		||||
                                expression: primary.span(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    }?;
 | 
			
		||||
| 
						 | 
				
			
			@ -1570,7 +1559,7 @@ impl Transpiler {
 | 
			
		|||
                    let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        identifier: ident.span.clone(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1647,7 +1636,7 @@ impl Transpiler {
 | 
			
		|||
                    expected_type: ExpectedType::Boolean,
 | 
			
		||||
                    expression: primary.span(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
            Primary::StringLiteral(s) => Ok((
 | 
			
		||||
| 
						 | 
				
			
			@ -1670,7 +1659,7 @@ impl Transpiler {
 | 
			
		|||
                            message: "Function calls as conditions do not support arguments."
 | 
			
		||||
                                .into(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                } else {
 | 
			
		||||
                    let (func_location, _) = self.get_or_transpile_function(
 | 
			
		||||
| 
						 | 
				
			
			@ -1713,7 +1702,7 @@ impl Transpiler {
 | 
			
		|||
                                expected_type: ExpectedType::Boolean,
 | 
			
		||||
                                expression: primary.span(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1721,7 +1710,7 @@ impl Transpiler {
 | 
			
		|||
                    let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        identifier: ident.span.clone(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1736,7 +1725,7 @@ impl Transpiler {
 | 
			
		|||
                        reason: IllegalIndexingReason::NotIdentifier,
 | 
			
		||||
                        expression: indexed.object().span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }?;
 | 
			
		||||
                #[expect(clippy::option_if_let_else)]
 | 
			
		||||
| 
						 | 
				
			
			@ -1770,7 +1759,7 @@ impl Transpiler {
 | 
			
		|||
                                        },
 | 
			
		||||
                                        expression: indexed.index().span(),
 | 
			
		||||
                                    });
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    handler.receive(err.clone());
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1780,7 +1769,7 @@ impl Transpiler {
 | 
			
		|||
                                    },
 | 
			
		||||
                                    expression: indexed.index().span(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                Err(err)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1789,7 +1778,7 @@ impl Transpiler {
 | 
			
		|||
                                expected_type: ExpectedType::Boolean,
 | 
			
		||||
                                expression: primary.span(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1797,7 +1786,7 @@ impl Transpiler {
 | 
			
		|||
                    let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        identifier: ident.span.clone(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1805,18 +1794,7 @@ impl Transpiler {
 | 
			
		|||
                .parent()
 | 
			
		||||
                .comptime_member_access(member_access, scope, handler)
 | 
			
		||||
                .map_or_else(
 | 
			
		||||
                    |_| {
 | 
			
		||||
                        // TODO: implement non-comptime access
 | 
			
		||||
 | 
			
		||||
                        let err = TranspileError::IllegalIndexing(IllegalIndexing {
 | 
			
		||||
                            expression: member_access.member().span(),
 | 
			
		||||
                            reason: IllegalIndexingReason::InvalidIndex {
 | 
			
		||||
                                index: member_access.member().span(),
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    },
 | 
			
		||||
                    |_| todo!("implement non-comptime member access"),
 | 
			
		||||
                    |value| match value {
 | 
			
		||||
                        ComptimeValue::Boolean(b) => {
 | 
			
		||||
                            Ok((Vec::new(), ExtendedCondition::Comptime(b)))
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,7 +1804,7 @@ impl Transpiler {
 | 
			
		|||
                                expected_type: ExpectedType::Boolean,
 | 
			
		||||
                                expression: primary.span(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                        ComptimeValue::String(s) => Ok((
 | 
			
		||||
| 
						 | 
				
			
			@ -1882,7 +1860,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: primary.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -1903,7 +1881,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: primary.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -1933,7 +1911,7 @@ impl Transpiler {
 | 
			
		|||
                    expected_type: ExpectedType::Boolean,
 | 
			
		||||
                    expression: binary.span(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2022,7 +2000,7 @@ impl Transpiler {
 | 
			
		|||
                    expected_type: ExpectedType::Boolean,
 | 
			
		||||
                    expression: binary.span(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                return Err(err);
 | 
			
		||||
            }
 | 
			
		||||
            DataLocation::Storage {
 | 
			
		||||
| 
						 | 
				
			
			@ -2049,7 +2027,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: binary.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    return Err(err);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -2195,7 +2173,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: source.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
                DataLocation::Storage {
 | 
			
		||||
| 
						 | 
				
			
			@ -2219,7 +2197,7 @@ impl Transpiler {
 | 
			
		|||
                            expression: source.span(),
 | 
			
		||||
                            expected_type: target.value_type().into(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -2245,7 +2223,7 @@ impl Transpiler {
 | 
			
		|||
                            expression: source.span(),
 | 
			
		||||
                            expected_type: target.value_type().into(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -2280,7 +2258,7 @@ impl Transpiler {
 | 
			
		|||
                            expected_type: target.value_type().into(),
 | 
			
		||||
                            expression: source.span(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -2316,7 +2294,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: source.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    return Err(err);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ use super::{
 | 
			
		|||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum TranspiledFunctionArguments {
 | 
			
		||||
    None,
 | 
			
		||||
    Static(BTreeMap<String, MacroString>, Vec<Command>),
 | 
			
		||||
    Static(BTreeMap<String, MacroString>),
 | 
			
		||||
    Dynamic(Vec<Command>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +59,11 @@ impl Transpiler {
 | 
			
		|||
            .expect("called variable should be of type function");
 | 
			
		||||
 | 
			
		||||
        let function_data = function.ok_or_else(|| {
 | 
			
		||||
            let err = TranspileError::MissingFunctionDeclaration(
 | 
			
		||||
            let error = TranspileError::MissingFunctionDeclaration(
 | 
			
		||||
                MissingFunctionDeclaration::from_scope(identifier_span.clone(), scope),
 | 
			
		||||
            );
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            err
 | 
			
		||||
            handler.receive(error.clone());
 | 
			
		||||
            error
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        let VariableData::Function {
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ impl Transpiler {
 | 
			
		|||
                                        .to_string(),
 | 
			
		||||
                                },
 | 
			
		||||
                            );
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            err
 | 
			
		||||
                        }),
 | 
			
		||||
                    TranspileAnnotationValue::Map(_, span) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ impl Transpiler {
 | 
			
		|||
                                annotation: span.clone(),
 | 
			
		||||
                                message: "Deobfuscate annotation cannot be a map.".to_string(),
 | 
			
		||||
                            });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +175,7 @@ impl Transpiler {
 | 
			
		|||
                    name: modified_name,
 | 
			
		||||
                    definition: identifier_span.clone(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                return Err(err);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,11 +193,11 @@ impl Transpiler {
 | 
			
		|||
        let function_location = function_path
 | 
			
		||||
            .get()
 | 
			
		||||
            .ok_or_else(|| {
 | 
			
		||||
                let err = TranspileError::MissingFunctionDeclaration(
 | 
			
		||||
                let error = TranspileError::MissingFunctionDeclaration(
 | 
			
		||||
                    MissingFunctionDeclaration::from_scope(identifier_span.clone(), scope),
 | 
			
		||||
                );
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                err
 | 
			
		||||
                handler.receive(error.clone());
 | 
			
		||||
                error
 | 
			
		||||
            })
 | 
			
		||||
            .map(String::to_owned)?;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +258,7 @@ impl Transpiler {
 | 
			
		|||
                    actual: arg_count,
 | 
			
		||||
                    span: identifier_span.clone(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
            Some(arg_count) if arg_count > 0 => {
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +283,7 @@ impl Transpiler {
 | 
			
		|||
                                Ok(val) => Ok(Parameter::Static(val.to_macro_string())),
 | 
			
		||||
                                Err(err) => {
 | 
			
		||||
                                    let err = TranspileError::NotComptime(err);
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    handler.receive(err.clone());
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +305,7 @@ impl Transpiler {
 | 
			
		|||
                                let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                                    identifier: ident.span(),
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                err
 | 
			
		||||
                            })?;
 | 
			
		||||
                            match var.as_ref() {
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +353,7 @@ impl Transpiler {
 | 
			
		|||
                                            ExpectedType::String,
 | 
			
		||||
                                        ]),
 | 
			
		||||
                                    });
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    handler.receive(err.clone());
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -430,9 +430,9 @@ impl Transpiler {
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                if compiled_args.iter().any(|arg| !arg.is_static()) {
 | 
			
		||||
                    let (require_dyn_params, mut setup_cmds, move_cmds, static_params) = parameters.clone().into_iter().zip(compiled_args).fold(
 | 
			
		||||
                        (false, Vec::new(), Vec::new(), BTreeMap::new()),
 | 
			
		||||
                        |(mut require_dyn_params, mut acc_setup, mut acc_move, mut statics), (param, data)| {
 | 
			
		||||
                    let (mut setup_cmds, move_cmds, static_params) = parameters.clone().into_iter().zip(compiled_args).fold(
 | 
			
		||||
                        (Vec::new(), Vec::new(), BTreeMap::new()),
 | 
			
		||||
                        |(mut acc_setup, mut acc_move, mut statics), (param, data)| {
 | 
			
		||||
                            match param.variable_type() {
 | 
			
		||||
                                FunctionVariableType::Macro(_) => {
 | 
			
		||||
                                    let arg_name = crate::util::identifier_to_macro(param.identifier().span.str());
 | 
			
		||||
| 
						 | 
				
			
			@ -455,7 +455,6 @@ impl Transpiler {
 | 
			
		|||
                                            };
 | 
			
		||||
                                        }
 | 
			
		||||
                                        Parameter::Storage { prepare_cmds, storage_name, path } => {
 | 
			
		||||
                                            require_dyn_params = true;
 | 
			
		||||
                                            acc_setup.extend(prepare_cmds);
 | 
			
		||||
                                            acc_move.push(Command::Raw(
 | 
			
		||||
                                                format!(r"data modify storage shulkerscript:function_arguments {arg_name} set from storage {storage_name} {path}")
 | 
			
		||||
| 
						 | 
				
			
			@ -496,7 +495,6 @@ impl Transpiler {
 | 
			
		|||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                FunctionVariableType::Boolean(_) => {
 | 
			
		||||
                                    require_dyn_params = true;
 | 
			
		||||
                                    let target_storage_name = format!("shulkerscript:arguments_{}", function_location.replace(['/', ':'], "_"));
 | 
			
		||||
                                    let param_str = param.identifier().span.str();
 | 
			
		||||
                                    let target_path = crate::util::identifier_to_scoreboard_target(param_str);
 | 
			
		||||
| 
						 | 
				
			
			@ -526,67 +524,50 @@ impl Transpiler {
 | 
			
		|||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                            }
 | 
			
		||||
                        (require_dyn_params, acc_setup, acc_move, statics)},
 | 
			
		||||
                        (acc_setup, acc_move, statics)},
 | 
			
		||||
                    );
 | 
			
		||||
                    if require_dyn_params {
 | 
			
		||||
                        let statics_len = static_params.len();
 | 
			
		||||
                        let joined_statics = super::util::join_macro_strings(
 | 
			
		||||
                            static_params
 | 
			
		||||
                                .into_iter()
 | 
			
		||||
                                .enumerate()
 | 
			
		||||
                                .map(|(i, (k, v))| match v {
 | 
			
		||||
                                    MacroString::String(s) => {
 | 
			
		||||
                                        let mut s = format!(r#"{k}:"{s}""#);
 | 
			
		||||
                                        if i < statics_len - 1 {
 | 
			
		||||
                                            s.push(',');
 | 
			
		||||
                                        }
 | 
			
		||||
                                        MacroString::String(s)
 | 
			
		||||
                    let statics_len = static_params.len();
 | 
			
		||||
                    let joined_statics =
 | 
			
		||||
                        super::util::join_macro_strings(static_params.into_iter().enumerate().map(
 | 
			
		||||
                            |(i, (k, v))| match v {
 | 
			
		||||
                                MacroString::String(s) => {
 | 
			
		||||
                                    let mut s = format!(r#"{k}:"{s}""#);
 | 
			
		||||
                                    if i < statics_len - 1 {
 | 
			
		||||
                                        s.push(',');
 | 
			
		||||
                                    }
 | 
			
		||||
                                    MacroString::MacroString(mut parts) => {
 | 
			
		||||
                                        parts.insert(
 | 
			
		||||
                                            0,
 | 
			
		||||
                                            MacroStringPart::String(format!(r#"{k}:""#)),
 | 
			
		||||
                                        );
 | 
			
		||||
                                        let mut ending = '"'.to_string();
 | 
			
		||||
                                        if i < statics_len - 1 {
 | 
			
		||||
                                            ending.push(',');
 | 
			
		||||
                                        }
 | 
			
		||||
                                        parts.push(MacroStringPart::String(ending));
 | 
			
		||||
                                        MacroString::MacroString(parts)
 | 
			
		||||
                                    MacroString::String(s)
 | 
			
		||||
                                }
 | 
			
		||||
                                MacroString::MacroString(mut parts) => {
 | 
			
		||||
                                    parts.insert(0, MacroStringPart::String(format!(r#"{k}:""#)));
 | 
			
		||||
                                    let mut ending = '"'.to_string();
 | 
			
		||||
                                    if i < statics_len - 1 {
 | 
			
		||||
                                        ending.push(',');
 | 
			
		||||
                                    }
 | 
			
		||||
                                }),
 | 
			
		||||
                        );
 | 
			
		||||
                        let storage_suffix = function_location.replace(['/', ':'], "_");
 | 
			
		||||
                        let statics_cmd = match joined_statics {
 | 
			
		||||
                            MacroString::String(s) => Command::Raw(format!(
 | 
			
		||||
                                r"data merge storage shulkerscript:function_arguments_{storage_suffix} {{{s}}}"
 | 
			
		||||
                            )),
 | 
			
		||||
                            MacroString::MacroString(_) => {
 | 
			
		||||
                                let prefix = MacroString::String(
 | 
			
		||||
                                    format!("data merge storage shulkerscript:function_arguments_{storage_suffix} {{"),
 | 
			
		||||
                                );
 | 
			
		||||
                                Command::UsesMacro(
 | 
			
		||||
                                    super::util::join_macro_strings([
 | 
			
		||||
                                        prefix,
 | 
			
		||||
                                        joined_statics,
 | 
			
		||||
                                        MacroString::String("}".to_string()),
 | 
			
		||||
                                    ])
 | 
			
		||||
                                    .into(),
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        };
 | 
			
		||||
                        setup_cmds.push(statics_cmd);
 | 
			
		||||
                        setup_cmds.extend(move_cmds);
 | 
			
		||||
                                    parts.push(MacroStringPart::String(ending));
 | 
			
		||||
                                    MacroString::MacroString(parts)
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                        ));
 | 
			
		||||
                    let statics_cmd = match joined_statics {
 | 
			
		||||
                        MacroString::String(s) => Command::Raw(format!(
 | 
			
		||||
                            r"data merge storage shulkerscript:function_arguments {{{s}}}"
 | 
			
		||||
                        )),
 | 
			
		||||
                        MacroString::MacroString(_) => Command::UsesMacro(
 | 
			
		||||
                            super::util::join_macro_strings([
 | 
			
		||||
                                MacroString::String(
 | 
			
		||||
                                    "data merge storage shulkerscript:function_arguments {"
 | 
			
		||||
                                        .to_string(),
 | 
			
		||||
                                ),
 | 
			
		||||
                                joined_statics,
 | 
			
		||||
                                MacroString::String("}".to_string()),
 | 
			
		||||
                            ])
 | 
			
		||||
                            .into(),
 | 
			
		||||
                        ),
 | 
			
		||||
                    };
 | 
			
		||||
                    setup_cmds.push(statics_cmd);
 | 
			
		||||
                    setup_cmds.extend(move_cmds);
 | 
			
		||||
 | 
			
		||||
                        Ok(TranspiledFunctionArguments::Dynamic(setup_cmds))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        setup_cmds.extend(move_cmds);
 | 
			
		||||
 | 
			
		||||
                        Ok(TranspiledFunctionArguments::Static(
 | 
			
		||||
                            static_params,
 | 
			
		||||
                            setup_cmds,
 | 
			
		||||
                        ))
 | 
			
		||||
                    }
 | 
			
		||||
                    Ok(TranspiledFunctionArguments::Dynamic(setup_cmds))
 | 
			
		||||
                } else {
 | 
			
		||||
                    let function_args = parameters
 | 
			
		||||
                        .clone()
 | 
			
		||||
| 
						 | 
				
			
			@ -598,10 +579,7 @@ impl Transpiler {
 | 
			
		|||
                        )
 | 
			
		||||
                        .map(|(k, v)| (k.identifier().span.str().to_string(), v))
 | 
			
		||||
                        .collect();
 | 
			
		||||
                    Ok(TranspiledFunctionArguments::Static(
 | 
			
		||||
                        function_args,
 | 
			
		||||
                        Vec::new(),
 | 
			
		||||
                    ))
 | 
			
		||||
                    Ok(TranspiledFunctionArguments::Static(function_args))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => Ok(TranspiledFunctionArguments::None),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,7 +132,7 @@ fn print_function(
 | 
			
		|||
                    Ok((false, cmd, value))
 | 
			
		||||
                }
 | 
			
		||||
                _ => Err(TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                    Box::new(Expression::Primary(Primary::Identifier(ident.to_owned()))),
 | 
			
		||||
                    Expression::Primary(Primary::Identifier(ident.to_owned())),
 | 
			
		||||
                ))),
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ mod enabled {
 | 
			
		|||
            };
 | 
			
		||||
 | 
			
		||||
            self.add_globals(&lua, scope)
 | 
			
		||||
                .inspect_err(|err| handler.receive(Box::new(err.clone())))?;
 | 
			
		||||
                .inspect_err(|err| handler.receive(err.clone()))?;
 | 
			
		||||
 | 
			
		||||
            let res = lua
 | 
			
		||||
                .load(self.code())
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ mod enabled {
 | 
			
		|||
                .map_err(|err| {
 | 
			
		||||
                    let err =
 | 
			
		||||
                        TranspileError::from(LuaRuntimeError::from_lua_err(&err, self.span()));
 | 
			
		||||
                    handler.receive(crate::Error::from(Box::new(err.clone())));
 | 
			
		||||
                    handler.receive(crate::Error::from(err.clone()));
 | 
			
		||||
                    err
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +329,7 @@ mod enabled {
 | 
			
		|||
                            code_block: self.span(),
 | 
			
		||||
                            error_message: "return table must contain non-nil 'value'".to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                    Ok(value) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +348,7 @@ mod enabled {
 | 
			
		|||
                                                    expression: self.span(),
 | 
			
		||||
                                                    expected_type: ExpectedType::Boolean,
 | 
			
		||||
                                                });
 | 
			
		||||
                                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                            handler.receive(err.clone());
 | 
			
		||||
                                            Err(err)
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -358,7 +358,7 @@ mod enabled {
 | 
			
		|||
                                                expression: self.span(),
 | 
			
		||||
                                                expected_type: ExpectedType::Boolean,
 | 
			
		||||
                                            });
 | 
			
		||||
                                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                        handler.receive(err.clone());
 | 
			
		||||
                                        Err(err)
 | 
			
		||||
                                    }
 | 
			
		||||
                                }?;
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +380,7 @@ mod enabled {
 | 
			
		|||
                            &err,
 | 
			
		||||
                            self.span(),
 | 
			
		||||
                        ));
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ mod enabled {
 | 
			
		|||
                        code_block: self.span(),
 | 
			
		||||
                        error_message: format!("invalid return type {}", value.type_name()),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -196,12 +196,13 @@ impl Transpiler {
 | 
			
		|||
                }
 | 
			
		||||
                TranspileAnnotationValue::Expression(_, span)
 | 
			
		||||
                | TranspileAnnotationValue::Map(_, span) => {
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: span.clone(),
 | 
			
		||||
                        message: "uninstall annotation must not have a value".to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: span.clone(),
 | 
			
		||||
                            message: "uninstall annotation must not have a value".to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .collect::<TranspileResult<Vec<_>>>()?;
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +273,7 @@ impl Transpiler {
 | 
			
		|||
                    })
 | 
			
		||||
                    .collect();
 | 
			
		||||
                let function_data = FunctionData {
 | 
			
		||||
                    namespace: namespace.name().str_content().to_string(),
 | 
			
		||||
                    namespace: namespace.namespace_name().str_content().to_string(),
 | 
			
		||||
                    identifier_span: identifier_span.clone(),
 | 
			
		||||
                    parameters: function
 | 
			
		||||
                        .parameters()
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +318,9 @@ impl Transpiler {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Declaration::Tag(tag) => {
 | 
			
		||||
                let namespace = self.datapack.namespace_mut(namespace.name().str_content());
 | 
			
		||||
                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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +344,7 @@ impl Transpiler {
 | 
			
		|||
 | 
			
		||||
                self.setup_cmds.extend(setup_variable_cmds);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -412,11 +415,11 @@ impl Transpiler {
 | 
			
		|||
                        self.transpile_run_expression(prefix.operand(), scope, handler)
 | 
			
		||||
                    }
 | 
			
		||||
                    unexpected => {
 | 
			
		||||
                        let err = TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                            Box::new(unexpected.clone()),
 | 
			
		||||
                        let error = TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                            unexpected.clone(),
 | 
			
		||||
                        ));
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                        handler.receive(error.clone());
 | 
			
		||||
                        Err(error)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                SemicolonStatement::VariableDeclaration(decl) => self
 | 
			
		||||
| 
						 | 
				
			
			@ -492,11 +495,11 @@ impl Transpiler {
 | 
			
		|||
                                read_only: _,
 | 
			
		||||
                            } => value.read().unwrap().as_ref().map_or_else(
 | 
			
		||||
                                || {
 | 
			
		||||
                                    let err = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                                    let error = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                                        expression: ident.span.clone(),
 | 
			
		||||
                                    });
 | 
			
		||||
                                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                    Err(err)
 | 
			
		||||
                                    handler.receive(error.clone());
 | 
			
		||||
                                    Err(error)
 | 
			
		||||
                                },
 | 
			
		||||
                                |val| {
 | 
			
		||||
                                    let cmd = val.to_string_no_macro().map_or_else(
 | 
			
		||||
| 
						 | 
				
			
			@ -529,21 +532,20 @@ impl Transpiler {
 | 
			
		|||
                                )))),
 | 
			
		||||
                            ),
 | 
			
		||||
                            _ => {
 | 
			
		||||
                                let err = TranspileError::UnexpectedExpression(
 | 
			
		||||
                                    UnexpectedExpression(Box::new(Expression::Primary(
 | 
			
		||||
                                        Primary::Identifier(ident.clone()),
 | 
			
		||||
                                    ))),
 | 
			
		||||
                                );
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                                let error =
 | 
			
		||||
                                    TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                                        Expression::Primary(Primary::Identifier(ident.clone())),
 | 
			
		||||
                                    ));
 | 
			
		||||
                                handler.receive(error.clone());
 | 
			
		||||
                                return Err(error);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        let error = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                            identifier: ident.span.clone(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                        handler.receive(error.clone());
 | 
			
		||||
                        return Err(error);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                _ => {
 | 
			
		||||
| 
						 | 
				
			
			@ -588,11 +590,11 @@ impl Transpiler {
 | 
			
		|||
                    read_only: _,
 | 
			
		||||
                }) => value.read().unwrap().as_ref().map_or_else(
 | 
			
		||||
                    || {
 | 
			
		||||
                        let err = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                        let error = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                            expression: ident.span.clone(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                        handler.receive(error.clone());
 | 
			
		||||
                        Err(error)
 | 
			
		||||
                    },
 | 
			
		||||
                    |val| {
 | 
			
		||||
                        let cmd = val.to_string_no_macro().map_or_else(
 | 
			
		||||
| 
						 | 
				
			
			@ -603,18 +605,18 @@ impl Transpiler {
 | 
			
		|||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
                Some(_) => {
 | 
			
		||||
                    let err = TranspileError::UnexpectedExpression(UnexpectedExpression(Box::new(
 | 
			
		||||
                    let error = TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                        Expression::Primary(expression.clone()),
 | 
			
		||||
                    )));
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    ));
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
                None => {
 | 
			
		||||
                    let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                    let error = TranspileError::UnknownIdentifier(UnknownIdentifier {
 | 
			
		||||
                        identifier: ident.span.clone(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -623,11 +625,11 @@ impl Transpiler {
 | 
			
		|||
            | Primary::Prefix(_)
 | 
			
		||||
            | Primary::Indexed(_)
 | 
			
		||||
            | Primary::MemberAccess(_) => {
 | 
			
		||||
                let err = TranspileError::UnexpectedExpression(UnexpectedExpression(Box::new(
 | 
			
		||||
                let error = TranspileError::UnexpectedExpression(UnexpectedExpression(
 | 
			
		||||
                    Expression::Primary(expression.clone()),
 | 
			
		||||
                )));
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                Err(err)
 | 
			
		||||
                ));
 | 
			
		||||
                handler.receive(error.clone());
 | 
			
		||||
                Err(error)
 | 
			
		||||
            }
 | 
			
		||||
            Primary::StringLiteral(string) => {
 | 
			
		||||
                Ok(vec![Command::Raw(string.str_content().to_string())])
 | 
			
		||||
| 
						 | 
				
			
			@ -641,14 +643,14 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::String,
 | 
			
		||||
                        expression: code.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
                Err(_) => {
 | 
			
		||||
                    let err = TranspileError::MissingValue(MissingValue {
 | 
			
		||||
                        expression: code.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -665,12 +667,12 @@ impl Transpiler {
 | 
			
		|||
                            expression: bin.span(),
 | 
			
		||||
                            expected_type: ExpectedType::String,
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                    Err(not_comptime) => {
 | 
			
		||||
                        let err = TranspileError::NotComptime(not_comptime);
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -692,7 +694,7 @@ impl Transpiler {
 | 
			
		|||
            scope.get_variable(func.identifier().span.str()).as_deref()
 | 
			
		||||
        {
 | 
			
		||||
            implementation(self, scope, func).inspect_err(|err| {
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
            })
 | 
			
		||||
        } else {
 | 
			
		||||
            let (location, arguments) = self.get_or_transpile_function(
 | 
			
		||||
| 
						 | 
				
			
			@ -703,61 +705,48 @@ impl Transpiler {
 | 
			
		|||
            )?;
 | 
			
		||||
            let mut function_call = format!("function {location}");
 | 
			
		||||
            match arguments {
 | 
			
		||||
                TranspiledFunctionArguments::Static(arguments, mut setup_cmds) => {
 | 
			
		||||
                TranspiledFunctionArguments::Static(arguments) => {
 | 
			
		||||
                    use std::fmt::Write;
 | 
			
		||||
                    let arguments_iter = arguments.iter().map(|(ident, v)| match v {
 | 
			
		||||
                        MacroString::String(s) => MacroString::String(format!(
 | 
			
		||||
                            r#"{macro_name}:"{escaped}""#,
 | 
			
		||||
                            macro_name = crate::util::identifier_to_macro(ident),
 | 
			
		||||
                            escaped = crate::util::escape_str(s)
 | 
			
		||||
                        )),
 | 
			
		||||
                        MacroString::MacroString(parts) => MacroString::MacroString(
 | 
			
		||||
                            std::iter::once(MacroStringPart::String(format!(
 | 
			
		||||
                                r#"{macro_name}:""#,
 | 
			
		||||
                                macro_name = crate::util::identifier_to_macro(ident)
 | 
			
		||||
                            )))
 | 
			
		||||
                            .chain(parts.clone().into_iter().map(|part| match part {
 | 
			
		||||
                                MacroStringPart::String(s) => {
 | 
			
		||||
                                    MacroStringPart::String(crate::util::escape_str(&s).to_string())
 | 
			
		||||
                                }
 | 
			
		||||
                                macro_usage @ MacroStringPart::MacroUsage(_) => macro_usage,
 | 
			
		||||
                            }))
 | 
			
		||||
                            .chain(std::iter::once(MacroStringPart::String('"'.to_string())))
 | 
			
		||||
                            .collect(),
 | 
			
		||||
                        ),
 | 
			
		||||
                    });
 | 
			
		||||
                    let arguments = super::util::join_macro_strings(arguments_iter);
 | 
			
		||||
 | 
			
		||||
                    let cmd = if arguments.is_empty() {
 | 
			
		||||
                        Command::Raw(function_call)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let arguments_iter = arguments.iter().map(|(ident, v)| match v {
 | 
			
		||||
                            MacroString::String(s) => MacroString::String(format!(
 | 
			
		||||
                                r#"{macro_name}:"{escaped}""#,
 | 
			
		||||
                                macro_name = crate::util::identifier_to_macro(ident),
 | 
			
		||||
                                escaped = crate::util::escape_str(s)
 | 
			
		||||
                            )),
 | 
			
		||||
                            MacroString::MacroString(parts) => MacroString::MacroString(
 | 
			
		||||
                                std::iter::once(MacroStringPart::String(format!(
 | 
			
		||||
                                    r#"{macro_name}:""#,
 | 
			
		||||
                                    macro_name = crate::util::identifier_to_macro(ident)
 | 
			
		||||
                                )))
 | 
			
		||||
                                .chain(parts.clone().into_iter().map(|part| match part {
 | 
			
		||||
                                    MacroStringPart::String(s) => MacroStringPart::String(
 | 
			
		||||
                                        crate::util::escape_str(&s).to_string(),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    macro_usage @ MacroStringPart::MacroUsage(_) => macro_usage,
 | 
			
		||||
                                }))
 | 
			
		||||
                                .chain(std::iter::once(MacroStringPart::String('"'.to_string())))
 | 
			
		||||
                                .collect(),
 | 
			
		||||
                            ),
 | 
			
		||||
                        });
 | 
			
		||||
                        let arguments = super::util::join_macro_strings(arguments_iter);
 | 
			
		||||
 | 
			
		||||
                        match arguments {
 | 
			
		||||
                            MacroString::String(arguments) => {
 | 
			
		||||
                                write!(function_call, " {{{arguments}}}").unwrap();
 | 
			
		||||
                                Command::Raw(function_call)
 | 
			
		||||
                            }
 | 
			
		||||
                            MacroString::MacroString(mut parts) => {
 | 
			
		||||
                                function_call.push_str(" {");
 | 
			
		||||
                                parts.insert(0, MacroStringPart::String(function_call));
 | 
			
		||||
                                parts.push(MacroStringPart::String('}'.to_string()));
 | 
			
		||||
                                Command::UsesMacro(MacroString::MacroString(parts).into())
 | 
			
		||||
                            }
 | 
			
		||||
                    let cmd = match arguments {
 | 
			
		||||
                        MacroString::String(arguments) => {
 | 
			
		||||
                            write!(function_call, " {{{arguments}}}").unwrap();
 | 
			
		||||
                            Command::Raw(function_call)
 | 
			
		||||
                        }
 | 
			
		||||
                        MacroString::MacroString(mut parts) => {
 | 
			
		||||
                            function_call.push_str(" {");
 | 
			
		||||
                            parts.insert(0, MacroStringPart::String(function_call));
 | 
			
		||||
                            parts.push(MacroStringPart::String('}'.to_string()));
 | 
			
		||||
                            Command::UsesMacro(MacroString::MacroString(parts).into())
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    setup_cmds.push(cmd);
 | 
			
		||||
 | 
			
		||||
                    Ok(setup_cmds)
 | 
			
		||||
                    Ok(vec![cmd])
 | 
			
		||||
                }
 | 
			
		||||
                TranspiledFunctionArguments::Dynamic(mut cmds) => {
 | 
			
		||||
                    use std::fmt::Write as _;
 | 
			
		||||
 | 
			
		||||
                    let _ = write!(
 | 
			
		||||
                        function_call,
 | 
			
		||||
                        " with storage shulkerscript:function_arguments_{suffix}",
 | 
			
		||||
                        suffix = location.replace(['/', ':'], "_")
 | 
			
		||||
                    );
 | 
			
		||||
                    function_call.push_str(" with storage shulkerscript:function_arguments");
 | 
			
		||||
                    cmds.push(Command::Raw(function_call));
 | 
			
		||||
                    Ok(cmds)
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,7 @@ impl MacroString {
 | 
			
		|||
    ///
 | 
			
		||||
    /// # Errors
 | 
			
		||||
    /// - If the macro string contains macros
 | 
			
		||||
    pub fn as_str(&self) -> Result<std::borrow::Cow<'_, str>, &[MacroStringPart]> {
 | 
			
		||||
    pub fn as_str(&self) -> Result<std::borrow::Cow<str>, &[MacroStringPart]> {
 | 
			
		||||
        match self {
 | 
			
		||||
            Self::String(s) => Ok(std::borrow::Cow::Borrowed(s)),
 | 
			
		||||
            Self::MacroString(parts) if self.contains_macros() => Err(parts),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,7 +308,7 @@ impl Transpiler {
 | 
			
		|||
                            .comptime_eval(scope, handler)
 | 
			
		||||
                            .map_err(|err| {
 | 
			
		||||
                                let err = TranspileError::NotComptime(err);
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                err
 | 
			
		||||
                            })?,
 | 
			
		||||
                    )
 | 
			
		||||
| 
						 | 
				
			
			@ -569,7 +569,7 @@ impl Transpiler {
 | 
			
		|||
                            },
 | 
			
		||||
                            expression: expression.span(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                    Some(_) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -579,7 +579,7 @@ impl Transpiler {
 | 
			
		|||
                                expected: ExpectedType::String,
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                    None => {
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +588,7 @@ impl Transpiler {
 | 
			
		|||
                            identifier: identifier.span(),
 | 
			
		||||
                            message: "Cannot assign to a scoreboard without indexing".to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -617,7 +617,7 @@ impl Transpiler {
 | 
			
		|||
                                        length: targets.len(),
 | 
			
		||||
                                    },
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -628,7 +628,7 @@ impl Transpiler {
 | 
			
		|||
                                    expected: ExpectedType::Integer,
 | 
			
		||||
                                },
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            return Err(err);
 | 
			
		||||
                        }
 | 
			
		||||
                        None => {
 | 
			
		||||
| 
						 | 
				
			
			@ -637,7 +637,7 @@ impl Transpiler {
 | 
			
		|||
                                identifier: identifier.span(),
 | 
			
		||||
                                message: "Cannot assign to an array without indexing".to_string(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            return Err(err);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -671,7 +671,7 @@ impl Transpiler {
 | 
			
		|||
                                        length: paths.len(),
 | 
			
		||||
                                    },
 | 
			
		||||
                                });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                handler.receive(err.clone());
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +682,7 @@ impl Transpiler {
 | 
			
		|||
                                    expected: ExpectedType::Integer,
 | 
			
		||||
                                },
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            return Err(err);
 | 
			
		||||
                        }
 | 
			
		||||
                        None => {
 | 
			
		||||
| 
						 | 
				
			
			@ -691,7 +691,7 @@ impl Transpiler {
 | 
			
		|||
                                identifier: identifier.span(),
 | 
			
		||||
                                message: "Cannot assign to an array without indexing".to_string(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            return Err(err);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -709,7 +709,7 @@ impl Transpiler {
 | 
			
		|||
                                expected: ExpectedType::String,
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                    Some(_) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -719,7 +719,7 @@ impl Transpiler {
 | 
			
		|||
                                expected: ExpectedType::String,
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                    None => {
 | 
			
		||||
| 
						 | 
				
			
			@ -728,7 +728,7 @@ impl Transpiler {
 | 
			
		|||
                            identifier: identifier.span(),
 | 
			
		||||
                            message: "Cannot assign to a tag without indexing".to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -738,13 +738,13 @@ impl Transpiler {
 | 
			
		|||
                            identifier: identifier.span(),
 | 
			
		||||
                            message: "Cannot assign to a read-only value.".to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        return Err(err);
 | 
			
		||||
                    }
 | 
			
		||||
                    let comptime_value =
 | 
			
		||||
                        expression.comptime_eval(scope, handler).map_err(|err| {
 | 
			
		||||
                            let err = TranspileError::NotComptime(err);
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            err
 | 
			
		||||
                        })?;
 | 
			
		||||
                    *value.write().unwrap() = Some(comptime_value);
 | 
			
		||||
| 
						 | 
				
			
			@ -765,7 +765,7 @@ impl Transpiler {
 | 
			
		|||
                            }
 | 
			
		||||
                        ),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            }?;
 | 
			
		||||
| 
						 | 
				
			
			@ -775,7 +775,7 @@ impl Transpiler {
 | 
			
		|||
                identifier: identifier.span(),
 | 
			
		||||
                message: "Variable does not exist.".to_string(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            handler.receive(err.clone());
 | 
			
		||||
            Err(err)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -796,12 +796,12 @@ impl Transpiler {
 | 
			
		|||
        let deobfuscate_annotation = deobfuscate_annotations.next();
 | 
			
		||||
 | 
			
		||||
        if let Some(duplicate) = deobfuscate_annotations.next() {
 | 
			
		||||
            let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
            let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                annotation: duplicate.span(),
 | 
			
		||||
                message: "Multiple deobfuscate annotations are not allowed.".to_string(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            return Err(err);
 | 
			
		||||
            handler.receive(error.clone());
 | 
			
		||||
            return Err(error);
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(deobfuscate_annotation) = deobfuscate_annotation {
 | 
			
		||||
            let deobfuscate_annotation_value = TranspileAnnotationValue::from_annotation_value(
 | 
			
		||||
| 
						 | 
				
			
			@ -818,32 +818,33 @@ impl Transpiler {
 | 
			
		|||
                    {
 | 
			
		||||
                        // TODO: change invalid criteria if boolean
 | 
			
		||||
                        if !crate::util::is_valid_scoreboard_objective_name(&name_eval) {
 | 
			
		||||
                            let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                                    annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                                    message: "Deobfuscate annotation must be a valid scoreboard objective name.".to_string()
 | 
			
		||||
                                                });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            return Err(err);
 | 
			
		||||
                            handler.receive(error.clone());
 | 
			
		||||
                            return Err(error);
 | 
			
		||||
                        }
 | 
			
		||||
                        Ok(name_eval)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                                annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                                message: "Deobfuscate annotation could not have been evaluated at compile time.".to_string()
 | 
			
		||||
                                            });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                        handler.receive(error.clone());
 | 
			
		||||
                        Err(error)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                TranspileAnnotationValue::None(_) => Ok(identifier.span.str().to_string()),
 | 
			
		||||
                TranspileAnnotationValue::Map(_, _) => {
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                        message: "Deobfuscate annotation must have no value or must be string."
 | 
			
		||||
                            .to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                            message: "Deobfuscate annotation must have no value or must be string."
 | 
			
		||||
                                .to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -880,12 +881,12 @@ impl Transpiler {
 | 
			
		|||
        let deobfuscate_annotation = deobfuscate_annotations.next();
 | 
			
		||||
 | 
			
		||||
        if let Some(duplicate) = deobfuscate_annotations.next() {
 | 
			
		||||
            let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
            let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                annotation: duplicate.span(),
 | 
			
		||||
                message: "Multiple deobfuscate annotations are not allowed.".to_string(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            return Err(err);
 | 
			
		||||
            handler.receive(error.clone());
 | 
			
		||||
            return Err(error);
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(deobfuscate_annotation) = deobfuscate_annotation {
 | 
			
		||||
            let deobfuscate_annotation_value = TranspileAnnotationValue::from_annotation_value(
 | 
			
		||||
| 
						 | 
				
			
			@ -895,13 +896,14 @@ impl Transpiler {
 | 
			
		|||
 | 
			
		||||
            if let TranspileAnnotationValue::Map(map, _) = deobfuscate_annotation_value {
 | 
			
		||||
                if map.len() > 2 {
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                        message: "Deobfuscate annotation must have at most 2 key-value pairs."
 | 
			
		||||
                            .to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    return Err(err);
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                            message: "Deobfuscate annotation must have at most 2 key-value pairs."
 | 
			
		||||
                                .to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    return Err(error);
 | 
			
		||||
                }
 | 
			
		||||
                if let (Some(name), Some(target)) = (map.get("name"), map.get("target")) {
 | 
			
		||||
                    if let (
 | 
			
		||||
| 
						 | 
				
			
			@ -921,54 +923,56 @@ impl Transpiler {
 | 
			
		|||
                        ) {
 | 
			
		||||
                            // TODO: change invalid criteria if boolean
 | 
			
		||||
                            if !crate::util::is_valid_scoreboard_objective_name(&name_eval) {
 | 
			
		||||
                                let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                            message: "Deobfuscate annotation 'name' must be a valid scoreboard objective name.".to_string()
 | 
			
		||||
                                        });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                                handler.receive(error.clone());
 | 
			
		||||
                                return Err(error);
 | 
			
		||||
                            }
 | 
			
		||||
                            if !crate::util::is_valid_scoreboard_target(&target_eval) {
 | 
			
		||||
                                let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                            message: "Deobfuscate annotation 'target' must be a valid scoreboard player name.".to_string()
 | 
			
		||||
                                        });
 | 
			
		||||
                                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                                return Err(err);
 | 
			
		||||
                                handler.receive(error.clone());
 | 
			
		||||
                                return Err(error);
 | 
			
		||||
                            }
 | 
			
		||||
                            Ok((name_eval, target_eval))
 | 
			
		||||
                        } else {
 | 
			
		||||
                            let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                        message: "Deobfuscate annotation 'name' or 'target' could not have been evaluated at compile time.".to_string()
 | 
			
		||||
                                    });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                            handler.receive(error.clone());
 | 
			
		||||
                            Err(error)
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                                    annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                                    message: "Deobfuscate annotation 'name' and 'target' must be compile time expressions.".to_string()
 | 
			
		||||
                                });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                        handler.receive(error.clone());
 | 
			
		||||
                        Err(error)
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                        message: "Deobfuscate annotation must have both 'name' and 'target' keys."
 | 
			
		||||
                            .to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                            message:
 | 
			
		||||
                                "Deobfuscate annotation must have both 'name' and 'target' keys."
 | 
			
		||||
                                    .to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                    annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                    message: "Deobfuscate annotation must be a map.".to_string(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                Err(err)
 | 
			
		||||
                handler.receive(error.clone());
 | 
			
		||||
                Err(error)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            let hashed = md5::hash(program_identifier).to_hex_lowercase();
 | 
			
		||||
| 
						 | 
				
			
			@ -1013,12 +1017,12 @@ impl Transpiler {
 | 
			
		|||
        let deobfuscate_annotation = deobfuscate_annotations.next();
 | 
			
		||||
 | 
			
		||||
        if let Some(duplicate) = deobfuscate_annotations.next() {
 | 
			
		||||
            let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
            let error = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                annotation: duplicate.span(),
 | 
			
		||||
                message: "Multiple deobfuscate annotations are not allowed.".to_string(),
 | 
			
		||||
            });
 | 
			
		||||
            handler.receive(Box::new(err.clone()));
 | 
			
		||||
            return Err(err);
 | 
			
		||||
            handler.receive(error.clone());
 | 
			
		||||
            return Err(error);
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(deobfuscate_annotation) = deobfuscate_annotation {
 | 
			
		||||
            let deobfuscate_annotation_value = TranspileAnnotationValue::from_annotation_value(
 | 
			
		||||
| 
						 | 
				
			
			@ -1044,21 +1048,24 @@ impl Transpiler {
 | 
			
		|||
                }
 | 
			
		||||
                TranspileAnnotationValue::Map(map, _) => {
 | 
			
		||||
                    // TODO: implement when map deobfuscate annotation is implemented
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                        message: "Deobfuscate annotation value must be a string or none."
 | 
			
		||||
                            .to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                            message: "Deobfuscate annotation value must be a string or none."
 | 
			
		||||
                                .to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
                TranspileAnnotationValue::Expression(_, _) => {
 | 
			
		||||
                    let err = TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                        annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                        message: "Deobfuscate annotation value must be a map or none.".to_string(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                    let error =
 | 
			
		||||
                        TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
 | 
			
		||||
                            annotation: deobfuscate_annotation.span(),
 | 
			
		||||
                            message: "Deobfuscate annotation value must be a map or none."
 | 
			
		||||
                                .to_string(),
 | 
			
		||||
                        });
 | 
			
		||||
                    handler.receive(error.clone());
 | 
			
		||||
                    Err(error)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1161,7 +1168,7 @@ impl Transpiler {
 | 
			
		|||
                                expression: expression.span(),
 | 
			
		||||
                                expected_type: to.value_type().into(),
 | 
			
		||||
                            });
 | 
			
		||||
                            handler.receive(Box::new(err.clone()));
 | 
			
		||||
                            handler.receive(err.clone());
 | 
			
		||||
                            Err(err)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1212,7 +1219,7 @@ impl Transpiler {
 | 
			
		|||
                            expression: expression.span(),
 | 
			
		||||
                            expected_type: to.value_type().into(),
 | 
			
		||||
                        });
 | 
			
		||||
                        handler.receive(Box::new(err.clone()));
 | 
			
		||||
                        handler.receive(err.clone());
 | 
			
		||||
                        Err(err)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1221,7 +1228,7 @@ impl Transpiler {
 | 
			
		|||
                        expected_type: ExpectedType::Boolean,
 | 
			
		||||
                        expression: expression.span(),
 | 
			
		||||
                    });
 | 
			
		||||
                    handler.receive(Box::new(err.clone()));
 | 
			
		||||
                    handler.receive(err.clone());
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -1230,7 +1237,7 @@ impl Transpiler {
 | 
			
		|||
                    expected_type: to.value_type().into(),
 | 
			
		||||
                    expression: expression.span(),
 | 
			
		||||
                });
 | 
			
		||||
                handler.receive(Box::new(err.clone()));
 | 
			
		||||
                handler.receive(err.clone());
 | 
			
		||||
                Err(err)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ use std::borrow::Cow;
 | 
			
		|||
 | 
			
		||||
/// Escapes `"` and `\` in a string.
 | 
			
		||||
#[must_use]
 | 
			
		||||
pub fn escape_str(s: &str) -> Cow<'_, str> {
 | 
			
		||||
pub fn escape_str(s: &str) -> Cow<str> {
 | 
			
		||||
    if s.contains('"') || s.contains('\\') {
 | 
			
		||||
        let mut escaped = String::with_capacity(s.len());
 | 
			
		||||
        for c in s.chars() {
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ pub fn escape_str(s: &str) -> Cow<'_, str> {
 | 
			
		|||
 | 
			
		||||
/// Unescapes '\`', `\`, `\n`, `\r` and `\t` in a string.
 | 
			
		||||
#[must_use]
 | 
			
		||||
pub fn unescape_macro_string(s: &str) -> Cow<'_, str> {
 | 
			
		||||
pub fn unescape_macro_string(s: &str) -> Cow<str> {
 | 
			
		||||
    if s.contains('\\') || s.contains('`') {
 | 
			
		||||
        Cow::Owned(
 | 
			
		||||
            s.replace("\\n", "\n")
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ pub fn unescape_macro_string(s: &str) -> Cow<'_, str> {
 | 
			
		|||
/// Transforms an identifier to a macro name that only contains `a-zA-Z0-9_`.
 | 
			
		||||
#[cfg(feature = "shulkerbox")]
 | 
			
		||||
#[must_use]
 | 
			
		||||
pub fn identifier_to_macro(ident: &str) -> std::borrow::Cow<'_, str> {
 | 
			
		||||
pub fn identifier_to_macro(ident: &str) -> std::borrow::Cow<str> {
 | 
			
		||||
    if ident.contains("__")
 | 
			
		||||
        || ident
 | 
			
		||||
            .chars()
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +82,7 @@ pub fn identifier_to_macro(ident: &str) -> std::borrow::Cow<str> {
 | 
			
		|||
/// Transforms an identifier to a macro name that only contains `a-zA-Z0-9_`.
 | 
			
		||||
#[cfg(feature = "shulkerbox")]
 | 
			
		||||
#[must_use]
 | 
			
		||||
pub fn identifier_to_scoreboard_target(ident: &str) -> std::borrow::Cow<'_, str> {
 | 
			
		||||
pub fn identifier_to_scoreboard_target(ident: &str) -> std::borrow::Cow<str> {
 | 
			
		||||
    if !(..=16).contains(&ident.len())
 | 
			
		||||
        || ident
 | 
			
		||||
            .chars()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,10 @@ fn parsing_test1() {
 | 
			
		|||
    )
 | 
			
		||||
    .expect("Failed to parse");
 | 
			
		||||
 | 
			
		||||
    assert_eq!(parsed.namespace().name().str_content(), "parsing-test");
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        parsed.namespace().namespace_name().str_content(),
 | 
			
		||||
        "parsing-test"
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let declarations = parsed.declarations();
 | 
			
		||||
    assert_eq!(declarations.len(), 1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue