allow custom handlers instead of only printer

This commit is contained in:
Moritz Hölting 2024-08-23 00:06:58 +02:00
parent bc25da6f2c
commit 83d5f329f9
20 changed files with 273 additions and 263 deletions

View File

@ -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));
}
}

View File

@ -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),
} }

View File

@ -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};

View File

@ -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

View File

@ -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();

View File

@ -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()
}
} }

View File

@ -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()))
}

View File

@ -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()

View File

@ -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,

View File

@ -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();

View File

@ -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)) => {

View File

@ -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));

View File

@ -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
} }
}?; }?;

View File

@ -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)) => {

View File

@ -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
} }
} }

View File

@ -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();

View File

@ -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;

View File

@ -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) => {

View File

@ -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");
} }

View File

@ -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);