allow custom handlers instead of only printer
This commit is contained in:
		
							parent
							
								
									bc25da6f2c
								
							
						
					
					
						commit
						83d5f329f9
					
				| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					use std::{cell::Cell, fmt::Display};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a trait responsible for handling diagnostics in the interpreter.
 | 
					/// Represents a trait responsible for handling diagnostics in the interpreter.
 | 
				
			||||||
pub trait Handler<T> {
 | 
					pub trait Handler<T> {
 | 
				
			||||||
    /// Receive an error and handles it.
 | 
					    /// Receive an error and handles it.
 | 
				
			||||||
| 
						 | 
					@ -6,13 +8,89 @@ pub trait Handler<T> {
 | 
				
			||||||
    fn has_received(&self) -> bool;
 | 
					    fn has_received(&self) -> bool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Is a struct that implements [`Handler`] trait by doing nothing with the errors.
 | 
					/// Is a struct that implements [`Handler`] trait by doing nothing with the errors and
 | 
				
			||||||
 | 
					/// never signifying that it has received a message.
 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
				
			||||||
pub struct DummyHandler;
 | 
					pub struct VoidHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T> Handler<T> for DummyHandler {
 | 
					impl<T> Handler<T> for VoidHandler {
 | 
				
			||||||
    fn receive<E: Into<T>>(&self, _error: E) {}
 | 
					    fn receive<E: Into<T>>(&self, _error: E) {}
 | 
				
			||||||
    fn has_received(&self) -> bool {
 | 
					    fn has_received(&self) -> bool {
 | 
				
			||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A handler that does not print the error to the standard error stream.
 | 
				
			||||||
 | 
					#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
 | 
				
			||||||
 | 
					pub struct SilentHandler {
 | 
				
			||||||
 | 
					    received: Cell<bool>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SilentHandler {
 | 
				
			||||||
 | 
					    /// Creates a new [`SilentHandler`].
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new() -> Self {
 | 
				
			||||||
 | 
					        Self::default()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> Handler<T> for SilentHandler {
 | 
				
			||||||
 | 
					    fn receive<E: Into<T>>(&self, _error: E) {
 | 
				
			||||||
 | 
					        self.received.set(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn has_received(&self) -> bool {
 | 
				
			||||||
 | 
					        self.received.get()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A simple error handler that prints the error to the standard error stream.
 | 
				
			||||||
 | 
					#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
 | 
				
			||||||
 | 
					pub struct PrintHandler {
 | 
				
			||||||
 | 
					    printed: Cell<bool>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PrintHandler {
 | 
				
			||||||
 | 
					    /// Creates a new [`PrintHandler`].
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new() -> Self {
 | 
				
			||||||
 | 
					        Self::default()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Display> Handler<T> for PrintHandler {
 | 
				
			||||||
 | 
					    fn receive<E: Into<T>>(&self, error: E) {
 | 
				
			||||||
 | 
					        eprintln!("{}", error.into());
 | 
				
			||||||
 | 
					        self.printed.set(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn has_received(&self) -> bool {
 | 
				
			||||||
 | 
					        self.printed.get()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_void_handler() {
 | 
				
			||||||
 | 
					        let handler = VoidHandler;
 | 
				
			||||||
 | 
					        Handler::<&str>::receive(&handler, "error");
 | 
				
			||||||
 | 
					        assert!(!Handler::<&str>::has_received(&handler));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_silent_handler() {
 | 
				
			||||||
 | 
					        let handler = SilentHandler::new();
 | 
				
			||||||
 | 
					        Handler::<&str>::receive(&handler, "error");
 | 
				
			||||||
 | 
					        assert!(Handler::<&str>::has_received(&handler));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_print_handler() {
 | 
				
			||||||
 | 
					        let handler = PrintHandler::new();
 | 
				
			||||||
 | 
					        Handler::<&str>::receive(&handler, "error");
 | 
				
			||||||
 | 
					        assert!(Handler::<&str>::has_received(&handler));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,14 @@
 | 
				
			||||||
pub enum Error {
 | 
					pub enum Error {
 | 
				
			||||||
    #[error("An error occurred while working with Input/Output.")]
 | 
					    #[error("An error occurred while working with Input/Output.")]
 | 
				
			||||||
    IoError(String),
 | 
					    IoError(String),
 | 
				
			||||||
 | 
					    #[error("An error occurred while lexing the source code.")]
 | 
				
			||||||
 | 
					    LexicalError(#[from] crate::lexical::Error),
 | 
				
			||||||
    #[error("An error occured while tokenizing the source code.")]
 | 
					    #[error("An error occured while tokenizing the source code.")]
 | 
				
			||||||
    TokenizeError(#[from] crate::lexical::token::TokenizeError),
 | 
					    TokenizeError(#[from] crate::lexical::token::TokenizeError),
 | 
				
			||||||
    #[error("An error occurred while parsing the source code.")]
 | 
					    #[error("An error occurred while parsing the source code.")]
 | 
				
			||||||
    ParseError(#[from] crate::syntax::error::Error),
 | 
					    ParseError(#[from] crate::syntax::error::Error),
 | 
				
			||||||
    #[error("An error occurred while transpiling the source code.")]
 | 
					    #[error("An error occurred while transpiling the source code.")]
 | 
				
			||||||
    TranspileError(#[from] crate::transpile::error::TranspileError),
 | 
					    TranspileError(#[from] crate::transpile::TranspileError),
 | 
				
			||||||
    #[error("An error occurred")]
 | 
					    #[error("An error occurred")]
 | 
				
			||||||
    Other(&'static str),
 | 
					    Other(&'static str),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@ mod error;
 | 
				
			||||||
pub use error::{Error, Result};
 | 
					pub use error::{Error, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod diagnostic;
 | 
					mod diagnostic;
 | 
				
			||||||
pub use diagnostic::{DummyHandler, Handler};
 | 
					pub use diagnostic::{Handler, PrintHandler, SilentHandler, VoidHandler};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod file_provider;
 | 
					mod file_provider;
 | 
				
			||||||
pub use file_provider::{FileProvider, FsProvider};
 | 
					pub use file_provider::{FileProvider, FsProvider};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
use std::{borrow::Cow, collections::HashMap, fmt::Display, str::FromStr, sync::OnceLock};
 | 
					use std::{borrow::Cow, collections::HashMap, fmt::Display, str::FromStr, sync::OnceLock};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::base::{
 | 
					use crate::base::{
 | 
				
			||||||
 | 
					    self,
 | 
				
			||||||
    source_file::{SourceElement, SourceIterator, Span},
 | 
					    source_file::{SourceElement, SourceIterator, Span},
 | 
				
			||||||
    Handler,
 | 
					    Handler,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -11,7 +12,7 @@ use enum_as_inner::EnumAsInner;
 | 
				
			||||||
use strum::IntoEnumIterator;
 | 
					use strum::IntoEnumIterator;
 | 
				
			||||||
use strum_macros::EnumIter;
 | 
					use strum_macros::EnumIter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{error::UnterminatedDelimitedComment, Error};
 | 
					use super::error::{self, UnterminatedDelimitedComment};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Is an enumeration representing keywords in shulkerscript.
 | 
					/// Is an enumeration representing keywords in shulkerscript.
 | 
				
			||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
					#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 | 
				
			||||||
| 
						 | 
					@ -439,7 +440,7 @@ impl Token {
 | 
				
			||||||
        start: usize,
 | 
					        start: usize,
 | 
				
			||||||
        character: char,
 | 
					        character: char,
 | 
				
			||||||
        prev_token: Option<&Self>,
 | 
					        prev_token: Option<&Self>,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Result<Self, TokenizeError> {
 | 
					    ) -> Result<Self, TokenizeError> {
 | 
				
			||||||
        // Single line comment
 | 
					        // Single line comment
 | 
				
			||||||
        if let Some((_, '/')) = iter.peek() {
 | 
					        if let Some((_, '/')) = iter.peek() {
 | 
				
			||||||
| 
						 | 
					@ -503,9 +504,9 @@ impl Token {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                .into())
 | 
					                .into())
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                handler.receive(UnterminatedDelimitedComment {
 | 
					                handler.receive(error::Error::from(UnterminatedDelimitedComment {
 | 
				
			||||||
                    span: Span::new(iter.source_file().clone(), start, start + 2).unwrap(),
 | 
					                    span: Span::new(iter.source_file().clone(), start, start + 2).unwrap(),
 | 
				
			||||||
                });
 | 
					                }));
 | 
				
			||||||
                return Err(TokenizeError::FatalLexicalError);
 | 
					                return Err(TokenizeError::FatalLexicalError);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -576,7 +577,7 @@ impl Token {
 | 
				
			||||||
    /// - [`TokenizeError::FatalLexicalError`] - A fatal lexical error occurred.
 | 
					    /// - [`TokenizeError::FatalLexicalError`] - A fatal lexical error occurred.
 | 
				
			||||||
    pub fn tokenize(
 | 
					    pub fn tokenize(
 | 
				
			||||||
        iter: &mut SourceIterator,
 | 
					        iter: &mut SourceIterator,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
        prev_token: Option<&Self>,
 | 
					        prev_token: Option<&Self>,
 | 
				
			||||||
    ) -> Result<Self, TokenizeError> {
 | 
					    ) -> Result<Self, TokenizeError> {
 | 
				
			||||||
        // Gets the first character
 | 
					        // Gets the first character
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ use derive_more::{Deref, From};
 | 
				
			||||||
use enum_as_inner::EnumAsInner;
 | 
					use enum_as_inner::EnumAsInner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::base::{
 | 
					use crate::base::{
 | 
				
			||||||
 | 
					    self,
 | 
				
			||||||
    source_file::{SourceElement, SourceFile, Span},
 | 
					    source_file::{SourceElement, SourceFile, Span},
 | 
				
			||||||
    Handler,
 | 
					    Handler,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -46,7 +47,7 @@ impl TokenStream {
 | 
				
			||||||
    /// encountered during tokenization.
 | 
					    /// encountered during tokenization.
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    #[tracing::instrument(level = "debug", skip_all, fields(source_file = %source_file.path().display()))]
 | 
					    #[tracing::instrument(level = "debug", skip_all, fields(source_file = %source_file.path().display()))]
 | 
				
			||||||
    pub fn tokenize(source_file: &Arc<SourceFile>, handler: &impl Handler<error::Error>) -> Self {
 | 
					    pub fn tokenize(source_file: &Arc<SourceFile>, handler: &impl Handler<base::Error>) -> Self {
 | 
				
			||||||
        // The list of token trees that will be returned.
 | 
					        // The list of token trees that will be returned.
 | 
				
			||||||
        let mut tokens = Vec::new();
 | 
					        let mut tokens = Vec::new();
 | 
				
			||||||
        let mut source_file_iterator = source_file.iter();
 | 
					        let mut source_file_iterator = source_file.iter();
 | 
				
			||||||
| 
						 | 
					@ -81,7 +82,7 @@ impl TokenStream {
 | 
				
			||||||
    /// Handles a token.
 | 
					    /// Handles a token.
 | 
				
			||||||
    fn handle_token(
 | 
					    fn handle_token(
 | 
				
			||||||
        tokens: &mut Vec<Token>,
 | 
					        tokens: &mut Vec<Token>,
 | 
				
			||||||
        handler: &impl Handler<error::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<TokenTree> {
 | 
					    ) -> Option<TokenTree> {
 | 
				
			||||||
        tokens
 | 
					        tokens
 | 
				
			||||||
            .pop()
 | 
					            .pop()
 | 
				
			||||||
| 
						 | 
					@ -92,7 +93,7 @@ impl TokenStream {
 | 
				
			||||||
    fn handle_popped_token(
 | 
					    fn handle_popped_token(
 | 
				
			||||||
        tokens: &mut Vec<Token>,
 | 
					        tokens: &mut Vec<Token>,
 | 
				
			||||||
        popped_token: Token,
 | 
					        popped_token: Token,
 | 
				
			||||||
        handler: &impl Handler<error::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<TokenTree> {
 | 
					    ) -> Option<TokenTree> {
 | 
				
			||||||
        match popped_token {
 | 
					        match popped_token {
 | 
				
			||||||
            Token::Punctuation(punc) if punc.punctuation == '{' => {
 | 
					            Token::Punctuation(punc) if punc.punctuation == '{' => {
 | 
				
			||||||
| 
						 | 
					@ -116,7 +117,7 @@ impl TokenStream {
 | 
				
			||||||
        tokens: &mut Vec<Token>,
 | 
					        tokens: &mut Vec<Token>,
 | 
				
			||||||
        open: Punctuation,
 | 
					        open: Punctuation,
 | 
				
			||||||
        delimiter: Delimiter,
 | 
					        delimiter: Delimiter,
 | 
				
			||||||
        handler: &impl Handler<error::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Delimited> {
 | 
					    ) -> Option<Delimited> {
 | 
				
			||||||
        let mut token_trees = Vec::new();
 | 
					        let mut token_trees = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										145
									
								
								src/lib.rs
								
								
								
								
							
							
						
						
									
										145
									
								
								src/lib.rs
								
								
								
								
							| 
						 | 
					@ -19,56 +19,77 @@ pub mod lexical;
 | 
				
			||||||
pub mod syntax;
 | 
					pub mod syntax;
 | 
				
			||||||
pub mod transpile;
 | 
					pub mod transpile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod public_helpers;
 | 
					use std::path::Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{cell::Cell, fmt::Display, path::Path};
 | 
					use base::{source_file::SourceFile, Error, FileProvider, Handler, Result};
 | 
				
			||||||
 | 
					use syntax::{parser::Parser, syntax_tree::program::ProgramFile};
 | 
				
			||||||
use base::{FileProvider, Handler, Result};
 | 
					 | 
				
			||||||
use syntax::syntax_tree::program::ProgramFile;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					#[cfg(feature = "shulkerbox")]
 | 
				
			||||||
use shulkerbox::{datapack::Datapack, virtual_fs::VFolder};
 | 
					use shulkerbox::{datapack::Datapack, virtual_fs::VFolder};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::lexical::token_stream::TokenStream;
 | 
					use crate::lexical::token_stream::TokenStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Converts the given source code to tokens.
 | 
					/// Converts the given source code to tokens and returns a token stream.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Errors
 | 
					/// # Errors
 | 
				
			||||||
/// - If an error occurs while reading the file.
 | 
					/// - If an error occurs while loading the [`SourceFile`].
 | 
				
			||||||
pub fn tokenize<F>(file_provider: &F, path: &Path) -> Result<TokenStream>
 | 
					pub fn tokenize(
 | 
				
			||||||
where
 | 
					    handler: &impl Handler<base::Error>,
 | 
				
			||||||
    F: FileProvider,
 | 
					    file_provider: &impl FileProvider,
 | 
				
			||||||
{
 | 
					    path: &Path,
 | 
				
			||||||
    let printer = Printer::new();
 | 
					) -> Result<TokenStream> {
 | 
				
			||||||
 | 
					    tracing::info!("Tokenizing the source code at path: {}", path.display());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public_helpers::tokenize(&printer, file_provider, path)
 | 
					    let source_file = SourceFile::load(path, file_provider)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(TokenStream::tokenize(&source_file, handler))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Parses the given source code.
 | 
					/// Parses the given source code and returns the AST of the program.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Errors
 | 
					/// # Errors
 | 
				
			||||||
/// - If an error occurs while reading the file.
 | 
					/// - If an error occurs during [`tokenize()`].
 | 
				
			||||||
/// - If an error occurs while parsing the source code.
 | 
					/// - If an error occurs while parsing the source code.
 | 
				
			||||||
pub fn parse<F>(file_provider: &F, path: &Path) -> Result<ProgramFile>
 | 
					pub fn parse(
 | 
				
			||||||
where
 | 
					    handler: &impl Handler<base::Error>,
 | 
				
			||||||
    F: FileProvider,
 | 
					    file_provider: &impl FileProvider,
 | 
				
			||||||
{
 | 
					    path: &Path,
 | 
				
			||||||
    let printer = Printer::new();
 | 
					) -> Result<ProgramFile> {
 | 
				
			||||||
 | 
					    let tokens = tokenize(handler, file_provider, path)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public_helpers::parse(&printer, file_provider, path)
 | 
					    if handler.has_received() {
 | 
				
			||||||
 | 
					        return Err(Error::Other(
 | 
				
			||||||
 | 
					            "An error occurred while tokenizing the source code.",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tracing::info!("Parsing the source code at path: {}", path.display());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut parser = Parser::new(&tokens);
 | 
				
			||||||
 | 
					    let program = parser.parse_program(handler).ok_or(Error::Other(
 | 
				
			||||||
 | 
					        "An error occured while parsing the source code.",
 | 
				
			||||||
 | 
					    ))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if handler.has_received() {
 | 
				
			||||||
 | 
					        return Err(Error::Other(
 | 
				
			||||||
 | 
					            "An error occurred while parsing the source code.",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(program)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Transpiles the given source code into a shulkerbox [`Datapack`].
 | 
					/// Transpiles the given source code into a shulkerbox [`Datapack`].
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Parameters:
 | 
					/// # Parameters:
 | 
				
			||||||
/// - `script_paths`: A list of tuples containing the identifier of the program and the path to the script.
 | 
					/// - `script_paths`: A list of tuples containing the identifier and the path of each script file.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Errors
 | 
					/// # Errors
 | 
				
			||||||
/// - If an error occurs while reading the file.
 | 
					/// - If an error occurs during [`parse()`]
 | 
				
			||||||
/// - If an error occurs while parsing the source code.
 | 
					 | 
				
			||||||
/// - If an error occurs while transpiling the source code.
 | 
					/// - If an error occurs while transpiling the source code.
 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					#[cfg(feature = "shulkerbox")]
 | 
				
			||||||
pub fn transpile<F, P>(
 | 
					pub fn transpile<F, P>(
 | 
				
			||||||
 | 
					    handler: &impl Handler<base::Error>,
 | 
				
			||||||
    file_provider: &F,
 | 
					    file_provider: &F,
 | 
				
			||||||
    pack_format: u8,
 | 
					    pack_format: u8,
 | 
				
			||||||
    script_paths: &[(String, P)],
 | 
					    script_paths: &[(String, P)],
 | 
				
			||||||
| 
						 | 
					@ -77,22 +98,50 @@ where
 | 
				
			||||||
    F: FileProvider,
 | 
					    F: FileProvider,
 | 
				
			||||||
    P: AsRef<Path>,
 | 
					    P: AsRef<Path>,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    let printer = Printer::new();
 | 
					    use transpile::Transpiler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public_helpers::transpile(&printer, file_provider, pack_format, script_paths)
 | 
					    let programs = script_paths
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|(program_identifier, path)| {
 | 
				
			||||||
 | 
					            let program = parse(handler, file_provider, path.as_ref())?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Ok((program_identifier, program))
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if programs.iter().any(Result::is_err) {
 | 
				
			||||||
 | 
					        return Err(programs.into_iter().find_map(Result::err).unwrap());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let programs = programs
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .filter_map(Result::ok)
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tracing::info!("Transpiling the source code.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut transpiler = Transpiler::new(pack_format);
 | 
				
			||||||
 | 
					    transpiler.transpile(&programs, handler)?;
 | 
				
			||||||
 | 
					    let datapack = transpiler.into_datapack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if handler.has_received() {
 | 
				
			||||||
 | 
					        return Err(Error::Other(
 | 
				
			||||||
 | 
					            "An error occurred while transpiling the source code.",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(datapack)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Compiles the given source code.
 | 
					/// Compiles the given source code.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Parameters:
 | 
					/// # Parameters:
 | 
				
			||||||
/// - `script_paths`: A list of tuples containing the identifier of the program and the path to the script.
 | 
					/// - `script_paths`: A list of tuples containing the identifier and the path of each script file.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Errors
 | 
					/// # Errors
 | 
				
			||||||
/// - If an error occurs while reading the file.
 | 
					/// - If an error occurs during [`transpile()`]
 | 
				
			||||||
/// - If an error occurs while parsing the source code.
 | 
					 | 
				
			||||||
/// - If an error occurs while transpiling the source code.
 | 
					 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					#[cfg(feature = "shulkerbox")]
 | 
				
			||||||
pub fn compile<F, P>(
 | 
					pub fn compile<F, P>(
 | 
				
			||||||
 | 
					    handler: &impl Handler<base::Error>,
 | 
				
			||||||
    file_provider: &F,
 | 
					    file_provider: &F,
 | 
				
			||||||
    pack_format: u8,
 | 
					    pack_format: u8,
 | 
				
			||||||
    script_paths: &[(String, P)],
 | 
					    script_paths: &[(String, P)],
 | 
				
			||||||
| 
						 | 
					@ -101,35 +150,11 @@ where
 | 
				
			||||||
    F: FileProvider,
 | 
					    F: FileProvider,
 | 
				
			||||||
    P: AsRef<Path>,
 | 
					    P: AsRef<Path>,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    let printer = Printer::new();
 | 
					    use shulkerbox::prelude::CompileOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public_helpers::compile(&printer, file_provider, pack_format, script_paths)
 | 
					    let datapack = transpile(handler, file_provider, pack_format, script_paths)?;
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					    tracing::info!("Compiling the source code.");
 | 
				
			||||||
struct Printer {
 | 
					
 | 
				
			||||||
    printed: Cell<bool>,
 | 
					    Ok(datapack.compile(&CompileOptions::default()))
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Printer {
 | 
					 | 
				
			||||||
    /// Creates a new [`Printer`].
 | 
					 | 
				
			||||||
    fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            printed: Cell::new(false),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn has_printed(&self) -> bool {
 | 
					 | 
				
			||||||
        self.printed.get()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: Display> Handler<T> for Printer {
 | 
					 | 
				
			||||||
    fn receive<E: Into<T>>(&self, error: E) {
 | 
					 | 
				
			||||||
        eprintln!("{}", error.into());
 | 
					 | 
				
			||||||
        self.printed.set(true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn has_received(&self) -> bool {
 | 
					 | 
				
			||||||
        self.printed.get()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,120 +0,0 @@
 | 
				
			||||||
use std::path::Path;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::{
 | 
					 | 
				
			||||||
    base::{source_file::SourceFile, Error, FileProvider, Result},
 | 
					 | 
				
			||||||
    lexical::token_stream::TokenStream,
 | 
					 | 
				
			||||||
    syntax::{parser::Parser, syntax_tree::program::ProgramFile},
 | 
					 | 
				
			||||||
    Printer,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					 | 
				
			||||||
use crate::transpile::transpiler::Transpiler;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					 | 
				
			||||||
use shulkerbox::{datapack::Datapack, util::compile::CompileOptions, virtual_fs::VFolder};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Tokenizes the source code at the given path.
 | 
					 | 
				
			||||||
pub fn tokenize(
 | 
					 | 
				
			||||||
    printer: &Printer,
 | 
					 | 
				
			||||||
    file_provider: &impl FileProvider,
 | 
					 | 
				
			||||||
    path: &Path,
 | 
					 | 
				
			||||||
) -> Result<TokenStream> {
 | 
					 | 
				
			||||||
    tracing::info!("Tokenizing the source code at path: {}", path.display());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let source_file = SourceFile::load(path, file_provider)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(TokenStream::tokenize(&source_file, printer))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Parses the source code at the given path.
 | 
					 | 
				
			||||||
pub fn parse(
 | 
					 | 
				
			||||||
    printer: &Printer,
 | 
					 | 
				
			||||||
    file_provider: &impl FileProvider,
 | 
					 | 
				
			||||||
    path: &Path,
 | 
					 | 
				
			||||||
) -> Result<ProgramFile> {
 | 
					 | 
				
			||||||
    let tokens = tokenize(printer, file_provider, path)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if printer.has_printed() {
 | 
					 | 
				
			||||||
        return Err(Error::Other(
 | 
					 | 
				
			||||||
            "An error occurred while tokenizing the source code.",
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tracing::info!("Parsing the source code at path: {}", path.display());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut parser = Parser::new(&tokens);
 | 
					 | 
				
			||||||
    let program = parser.parse_program(printer).ok_or(Error::Other(
 | 
					 | 
				
			||||||
        "An error occured while parsing the source code.",
 | 
					 | 
				
			||||||
    ))?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if printer.has_printed() {
 | 
					 | 
				
			||||||
        return Err(Error::Other(
 | 
					 | 
				
			||||||
            "An error occurred while parsing the source code.",
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(program)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Transpiles the source code at the given paths into a shulkerbox [`Datapack`].
 | 
					 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					 | 
				
			||||||
pub fn transpile<F, P>(
 | 
					 | 
				
			||||||
    printer: &Printer,
 | 
					 | 
				
			||||||
    file_provider: &F,
 | 
					 | 
				
			||||||
    pack_format: u8,
 | 
					 | 
				
			||||||
    script_paths: &[(String, P)],
 | 
					 | 
				
			||||||
) -> Result<Datapack>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    F: FileProvider,
 | 
					 | 
				
			||||||
    P: AsRef<Path>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let programs = script_paths
 | 
					 | 
				
			||||||
        .iter()
 | 
					 | 
				
			||||||
        .map(|(program_identifier, path)| {
 | 
					 | 
				
			||||||
            let program = parse(printer, file_provider, path.as_ref())?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Ok((program_identifier, program))
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .collect::<Vec<_>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if programs.iter().any(Result::is_err) {
 | 
					 | 
				
			||||||
        return Err(programs.into_iter().find_map(Result::err).unwrap());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    let programs = programs
 | 
					 | 
				
			||||||
        .into_iter()
 | 
					 | 
				
			||||||
        .filter_map(Result::ok)
 | 
					 | 
				
			||||||
        .collect::<Vec<_>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tracing::info!("Transpiling the source code.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut transpiler = Transpiler::new(pack_format);
 | 
					 | 
				
			||||||
    transpiler.transpile(&programs, printer)?;
 | 
					 | 
				
			||||||
    let datapack = transpiler.into_datapack();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if printer.has_printed() {
 | 
					 | 
				
			||||||
        return Err(Error::Other(
 | 
					 | 
				
			||||||
            "An error occurred while transpiling the source code.",
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(datapack)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Compiles the source code at the given paths.
 | 
					 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					 | 
				
			||||||
pub fn compile<F, P>(
 | 
					 | 
				
			||||||
    printer: &Printer,
 | 
					 | 
				
			||||||
    file_provider: &F,
 | 
					 | 
				
			||||||
    pack_format: u8,
 | 
					 | 
				
			||||||
    script_paths: &[(String, P)],
 | 
					 | 
				
			||||||
) -> Result<VFolder>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    F: FileProvider,
 | 
					 | 
				
			||||||
    P: AsRef<Path>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let datapack = transpile(printer, file_provider, pack_format, script_paths)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tracing::info!("Compiling the source code.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(datapack.compile(&CompileOptions::default()))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ use derive_more::{Deref, DerefMut};
 | 
				
			||||||
use enum_as_inner::EnumAsInner;
 | 
					use enum_as_inner::EnumAsInner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::Handler,
 | 
					    base::{self, Handler},
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Identifier, Keyword, KeywordKind, Numeric, Punctuation, StringLiteral, Token},
 | 
					        token::{Identifier, Keyword, KeywordKind, Numeric, Punctuation, StringLiteral, Token},
 | 
				
			||||||
        token_stream::{Delimited, Delimiter, TokenStream, TokenTree},
 | 
					        token_stream::{Delimited, Delimiter, TokenStream, TokenTree},
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        delimiter: Delimiter,
 | 
					        delimiter: Delimiter,
 | 
				
			||||||
        f: impl FnOnce(&mut Self) -> Option<T>,
 | 
					        f: impl FnOnce(&mut Self) -> Option<T>,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<DelimitedTree<T>> {
 | 
					    ) -> Option<DelimitedTree<T>> {
 | 
				
			||||||
        self.current_frame.stop_at_significant();
 | 
					        self.current_frame.stop_at_significant();
 | 
				
			||||||
        let raw_token_tree = self
 | 
					        let raw_token_tree = self
 | 
				
			||||||
| 
						 | 
					@ -363,7 +363,7 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Errors
 | 
					    /// # Errors
 | 
				
			||||||
    /// If the next [`Token`] is not an [`Identifier`].
 | 
					    /// If the next [`Token`] is not an [`Identifier`].
 | 
				
			||||||
    pub fn parse_identifier(&mut self, handler: &impl Handler<Error>) -> Option<Identifier> {
 | 
					    pub fn parse_identifier(&mut self, handler: &impl Handler<base::Error>) -> Option<Identifier> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Identifier(ident)) => Some(ident),
 | 
					            Reading::Atomic(Token::Identifier(ident)) => Some(ident),
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
| 
						 | 
					@ -397,7 +397,10 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Errors
 | 
					    /// # Errors
 | 
				
			||||||
    /// If the next [`Token`] is not an [`StringLiteral`].
 | 
					    /// If the next [`Token`] is not an [`StringLiteral`].
 | 
				
			||||||
    pub fn parse_string_literal(&mut self, handler: &impl Handler<Error>) -> Option<StringLiteral> {
 | 
					    pub fn parse_string_literal(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> Option<StringLiteral> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::StringLiteral(literal)) => Some(literal),
 | 
					            Reading::Atomic(Token::StringLiteral(literal)) => Some(literal),
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
| 
						 | 
					@ -417,7 +420,7 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    pub fn parse_keyword(
 | 
					    pub fn parse_keyword(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        expected: KeywordKind,
 | 
					        expected: KeywordKind,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Keyword> {
 | 
					    ) -> Option<Keyword> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(keyword_token)) if keyword_token.keyword == expected => {
 | 
					            Reading::Atomic(Token::Keyword(keyword_token)) if keyword_token.keyword == expected => {
 | 
				
			||||||
| 
						 | 
					@ -441,7 +444,7 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        expected: char,
 | 
					        expected: char,
 | 
				
			||||||
        skip_insignificant: bool,
 | 
					        skip_insignificant: bool,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Punctuation> {
 | 
					    ) -> Option<Punctuation> {
 | 
				
			||||||
        match if skip_insignificant {
 | 
					        match if skip_insignificant {
 | 
				
			||||||
            self.next_significant_token()
 | 
					            self.next_significant_token()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,9 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        DummyHandler, Handler,
 | 
					        VoidHandler, Handler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Punctuation, StringLiteral, Token},
 | 
					        token::{Punctuation, StringLiteral, Token},
 | 
				
			||||||
| 
						 | 
					@ -240,7 +241,7 @@ impl SourceElement for Condition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`Condition`].
 | 
					    /// Parses a [`Condition`].
 | 
				
			||||||
    pub fn parse_condition(&mut self, handler: &impl Handler<Error>) -> Option<Condition> {
 | 
					    pub fn parse_condition(&mut self, handler: &impl Handler<base::Error>) -> Option<Condition> {
 | 
				
			||||||
        let mut lhs = Condition::Primary(self.parse_primary_condition(handler)?);
 | 
					        let mut lhs = Condition::Primary(self.parse_primary_condition(handler)?);
 | 
				
			||||||
        let mut expressions = VecDeque::new();
 | 
					        let mut expressions = VecDeque::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -305,7 +306,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`PrimaryCondition`].
 | 
					    /// Parses a [`PrimaryCondition`].
 | 
				
			||||||
    pub fn parse_primary_condition(
 | 
					    pub fn parse_primary_condition(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<PrimaryCondition> {
 | 
					    ) -> Option<PrimaryCondition> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // prefixed expression
 | 
					            // prefixed expression
 | 
				
			||||||
| 
						 | 
					@ -354,7 +355,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`ParenthesizedCondition`].
 | 
					    /// Parses a [`ParenthesizedCondition`].
 | 
				
			||||||
    pub fn parse_parenthesized_condition(
 | 
					    pub fn parse_parenthesized_condition(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ParenthesizedCondition> {
 | 
					    ) -> Option<ParenthesizedCondition> {
 | 
				
			||||||
        let token_tree = self.step_into(
 | 
					        let token_tree = self.step_into(
 | 
				
			||||||
            Delimiter::Parenthesis,
 | 
					            Delimiter::Parenthesis,
 | 
				
			||||||
| 
						 | 
					@ -377,11 +378,11 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        self.try_parse(|parser| match parser.next_significant_token() {
 | 
					        self.try_parse(|parser| match parser.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punc)) => match punc.punctuation {
 | 
					            Reading::Atomic(Token::Punctuation(punc)) => match punc.punctuation {
 | 
				
			||||||
                '&' => {
 | 
					                '&' => {
 | 
				
			||||||
                    let b = parser.parse_punctuation('&', false, &DummyHandler)?;
 | 
					                    let b = parser.parse_punctuation('&', false, &VoidHandler)?;
 | 
				
			||||||
                    Some(ConditionalBinaryOperator::LogicalAnd(punc, b))
 | 
					                    Some(ConditionalBinaryOperator::LogicalAnd(punc, b))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                '|' => {
 | 
					                '|' => {
 | 
				
			||||||
                    let b = parser.parse_punctuation('|', false, &DummyHandler)?;
 | 
					                    let b = parser.parse_punctuation('|', false, &VoidHandler)?;
 | 
				
			||||||
                    Some(ConditionalBinaryOperator::LogicalOr(punc, b))
 | 
					                    Some(ConditionalBinaryOperator::LogicalOr(punc, b))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => None,
 | 
					                _ => None,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,8 +6,9 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        DummyHandler, Handler,
 | 
					        Handler, VoidHandler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Identifier, Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
					        token::{Identifier, Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
				
			||||||
| 
						 | 
					@ -226,7 +227,7 @@ impl SourceElement for Import {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn parse_annotation(&mut self, handler: &impl Handler<Error>) -> Option<Annotation> {
 | 
					    pub fn parse_annotation(&mut self, handler: &impl Handler<base::Error>) -> Option<Annotation> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
 | 
					            Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
 | 
				
			||||||
                // eat the pound sign
 | 
					                // eat the pound sign
 | 
				
			||||||
| 
						 | 
					@ -280,7 +281,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[tracing::instrument(level = "trace", skip_all)]
 | 
					    #[tracing::instrument(level = "trace", skip_all)]
 | 
				
			||||||
    pub fn parse_declaration(&mut self, handler: &impl Handler<Error>) -> Option<Declaration> {
 | 
					    pub fn parse_declaration(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> Option<Declaration> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(function_keyword))
 | 
					            Reading::Atomic(Token::Keyword(function_keyword))
 | 
				
			||||||
                if function_keyword.keyword == KeywordKind::Function =>
 | 
					                if function_keyword.keyword == KeywordKind::Function =>
 | 
				
			||||||
| 
						 | 
					@ -355,7 +359,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    self.try_parse(|parser| parser
 | 
					                    self.try_parse(|parser| parser
 | 
				
			||||||
                        .parse_connected_list(
 | 
					                        .parse_connected_list(
 | 
				
			||||||
                            ',',
 | 
					                            ',',
 | 
				
			||||||
                            |parser| parser.parse_identifier(&DummyHandler),
 | 
					                            |parser| parser.parse_identifier(&VoidHandler),
 | 
				
			||||||
                            handler,
 | 
					                            handler,
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                        .map(ImportItems::Named)) // ,
 | 
					                        .map(ImportItems::Named)) // ,
 | 
				
			||||||
| 
						 | 
					@ -398,7 +402,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn parse_function(&mut self, handler: &impl Handler<Error>) -> Option<Function> {
 | 
					    pub fn parse_function(&mut self, handler: &impl Handler<base::Error>) -> Option<Function> {
 | 
				
			||||||
        if let Reading::Atomic(Token::Keyword(function_keyword)) = self.stop_at_significant() {
 | 
					        if let Reading::Atomic(Token::Keyword(function_keyword)) = self.stop_at_significant() {
 | 
				
			||||||
            // eat the function keyword
 | 
					            // eat the function keyword
 | 
				
			||||||
            self.forward();
 | 
					            self.forward();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        Handler,
 | 
					        Handler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -155,12 +156,12 @@ impl LuaCode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses an [`Expression`]
 | 
					    /// Parses an [`Expression`]
 | 
				
			||||||
    pub fn parse_expression(&mut self, handler: &impl Handler<Error>) -> Option<Expression> {
 | 
					    pub fn parse_expression(&mut self, handler: &impl Handler<base::Error>) -> Option<Expression> {
 | 
				
			||||||
        Some(Expression::Primary(self.parse_primary(handler)?))
 | 
					        Some(Expression::Primary(self.parse_primary(handler)?))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Parses an [`Primary`]
 | 
					    /// Parses an [`Primary`]
 | 
				
			||||||
    pub fn parse_primary(&mut self, handler: &impl Handler<Error>) -> Option<Primary> {
 | 
					    pub fn parse_primary(&mut self, handler: &impl Handler<base::Error>) -> Option<Primary> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // identifier expression
 | 
					            // identifier expression
 | 
				
			||||||
            Reading::Atomic(Token::Identifier(identifier)) => {
 | 
					            Reading::Atomic(Token::Identifier(identifier)) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,9 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        DummyHandler, Handler,
 | 
					        Handler, VoidHandler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Punctuation, Token},
 | 
					        token::{Punctuation, Token},
 | 
				
			||||||
| 
						 | 
					@ -14,7 +15,7 @@ use crate::{
 | 
				
			||||||
    syntax::parser::Reading,
 | 
					    syntax::parser::Reading,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{error::Error, parser::Parser};
 | 
					use super::parser::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod condition;
 | 
					pub mod condition;
 | 
				
			||||||
pub mod declaration;
 | 
					pub mod declaration;
 | 
				
			||||||
| 
						 | 
					@ -76,7 +77,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        delimiter: Delimiter,
 | 
					        delimiter: Delimiter,
 | 
				
			||||||
        separator: char,
 | 
					        separator: char,
 | 
				
			||||||
        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
					        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<DelimitedList<T>> {
 | 
					    ) -> Option<DelimitedList<T>> {
 | 
				
			||||||
        fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option<Punctuation> {
 | 
					        fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option<Punctuation> {
 | 
				
			||||||
            if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| {
 | 
					            if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| {
 | 
				
			||||||
| 
						 | 
					@ -162,14 +163,14 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        seperator: char,
 | 
					        seperator: char,
 | 
				
			||||||
        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
					        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
				
			||||||
        _handler: &impl Handler<Error>,
 | 
					        _handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ConnectedList<T, Punctuation>> {
 | 
					    ) -> Option<ConnectedList<T, Punctuation>> {
 | 
				
			||||||
        let first = f(self)?;
 | 
					        let first = f(self)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut rest = Vec::new();
 | 
					        let mut rest = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while let Some(sep) =
 | 
					        while let Some(sep) =
 | 
				
			||||||
            self.try_parse(|parser| parser.parse_punctuation(seperator, true, &DummyHandler))
 | 
					            self.try_parse(|parser| parser.parse_punctuation(seperator, true, &VoidHandler))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if let Some(element) = self.try_parse(&mut f) {
 | 
					            if let Some(element) = self.try_parse(&mut f) {
 | 
				
			||||||
                rest.push((sep, element));
 | 
					                rest.push((sep, element));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,14 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        Handler,
 | 
					        Handler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
					    lexical::token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        error::{Error, SyntaxKind, UnexpectedSyntax},
 | 
					        self,
 | 
				
			||||||
 | 
					        error::{SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -79,7 +81,7 @@ impl Namespace {
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`ProgramFile`].
 | 
					    /// Parses a [`ProgramFile`].
 | 
				
			||||||
    #[tracing::instrument(level = "debug", skip_all)]
 | 
					    #[tracing::instrument(level = "debug", skip_all)]
 | 
				
			||||||
    pub fn parse_program(&mut self, handler: &impl Handler<Error>) -> Option<ProgramFile> {
 | 
					    pub fn parse_program(&mut self, handler: &impl Handler<base::Error>) -> Option<ProgramFile> {
 | 
				
			||||||
        tracing::debug!("Parsing program");
 | 
					        tracing::debug!("Parsing program");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let namespace = match self.stop_at_significant() {
 | 
					        let namespace = match self.stop_at_significant() {
 | 
				
			||||||
| 
						 | 
					@ -102,10 +104,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(UnexpectedSyntax {
 | 
					                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Keyword(KeywordKind::Namespace),
 | 
					                    expected: SyntaxKind::Keyword(KeywordKind::Namespace),
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                });
 | 
					                }));
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }?;
 | 
					        }?;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        Handler,
 | 
					        Handler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -14,10 +15,7 @@ use crate::{
 | 
				
			||||||
        token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
 | 
					        token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::parser::{Parser, Reading},
 | 
				
			||||||
        error::Error,
 | 
					 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use self::execute_block::ExecuteBlock;
 | 
					use self::execute_block::ExecuteBlock;
 | 
				
			||||||
| 
						 | 
					@ -211,7 +209,7 @@ impl Semicolon {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`Block`].
 | 
					    /// Parses a [`Block`].
 | 
				
			||||||
    pub fn parse_block(&mut self, handler: &impl Handler<Error>) -> Option<Block> {
 | 
					    pub fn parse_block(&mut self, handler: &impl Handler<base::Error>) -> Option<Block> {
 | 
				
			||||||
        let token_tree = self.step_into(
 | 
					        let token_tree = self.step_into(
 | 
				
			||||||
            Delimiter::Brace,
 | 
					            Delimiter::Brace,
 | 
				
			||||||
            |parser| {
 | 
					            |parser| {
 | 
				
			||||||
| 
						 | 
					@ -250,7 +248,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Parses a [`Statement`].
 | 
					    /// Parses a [`Statement`].
 | 
				
			||||||
    #[tracing::instrument(level = "trace", skip_all)]
 | 
					    #[tracing::instrument(level = "trace", skip_all)]
 | 
				
			||||||
    pub fn parse_statement(&mut self, handler: &impl Handler<Error>) -> Option<Statement> {
 | 
					    pub fn parse_statement(&mut self, handler: &impl Handler<base::Error>) -> Option<Statement> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // variable declaration
 | 
					            // variable declaration
 | 
				
			||||||
            Reading::Atomic(Token::CommandLiteral(command)) => {
 | 
					            Reading::Atomic(Token::CommandLiteral(command)) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,15 +6,17 @@ use getset::Getters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        DummyHandler, Handler,
 | 
					        VoidHandler, Handler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
					        token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        error::{Error, SyntaxKind, UnexpectedSyntax},
 | 
					        self,
 | 
				
			||||||
 | 
					        error::{SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        parser::{DelimitedTree, Parser, Reading},
 | 
					        parser::{DelimitedTree, Parser, Reading},
 | 
				
			||||||
        syntax_tree::condition::ParenthesizedCondition,
 | 
					        syntax_tree::condition::ParenthesizedCondition,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -711,7 +713,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses an [`ExecuteBlock`].
 | 
					    /// Parses an [`ExecuteBlock`].
 | 
				
			||||||
    pub fn parse_execute_block_statement(
 | 
					    pub fn parse_execute_block_statement(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ExecuteBlock> {
 | 
					    ) -> Option<ExecuteBlock> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(if_keyword))
 | 
					            Reading::Atomic(Token::Keyword(if_keyword))
 | 
				
			||||||
| 
						 | 
					@ -728,7 +730,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let else_tail = self.try_parse(|parser| {
 | 
					                let else_tail = self.try_parse(|parser| {
 | 
				
			||||||
                    let block = parser.parse_block(&DummyHandler)?;
 | 
					                    let block = parser.parse_block(&VoidHandler)?;
 | 
				
			||||||
                    let (else_keyword, else_block) = match parser.stop_at_significant() {
 | 
					                    let (else_keyword, else_block) = match parser.stop_at_significant() {
 | 
				
			||||||
                        // else statement
 | 
					                        // else statement
 | 
				
			||||||
                        Reading::Atomic(Token::Keyword(else_keyword))
 | 
					                        Reading::Atomic(Token::Keyword(else_keyword))
 | 
				
			||||||
| 
						 | 
					@ -775,10 +777,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                        handler,
 | 
					                        handler,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    unexpected => {
 | 
					                    unexpected => {
 | 
				
			||||||
                        handler.receive(UnexpectedSyntax {
 | 
					                        handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
				
			||||||
                            expected: SyntaxKind::Punctuation('('),
 | 
					                            expected: SyntaxKind::Punctuation('('),
 | 
				
			||||||
                            found: unexpected.into_token(),
 | 
					                            found: unexpected.into_token(),
 | 
				
			||||||
                        });
 | 
					                        }));
 | 
				
			||||||
                        None
 | 
					                        None
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }?;
 | 
					                }?;
 | 
				
			||||||
| 
						 | 
					@ -792,10 +794,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // unexpected
 | 
					            // unexpected
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(UnexpectedSyntax {
 | 
					                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::ExecuteBlock,
 | 
					                    expected: SyntaxKind::ExecuteBlock,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                });
 | 
					                }));
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -803,7 +805,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn parse_execute_block_tail(
 | 
					    fn parse_execute_block_tail(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ExecuteBlockTail> {
 | 
					    ) -> Option<ExecuteBlockTail> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // nested execute block
 | 
					            // nested execute block
 | 
				
			||||||
| 
						 | 
					@ -827,10 +829,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(UnexpectedSyntax {
 | 
					                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::ExecuteBlockTail,
 | 
					                    expected: SyntaxKind::ExecuteBlockTail,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                });
 | 
					                }));
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ mod enabled {
 | 
				
			||||||
    use mlua::Lua;
 | 
					    use mlua::Lua;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use crate::{
 | 
					    use crate::{
 | 
				
			||||||
        base::{source_file::SourceElement, Handler},
 | 
					        base::{self, source_file::SourceElement, Handler},
 | 
				
			||||||
        syntax::syntax_tree::expression::LuaCode,
 | 
					        syntax::syntax_tree::expression::LuaCode,
 | 
				
			||||||
        transpile::error::{TranspileError, TranspileResult},
 | 
					        transpile::error::{TranspileError, TranspileResult},
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -16,10 +16,7 @@ mod enabled {
 | 
				
			||||||
        /// # Errors
 | 
					        /// # Errors
 | 
				
			||||||
        /// - If Lua code evaluation is disabled.
 | 
					        /// - If Lua code evaluation is disabled.
 | 
				
			||||||
        #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
 | 
					        #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
 | 
				
			||||||
        pub fn eval_string(
 | 
					        pub fn eval_string(&self, handler: &impl Handler<base::Error>) -> TranspileResult<String> {
 | 
				
			||||||
            &self,
 | 
					 | 
				
			||||||
            handler: &impl Handler<TranspileError>,
 | 
					 | 
				
			||||||
        ) -> TranspileResult<String> {
 | 
					 | 
				
			||||||
            tracing::debug!("Evaluating Lua code");
 | 
					            tracing::debug!("Evaluating Lua code");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let lua = Lua::new();
 | 
					            let lua = Lua::new();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,15 @@
 | 
				
			||||||
#[doc(hidden)]
 | 
					#[doc(hidden)]
 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					#[cfg(feature = "shulkerbox")]
 | 
				
			||||||
pub mod conversions;
 | 
					pub mod conversions;
 | 
				
			||||||
pub mod error;
 | 
					mod error;
 | 
				
			||||||
 | 
					#[doc(inline)]
 | 
				
			||||||
 | 
					#[allow(clippy::module_name_repetitions)]
 | 
				
			||||||
 | 
					pub use error::{TranspileError, TranspileResult};
 | 
				
			||||||
#[doc(hidden)]
 | 
					#[doc(hidden)]
 | 
				
			||||||
pub mod lua;
 | 
					pub mod lua;
 | 
				
			||||||
#[cfg(feature = "shulkerbox")]
 | 
					#[cfg(feature = "shulkerbox")]
 | 
				
			||||||
pub mod transpiler;
 | 
					mod transpiler;
 | 
				
			||||||
 | 
					#[doc(inline)]
 | 
				
			||||||
 | 
					pub use transpiler::Transpiler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod util;
 | 
					mod util;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ use std::{collections::HashMap, iter, sync::RwLock};
 | 
				
			||||||
use shulkerbox::datapack::{self, Command, Datapack, Execute};
 | 
					use shulkerbox::datapack::{self, Command, Datapack, Execute};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{source_file::SourceElement, Handler},
 | 
					    base::{self, source_file::SourceElement, Handler},
 | 
				
			||||||
    syntax::syntax_tree::{
 | 
					    syntax::syntax_tree::{
 | 
				
			||||||
        declaration::{Declaration, ImportItems},
 | 
					        declaration::{Declaration, ImportItems},
 | 
				
			||||||
        expression::{Expression, FunctionCall, Primary},
 | 
					        expression::{Expression, FunctionCall, Primary},
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,7 @@ impl Transpiler {
 | 
				
			||||||
    pub fn transpile<Ident>(
 | 
					    pub fn transpile<Ident>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        programs: &[(Ident, ProgramFile)],
 | 
					        programs: &[(Ident, ProgramFile)],
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Result<(), TranspileError>
 | 
					    ) -> Result<(), TranspileError>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Ident: AsRef<str>,
 | 
					        Ident: AsRef<str>,
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        program: &ProgramFile,
 | 
					        program: &ProgramFile,
 | 
				
			||||||
        identifier: &str,
 | 
					        identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let namespace = program.namespace();
 | 
					        let namespace = program.namespace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,12 +117,13 @@ impl Transpiler {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Transpiles the given declaration.
 | 
					    /// Transpiles the given declaration.
 | 
				
			||||||
 | 
					    #[allow(clippy::needless_pass_by_ref_mut)]
 | 
				
			||||||
    fn transpile_declaration(
 | 
					    fn transpile_declaration(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        declaration: &Declaration,
 | 
					        declaration: &Declaration,
 | 
				
			||||||
        namespace: &Namespace,
 | 
					        namespace: &Namespace,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        _handler: &impl Handler<TranspileError>,
 | 
					        _handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        match declaration {
 | 
					        match declaration {
 | 
				
			||||||
            Declaration::Function(function) => {
 | 
					            Declaration::Function(function) => {
 | 
				
			||||||
| 
						 | 
					@ -184,7 +185,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        name: &str,
 | 
					        name: &str,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<String> {
 | 
					    ) -> TranspileResult<String> {
 | 
				
			||||||
        let program_query = (program_identifier.to_string(), name.to_string());
 | 
					        let program_query = (program_identifier.to_string(), name.to_string());
 | 
				
			||||||
        let alias_query = {
 | 
					        let alias_query = {
 | 
				
			||||||
| 
						 | 
					@ -289,7 +290,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        statements: &[Statement],
 | 
					        statements: &[Statement],
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Vec<Command>> {
 | 
					    ) -> TranspileResult<Vec<Command>> {
 | 
				
			||||||
        let mut errors = Vec::new();
 | 
					        let mut errors = Vec::new();
 | 
				
			||||||
        let commands = statements
 | 
					        let commands = statements
 | 
				
			||||||
| 
						 | 
					@ -314,7 +315,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        statement: &Statement,
 | 
					        statement: &Statement,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Option<Command>> {
 | 
					    ) -> TranspileResult<Option<Command>> {
 | 
				
			||||||
        match statement {
 | 
					        match statement {
 | 
				
			||||||
            Statement::LiteralCommand(literal_command) => {
 | 
					            Statement::LiteralCommand(literal_command) => {
 | 
				
			||||||
| 
						 | 
					@ -381,7 +382,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        func: &FunctionCall,
 | 
					        func: &FunctionCall,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Command> {
 | 
					    ) -> TranspileResult<Command> {
 | 
				
			||||||
        let identifier = func.identifier().span();
 | 
					        let identifier = func.identifier().span();
 | 
				
			||||||
        let identifier_name = identifier.str();
 | 
					        let identifier_name = identifier.str();
 | 
				
			||||||
| 
						 | 
					@ -394,7 +395,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        execute: &ExecuteBlock,
 | 
					        execute: &ExecuteBlock,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Option<Command>> {
 | 
					    ) -> TranspileResult<Option<Command>> {
 | 
				
			||||||
        self.transpile_execute_block_internal(execute, program_identifier, handler)
 | 
					        self.transpile_execute_block_internal(execute, program_identifier, handler)
 | 
				
			||||||
            .map(|ex| ex.map(Command::Execute))
 | 
					            .map(|ex| ex.map(Command::Execute))
 | 
				
			||||||
| 
						 | 
					@ -404,7 +405,7 @@ impl Transpiler {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        execute: &ExecuteBlock,
 | 
					        execute: &ExecuteBlock,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Option<Execute>> {
 | 
					    ) -> TranspileResult<Option<Execute>> {
 | 
				
			||||||
        match execute {
 | 
					        match execute {
 | 
				
			||||||
            ExecuteBlock::HeadTail(head, tail) => {
 | 
					            ExecuteBlock::HeadTail(head, tail) => {
 | 
				
			||||||
| 
						 | 
					@ -489,7 +490,7 @@ impl Transpiler {
 | 
				
			||||||
        then: Execute,
 | 
					        then: Execute,
 | 
				
			||||||
        el: Option<&Else>,
 | 
					        el: Option<&Else>,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Option<Execute>> {
 | 
					    ) -> TranspileResult<Option<Execute>> {
 | 
				
			||||||
        let (_, cond) = cond.clone().dissolve();
 | 
					        let (_, cond) = cond.clone().dissolve();
 | 
				
			||||||
        let (_, cond, _) = cond.dissolve();
 | 
					        let (_, cond, _) = cond.dissolve();
 | 
				
			||||||
| 
						 | 
					@ -540,7 +541,7 @@ impl Transpiler {
 | 
				
			||||||
        head: &ExecuteBlockHead,
 | 
					        head: &ExecuteBlockHead,
 | 
				
			||||||
        tail: Option<Execute>,
 | 
					        tail: Option<Execute>,
 | 
				
			||||||
        program_identifier: &str,
 | 
					        program_identifier: &str,
 | 
				
			||||||
        handler: &impl Handler<TranspileError>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> TranspileResult<Option<Execute>> {
 | 
					    ) -> TranspileResult<Option<Execute>> {
 | 
				
			||||||
        Ok(match head {
 | 
					        Ok(match head {
 | 
				
			||||||
            ExecuteBlockHead::Conditional(cond) => {
 | 
					            ExecuteBlockHead::Conditional(cond) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ use std::path::Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use shulkerbox::virtual_fs::{VFile, VFolder};
 | 
					use shulkerbox::virtual_fs::{VFile, VFolder};
 | 
				
			||||||
use shulkerscript::{
 | 
					use shulkerscript::{
 | 
				
			||||||
    base::source_file::SourceElement,
 | 
					    base::{source_file::SourceElement, PrintHandler},
 | 
				
			||||||
    syntax::syntax_tree::{declaration::Declaration, statement::Statement},
 | 
					    syntax::syntax_tree::{declaration::Declaration, statement::Statement},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,8 @@ fn parsing_test1() {
 | 
				
			||||||
    let mut dir = VFolder::new();
 | 
					    let mut dir = VFolder::new();
 | 
				
			||||||
    dir.add_file("test1.shu", VFile::Text(source.to_string()));
 | 
					    dir.add_file("test1.shu", VFile::Text(source.to_string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let parsed = shulkerscript::parse(&dir, Path::new("test1.shu")).expect("Failed to parse");
 | 
					    let parsed = shulkerscript::parse(&PrintHandler::default(), &dir, Path::new("test1.shu"))
 | 
				
			||||||
 | 
					        .expect("Failed to parse");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
        parsed.namespace().namespace_name().str_content(),
 | 
					        parsed.namespace().namespace_name().str_content(),
 | 
				
			||||||
| 
						 | 
					@ -48,5 +49,6 @@ fn parsing_invalid() {
 | 
				
			||||||
    let mut dir = VFolder::new();
 | 
					    let mut dir = VFolder::new();
 | 
				
			||||||
    dir.add_file("invalid.shu", VFile::Text(source.to_string()));
 | 
					    dir.add_file("invalid.shu", VFile::Text(source.to_string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shulkerscript::parse(&dir, Path::new("invalid.shu")).expect_err("Expecting parsing failure");
 | 
					    shulkerscript::parse(&PrintHandler::default(), &dir, Path::new("invalid.shu"))
 | 
				
			||||||
 | 
					        .expect_err("Expecting parsing failure");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ use shulkerbox::{
 | 
				
			||||||
    datapack::{Command, Condition, Datapack, Execute},
 | 
					    datapack::{Command, Condition, Datapack, Execute},
 | 
				
			||||||
    virtual_fs::{VFile, VFolder},
 | 
					    virtual_fs::{VFile, VFolder},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use shulkerscript::base::PrintHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn transpile_test1() {
 | 
					fn transpile_test1() {
 | 
				
			||||||
| 
						 | 
					@ -9,8 +10,13 @@ fn transpile_test1() {
 | 
				
			||||||
    let mut dir = VFolder::new();
 | 
					    let mut dir = VFolder::new();
 | 
				
			||||||
    dir.add_file("test1.shu", VFile::Text(source.to_string()));
 | 
					    dir.add_file("test1.shu", VFile::Text(source.to_string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let transpiled = shulkerscript::transpile(&dir, 48, &[("test1".to_string(), "./test1.shu")])
 | 
					    let transpiled = shulkerscript::transpile(
 | 
				
			||||||
        .expect("Failed to transpile");
 | 
					        &PrintHandler::default(),
 | 
				
			||||||
 | 
					        &dir,
 | 
				
			||||||
 | 
					        48,
 | 
				
			||||||
 | 
					        &[("test1".to_string(), "./test1.shu")],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .expect("Failed to transpile");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let expected = {
 | 
					    let expected = {
 | 
				
			||||||
        let mut dp = Datapack::new(48);
 | 
					        let mut dp = Datapack::new(48);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue