From 83d5f329f91f336ae80b782e9fe9812914adc6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20H=C3=B6lting?= <87192362+moritz-hoelting@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:06:58 +0200 Subject: [PATCH] allow custom handlers instead of only printer --- src/base/diagnostic.rs | 84 +++++++++- src/base/error.rs | 4 +- src/base/mod.rs | 2 +- src/lexical/token.rs | 11 +- src/lexical/token_stream.rs | 9 +- src/lib.rs | 145 ++++++++++-------- src/public_helpers.rs | 120 --------------- src/syntax/parser.rs | 15 +- src/syntax/syntax_tree/condition.rs | 13 +- src/syntax/syntax_tree/declaration.rs | 14 +- src/syntax/syntax_tree/expression.rs | 5 +- src/syntax/syntax_tree/mod.rs | 11 +- src/syntax/syntax_tree/program.rs | 10 +- src/syntax/syntax_tree/statement.rs | 10 +- .../syntax_tree/statement/execute_block.rs | 24 +-- src/transpile/lua.rs | 7 +- src/transpile/mod.rs | 9 +- src/transpile/transpiler.rs | 25 +-- tests/parsing/main.rs | 8 +- tests/transpiling/main.rs | 10 +- 20 files changed, 273 insertions(+), 263 deletions(-) delete mode 100644 src/public_helpers.rs diff --git a/src/base/diagnostic.rs b/src/base/diagnostic.rs index 1b1a4a3..df27a64 100644 --- a/src/base/diagnostic.rs +++ b/src/base/diagnostic.rs @@ -1,3 +1,5 @@ +use std::{cell::Cell, fmt::Display}; + /// Represents a trait responsible for handling diagnostics in the interpreter. pub trait Handler { /// Receive an error and handles it. @@ -6,13 +8,89 @@ pub trait Handler { 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)] -pub struct DummyHandler; +pub struct VoidHandler; -impl Handler for DummyHandler { +impl Handler for VoidHandler { fn receive>(&self, _error: E) {} fn has_received(&self) -> bool { 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, +} + +impl SilentHandler { + /// Creates a new [`SilentHandler`]. + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +impl Handler for SilentHandler { + fn receive>(&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, +} + +impl PrintHandler { + /// Creates a new [`PrintHandler`]. + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +impl Handler for PrintHandler { + fn receive>(&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)); + } +} diff --git a/src/base/error.rs b/src/base/error.rs index 5575dce..5c8b776 100644 --- a/src/base/error.rs +++ b/src/base/error.rs @@ -4,12 +4,14 @@ pub enum Error { #[error("An error occurred while working with Input/Output.")] 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.")] TokenizeError(#[from] crate::lexical::token::TokenizeError), #[error("An error occurred while parsing the source code.")] ParseError(#[from] crate::syntax::error::Error), #[error("An error occurred while transpiling the source code.")] - TranspileError(#[from] crate::transpile::error::TranspileError), + TranspileError(#[from] crate::transpile::TranspileError), #[error("An error occurred")] Other(&'static str), } diff --git a/src/base/mod.rs b/src/base/mod.rs index c6e5a00..e5369bd 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -7,7 +7,7 @@ mod error; pub use error::{Error, Result}; mod diagnostic; -pub use diagnostic::{DummyHandler, Handler}; +pub use diagnostic::{Handler, PrintHandler, SilentHandler, VoidHandler}; mod file_provider; pub use file_provider::{FileProvider, FsProvider}; diff --git a/src/lexical/token.rs b/src/lexical/token.rs index 4415b51..ec43260 100644 --- a/src/lexical/token.rs +++ b/src/lexical/token.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, collections::HashMap, fmt::Display, str::FromStr, sync::OnceLock}; use crate::base::{ + self, source_file::{SourceElement, SourceIterator, Span}, Handler, }; @@ -11,7 +12,7 @@ use enum_as_inner::EnumAsInner; use strum::IntoEnumIterator; use strum_macros::EnumIter; -use super::{error::UnterminatedDelimitedComment, Error}; +use super::error::{self, UnterminatedDelimitedComment}; /// Is an enumeration representing keywords in shulkerscript. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -439,7 +440,7 @@ impl Token { start: usize, character: char, prev_token: Option<&Self>, - handler: &impl Handler, + handler: &impl Handler, ) -> Result { // Single line comment if let Some((_, '/')) = iter.peek() { @@ -503,9 +504,9 @@ impl Token { } .into()) } else { - handler.receive(UnterminatedDelimitedComment { + handler.receive(error::Error::from(UnterminatedDelimitedComment { span: Span::new(iter.source_file().clone(), start, start + 2).unwrap(), - }); + })); return Err(TokenizeError::FatalLexicalError); } } @@ -576,7 +577,7 @@ impl Token { /// - [`TokenizeError::FatalLexicalError`] - A fatal lexical error occurred. pub fn tokenize( iter: &mut SourceIterator, - handler: &impl Handler, + handler: &impl Handler, prev_token: Option<&Self>, ) -> Result { // Gets the first character diff --git a/src/lexical/token_stream.rs b/src/lexical/token_stream.rs index 21c1f12..1e3fb99 100644 --- a/src/lexical/token_stream.rs +++ b/src/lexical/token_stream.rs @@ -6,6 +6,7 @@ use derive_more::{Deref, From}; use enum_as_inner::EnumAsInner; use crate::base::{ + self, source_file::{SourceElement, SourceFile, Span}, Handler, }; @@ -46,7 +47,7 @@ impl TokenStream { /// encountered during tokenization. #[must_use] #[tracing::instrument(level = "debug", skip_all, fields(source_file = %source_file.path().display()))] - pub fn tokenize(source_file: &Arc, handler: &impl Handler) -> Self { + pub fn tokenize(source_file: &Arc, handler: &impl Handler) -> Self { // The list of token trees that will be returned. let mut tokens = Vec::new(); let mut source_file_iterator = source_file.iter(); @@ -81,7 +82,7 @@ impl TokenStream { /// Handles a token. fn handle_token( tokens: &mut Vec, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { tokens .pop() @@ -92,7 +93,7 @@ impl TokenStream { fn handle_popped_token( tokens: &mut Vec, popped_token: Token, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match popped_token { Token::Punctuation(punc) if punc.punctuation == '{' => { @@ -116,7 +117,7 @@ impl TokenStream { tokens: &mut Vec, open: Punctuation, delimiter: Delimiter, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { let mut token_trees = Vec::new(); diff --git a/src/lib.rs b/src/lib.rs index e82ca9e..3208843 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,56 +19,77 @@ pub mod lexical; pub mod syntax; pub mod transpile; -mod public_helpers; +use std::path::Path; -use std::{cell::Cell, fmt::Display, path::Path}; - -use base::{FileProvider, Handler, Result}; -use syntax::syntax_tree::program::ProgramFile; +use base::{source_file::SourceFile, Error, FileProvider, Handler, Result}; +use syntax::{parser::Parser, syntax_tree::program::ProgramFile}; #[cfg(feature = "shulkerbox")] use shulkerbox::{datapack::Datapack, virtual_fs::VFolder}; 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 -/// - If an error occurs while reading the file. -pub fn tokenize(file_provider: &F, path: &Path) -> Result -where - F: FileProvider, -{ - let printer = Printer::new(); +/// - If an error occurs while loading the [`SourceFile`]. +pub fn tokenize( + handler: &impl Handler, + file_provider: &impl FileProvider, + path: &Path, +) -> Result { + 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 -/// - If an error occurs while reading the file. +/// - If an error occurs during [`tokenize()`]. /// - If an error occurs while parsing the source code. -pub fn parse(file_provider: &F, path: &Path) -> Result -where - F: FileProvider, -{ - let printer = Printer::new(); +pub fn parse( + handler: &impl Handler, + file_provider: &impl FileProvider, + path: &Path, +) -> Result { + 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`]. /// /// # 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 -/// - If an error occurs while reading the file. -/// - If an error occurs while parsing the source code. +/// - If an error occurs during [`parse()`] /// - If an error occurs while transpiling the source code. #[cfg(feature = "shulkerbox")] pub fn transpile( + handler: &impl Handler, file_provider: &F, pack_format: u8, script_paths: &[(String, P)], @@ -77,22 +98,50 @@ where F: FileProvider, P: AsRef, { - 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::>(); + + 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::>(); + + 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. /// /// # 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 -/// - If an error occurs while reading the file. -/// - If an error occurs while parsing the source code. -/// - If an error occurs while transpiling the source code. +/// - If an error occurs during [`transpile()`] #[cfg(feature = "shulkerbox")] pub fn compile( + handler: &impl Handler, file_provider: &F, pack_format: u8, script_paths: &[(String, P)], @@ -101,35 +150,11 @@ where F: FileProvider, P: AsRef, { - let printer = Printer::new(); + use shulkerbox::prelude::CompileOptions; - public_helpers::compile(&printer, file_provider, pack_format, script_paths) -} - -struct Printer { - printed: Cell, -} - -impl Printer { - /// Creates a new [`Printer`]. - fn new() -> Self { - Self { - printed: Cell::new(false), - } - } - - fn has_printed(&self) -> bool { - self.printed.get() - } -} - -impl Handler for Printer { - fn receive>(&self, error: E) { - eprintln!("{}", error.into()); - self.printed.set(true); - } - - fn has_received(&self) -> bool { - self.printed.get() - } + let datapack = transpile(handler, file_provider, pack_format, script_paths)?; + + tracing::info!("Compiling the source code."); + + Ok(datapack.compile(&CompileOptions::default())) } diff --git a/src/public_helpers.rs b/src/public_helpers.rs deleted file mode 100644 index d4e519a..0000000 --- a/src/public_helpers.rs +++ /dev/null @@ -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 { - 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 { - 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( - printer: &Printer, - file_provider: &F, - pack_format: u8, - script_paths: &[(String, P)], -) -> Result -where - F: FileProvider, - P: AsRef, -{ - let programs = script_paths - .iter() - .map(|(program_identifier, path)| { - let program = parse(printer, file_provider, path.as_ref())?; - - Ok((program_identifier, program)) - }) - .collect::>(); - - 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::>(); - - 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( - printer: &Printer, - file_provider: &F, - pack_format: u8, - script_paths: &[(String, P)], -) -> Result -where - F: FileProvider, - P: AsRef, -{ - let datapack = transpile(printer, file_provider, pack_format, script_paths)?; - - tracing::info!("Compiling the source code."); - - Ok(datapack.compile(&CompileOptions::default())) -} diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index e66a917..0264b38 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -4,7 +4,7 @@ use derive_more::{Deref, DerefMut}; use enum_as_inner::EnumAsInner; use crate::{ - base::Handler, + base::{self, Handler}, lexical::{ token::{Identifier, Keyword, KeywordKind, Numeric, Punctuation, StringLiteral, Token}, token_stream::{Delimited, Delimiter, TokenStream, TokenTree}, @@ -42,7 +42,7 @@ impl<'a> Parser<'a> { &mut self, delimiter: Delimiter, f: impl FnOnce(&mut Self) -> Option, - handler: &impl Handler, + handler: &impl Handler, ) -> Option> { self.current_frame.stop_at_significant(); let raw_token_tree = self @@ -363,7 +363,7 @@ impl<'a> Frame<'a> { /// /// # Errors /// If the next [`Token`] is not an [`Identifier`]. - pub fn parse_identifier(&mut self, handler: &impl Handler) -> Option { + pub fn parse_identifier(&mut self, handler: &impl Handler) -> Option { match self.next_significant_token() { Reading::Atomic(Token::Identifier(ident)) => Some(ident), found => { @@ -397,7 +397,10 @@ impl<'a> Frame<'a> { /// /// # Errors /// If the next [`Token`] is not an [`StringLiteral`]. - pub fn parse_string_literal(&mut self, handler: &impl Handler) -> Option { + pub fn parse_string_literal( + &mut self, + handler: &impl Handler, + ) -> Option { match self.next_significant_token() { Reading::Atomic(Token::StringLiteral(literal)) => Some(literal), found => { @@ -417,7 +420,7 @@ impl<'a> Frame<'a> { pub fn parse_keyword( &mut self, expected: KeywordKind, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match self.next_significant_token() { Reading::Atomic(Token::Keyword(keyword_token)) if keyword_token.keyword == expected => { @@ -441,7 +444,7 @@ impl<'a> Frame<'a> { &mut self, expected: char, skip_insignificant: bool, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match if skip_insignificant { self.next_significant_token() diff --git a/src/syntax/syntax_tree/condition.rs b/src/syntax/syntax_tree/condition.rs index c0bfd99..cadaca4 100644 --- a/src/syntax/syntax_tree/condition.rs +++ b/src/syntax/syntax_tree/condition.rs @@ -7,8 +7,9 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, - DummyHandler, Handler, + VoidHandler, Handler, }, lexical::{ token::{Punctuation, StringLiteral, Token}, @@ -240,7 +241,7 @@ impl SourceElement for Condition { impl<'a> Parser<'a> { /// Parses a [`Condition`]. - pub fn parse_condition(&mut self, handler: &impl Handler) -> Option { + pub fn parse_condition(&mut self, handler: &impl Handler) -> Option { let mut lhs = Condition::Primary(self.parse_primary_condition(handler)?); let mut expressions = VecDeque::new(); @@ -305,7 +306,7 @@ impl<'a> Parser<'a> { /// Parses a [`PrimaryCondition`]. pub fn parse_primary_condition( &mut self, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match self.stop_at_significant() { // prefixed expression @@ -354,7 +355,7 @@ impl<'a> Parser<'a> { /// Parses a [`ParenthesizedCondition`]. pub fn parse_parenthesized_condition( &mut self, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { let token_tree = self.step_into( Delimiter::Parenthesis, @@ -377,11 +378,11 @@ impl<'a> Parser<'a> { self.try_parse(|parser| match parser.next_significant_token() { 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)) } '|' => { - let b = parser.parse_punctuation('|', false, &DummyHandler)?; + let b = parser.parse_punctuation('|', false, &VoidHandler)?; Some(ConditionalBinaryOperator::LogicalOr(punc, b)) } _ => None, diff --git a/src/syntax/syntax_tree/declaration.rs b/src/syntax/syntax_tree/declaration.rs index 5eccd54..0e66178 100644 --- a/src/syntax/syntax_tree/declaration.rs +++ b/src/syntax/syntax_tree/declaration.rs @@ -6,8 +6,9 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, - DummyHandler, Handler, + Handler, VoidHandler, }, lexical::{ token::{Identifier, Keyword, KeywordKind, Punctuation, StringLiteral, Token}, @@ -226,7 +227,7 @@ impl SourceElement for Import { } impl<'a> Parser<'a> { - pub fn parse_annotation(&mut self, handler: &impl Handler) -> Option { + pub fn parse_annotation(&mut self, handler: &impl Handler) -> Option { match self.stop_at_significant() { Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => { // eat the pound sign @@ -280,7 +281,10 @@ impl<'a> Parser<'a> { } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_declaration(&mut self, handler: &impl Handler) -> Option { + pub fn parse_declaration( + &mut self, + handler: &impl Handler, + ) -> Option { match self.stop_at_significant() { Reading::Atomic(Token::Keyword(function_keyword)) if function_keyword.keyword == KeywordKind::Function => @@ -355,7 +359,7 @@ impl<'a> Parser<'a> { self.try_parse(|parser| parser .parse_connected_list( ',', - |parser| parser.parse_identifier(&DummyHandler), + |parser| parser.parse_identifier(&VoidHandler), handler, ) .map(ImportItems::Named)) // , @@ -398,7 +402,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_function(&mut self, handler: &impl Handler) -> Option { + pub fn parse_function(&mut self, handler: &impl Handler) -> Option { if let Reading::Atomic(Token::Keyword(function_keyword)) = self.stop_at_significant() { // eat the function keyword self.forward(); diff --git a/src/syntax/syntax_tree/expression.rs b/src/syntax/syntax_tree/expression.rs index b3d48e9..3eb9e81 100644 --- a/src/syntax/syntax_tree/expression.rs +++ b/src/syntax/syntax_tree/expression.rs @@ -5,6 +5,7 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, Handler, }, @@ -155,12 +156,12 @@ impl LuaCode { impl<'a> Parser<'a> { /// Parses an [`Expression`] - pub fn parse_expression(&mut self, handler: &impl Handler) -> Option { + pub fn parse_expression(&mut self, handler: &impl Handler) -> Option { Some(Expression::Primary(self.parse_primary(handler)?)) } /// Parses an [`Primary`] - pub fn parse_primary(&mut self, handler: &impl Handler) -> Option { + pub fn parse_primary(&mut self, handler: &impl Handler) -> Option { match self.stop_at_significant() { // identifier expression Reading::Atomic(Token::Identifier(identifier)) => { diff --git a/src/syntax/syntax_tree/mod.rs b/src/syntax/syntax_tree/mod.rs index 8fe4489..399e657 100644 --- a/src/syntax/syntax_tree/mod.rs +++ b/src/syntax/syntax_tree/mod.rs @@ -4,8 +4,9 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, - DummyHandler, Handler, + Handler, VoidHandler, }, lexical::{ token::{Punctuation, Token}, @@ -14,7 +15,7 @@ use crate::{ syntax::parser::Reading, }; -use super::{error::Error, parser::Parser}; +use super::parser::Parser; pub mod condition; pub mod declaration; @@ -76,7 +77,7 @@ impl<'a> Parser<'a> { delimiter: Delimiter, separator: char, mut f: impl FnMut(&mut Self) -> Option, - handler: &impl Handler, + handler: &impl Handler, ) -> Option> { fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option { if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| { @@ -162,14 +163,14 @@ impl<'a> Parser<'a> { &mut self, seperator: char, mut f: impl FnMut(&mut Self) -> Option, - _handler: &impl Handler, + _handler: &impl Handler, ) -> Option> { let first = f(self)?; let mut rest = Vec::new(); 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) { rest.push((sep, element)); diff --git a/src/syntax/syntax_tree/program.rs b/src/syntax/syntax_tree/program.rs index 69ee059..8740f7f 100644 --- a/src/syntax/syntax_tree/program.rs +++ b/src/syntax/syntax_tree/program.rs @@ -4,12 +4,14 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, Handler, }, lexical::token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token}, syntax::{ - error::{Error, SyntaxKind, UnexpectedSyntax}, + self, + error::{SyntaxKind, UnexpectedSyntax}, parser::{Parser, Reading}, }, }; @@ -79,7 +81,7 @@ impl Namespace { impl<'a> Parser<'a> { /// Parses a [`ProgramFile`]. #[tracing::instrument(level = "debug", skip_all)] - pub fn parse_program(&mut self, handler: &impl Handler) -> Option { + pub fn parse_program(&mut self, handler: &impl Handler) -> Option { tracing::debug!("Parsing program"); let namespace = match self.stop_at_significant() { @@ -102,10 +104,10 @@ impl<'a> Parser<'a> { }) } unexpected => { - handler.receive(UnexpectedSyntax { + handler.receive(syntax::error::Error::from(UnexpectedSyntax { expected: SyntaxKind::Keyword(KeywordKind::Namespace), found: unexpected.into_token(), - }); + })); None } }?; diff --git a/src/syntax/syntax_tree/statement.rs b/src/syntax/syntax_tree/statement.rs index 5e48f36..435a51d 100644 --- a/src/syntax/syntax_tree/statement.rs +++ b/src/syntax/syntax_tree/statement.rs @@ -7,6 +7,7 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, Handler, }, @@ -14,10 +15,7 @@ use crate::{ token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token}, token_stream::Delimiter, }, - syntax::{ - error::Error, - parser::{Parser, Reading}, - }, + syntax::parser::{Parser, Reading}, }; use self::execute_block::ExecuteBlock; @@ -211,7 +209,7 @@ impl Semicolon { impl<'a> Parser<'a> { /// Parses a [`Block`]. - pub fn parse_block(&mut self, handler: &impl Handler) -> Option { + pub fn parse_block(&mut self, handler: &impl Handler) -> Option { let token_tree = self.step_into( Delimiter::Brace, |parser| { @@ -250,7 +248,7 @@ impl<'a> Parser<'a> { /// Parses a [`Statement`]. #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_statement(&mut self, handler: &impl Handler) -> Option { + pub fn parse_statement(&mut self, handler: &impl Handler) -> Option { match self.stop_at_significant() { // variable declaration Reading::Atomic(Token::CommandLiteral(command)) => { diff --git a/src/syntax/syntax_tree/statement/execute_block.rs b/src/syntax/syntax_tree/statement/execute_block.rs index 86ff1f2..2bc4bfa 100644 --- a/src/syntax/syntax_tree/statement/execute_block.rs +++ b/src/syntax/syntax_tree/statement/execute_block.rs @@ -6,15 +6,17 @@ use getset::Getters; use crate::{ base::{ + self, source_file::{SourceElement, Span}, - DummyHandler, Handler, + VoidHandler, Handler, }, lexical::{ token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token}, token_stream::Delimiter, }, syntax::{ - error::{Error, SyntaxKind, UnexpectedSyntax}, + self, + error::{SyntaxKind, UnexpectedSyntax}, parser::{DelimitedTree, Parser, Reading}, syntax_tree::condition::ParenthesizedCondition, }, @@ -711,7 +713,7 @@ impl<'a> Parser<'a> { /// Parses an [`ExecuteBlock`]. pub fn parse_execute_block_statement( &mut self, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match self.stop_at_significant() { Reading::Atomic(Token::Keyword(if_keyword)) @@ -728,7 +730,7 @@ impl<'a> Parser<'a> { }; 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() { // else statement Reading::Atomic(Token::Keyword(else_keyword)) @@ -775,10 +777,10 @@ impl<'a> Parser<'a> { handler, ), unexpected => { - handler.receive(UnexpectedSyntax { + handler.receive(syntax::error::Error::from(UnexpectedSyntax { expected: SyntaxKind::Punctuation('('), found: unexpected.into_token(), - }); + })); None } }?; @@ -792,10 +794,10 @@ impl<'a> Parser<'a> { // unexpected unexpected => { - handler.receive(UnexpectedSyntax { + handler.receive(syntax::error::Error::from(UnexpectedSyntax { expected: SyntaxKind::ExecuteBlock, found: unexpected.into_token(), - }); + })); None } } @@ -803,7 +805,7 @@ impl<'a> Parser<'a> { fn parse_execute_block_tail( &mut self, - handler: &impl Handler, + handler: &impl Handler, ) -> Option { match self.stop_at_significant() { // nested execute block @@ -827,10 +829,10 @@ impl<'a> Parser<'a> { } unexpected => { - handler.receive(UnexpectedSyntax { + handler.receive(syntax::error::Error::from(UnexpectedSyntax { expected: SyntaxKind::ExecuteBlockTail, found: unexpected.into_token(), - }); + })); None } } diff --git a/src/transpile/lua.rs b/src/transpile/lua.rs index f744728..172ee87 100644 --- a/src/transpile/lua.rs +++ b/src/transpile/lua.rs @@ -5,7 +5,7 @@ mod enabled { use mlua::Lua; use crate::{ - base::{source_file::SourceElement, Handler}, + base::{self, source_file::SourceElement, Handler}, syntax::syntax_tree::expression::LuaCode, transpile::error::{TranspileError, TranspileResult}, }; @@ -16,10 +16,7 @@ mod enabled { /// # Errors /// - If Lua code evaluation is disabled. #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)] - pub fn eval_string( - &self, - handler: &impl Handler, - ) -> TranspileResult { + pub fn eval_string(&self, handler: &impl Handler) -> TranspileResult { tracing::debug!("Evaluating Lua code"); let lua = Lua::new(); diff --git a/src/transpile/mod.rs b/src/transpile/mod.rs index 151641c..0ef8314 100644 --- a/src/transpile/mod.rs +++ b/src/transpile/mod.rs @@ -3,10 +3,15 @@ #[doc(hidden)] #[cfg(feature = "shulkerbox")] pub mod conversions; -pub mod error; +mod error; +#[doc(inline)] +#[allow(clippy::module_name_repetitions)] +pub use error::{TranspileError, TranspileResult}; #[doc(hidden)] pub mod lua; #[cfg(feature = "shulkerbox")] -pub mod transpiler; +mod transpiler; +#[doc(inline)] +pub use transpiler::Transpiler; mod util; diff --git a/src/transpile/transpiler.rs b/src/transpile/transpiler.rs index f3f6ebd..7b4d084 100644 --- a/src/transpile/transpiler.rs +++ b/src/transpile/transpiler.rs @@ -6,7 +6,7 @@ use std::{collections::HashMap, iter, sync::RwLock}; use shulkerbox::datapack::{self, Command, Datapack, Execute}; use crate::{ - base::{source_file::SourceElement, Handler}, + base::{self, source_file::SourceElement, Handler}, syntax::syntax_tree::{ declaration::{Declaration, ImportItems}, expression::{Expression, FunctionCall, Primary}, @@ -64,7 +64,7 @@ impl Transpiler { pub fn transpile( &mut self, programs: &[(Ident, ProgramFile)], - handler: &impl Handler, + handler: &impl Handler, ) -> Result<(), TranspileError> where Ident: AsRef, @@ -107,7 +107,7 @@ impl Transpiler { &mut self, program: &ProgramFile, identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) { let namespace = program.namespace(); @@ -117,12 +117,13 @@ impl Transpiler { } /// Transpiles the given declaration. + #[allow(clippy::needless_pass_by_ref_mut)] fn transpile_declaration( &mut self, declaration: &Declaration, namespace: &Namespace, program_identifier: &str, - _handler: &impl Handler, + _handler: &impl Handler, ) { match declaration { Declaration::Function(function) => { @@ -184,7 +185,7 @@ impl Transpiler { &mut self, name: &str, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult { let program_query = (program_identifier.to_string(), name.to_string()); let alias_query = { @@ -289,7 +290,7 @@ impl Transpiler { &mut self, statements: &[Statement], program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { let mut errors = Vec::new(); let commands = statements @@ -314,7 +315,7 @@ impl Transpiler { &mut self, statement: &Statement, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { match statement { Statement::LiteralCommand(literal_command) => { @@ -381,7 +382,7 @@ impl Transpiler { &mut self, func: &FunctionCall, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult { let identifier = func.identifier().span(); let identifier_name = identifier.str(); @@ -394,7 +395,7 @@ impl Transpiler { &mut self, execute: &ExecuteBlock, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { self.transpile_execute_block_internal(execute, program_identifier, handler) .map(|ex| ex.map(Command::Execute)) @@ -404,7 +405,7 @@ impl Transpiler { &mut self, execute: &ExecuteBlock, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { match execute { ExecuteBlock::HeadTail(head, tail) => { @@ -489,7 +490,7 @@ impl Transpiler { then: Execute, el: Option<&Else>, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { let (_, cond) = cond.clone().dissolve(); let (_, cond, _) = cond.dissolve(); @@ -540,7 +541,7 @@ impl Transpiler { head: &ExecuteBlockHead, tail: Option, program_identifier: &str, - handler: &impl Handler, + handler: &impl Handler, ) -> TranspileResult> { Ok(match head { ExecuteBlockHead::Conditional(cond) => { diff --git a/tests/parsing/main.rs b/tests/parsing/main.rs index a0a5741..3c02106 100644 --- a/tests/parsing/main.rs +++ b/tests/parsing/main.rs @@ -2,7 +2,7 @@ use std::path::Path; use shulkerbox::virtual_fs::{VFile, VFolder}; use shulkerscript::{ - base::source_file::SourceElement, + base::{source_file::SourceElement, PrintHandler}, syntax::syntax_tree::{declaration::Declaration, statement::Statement}, }; @@ -12,7 +12,8 @@ fn parsing_test1() { let mut dir = VFolder::new(); 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!( parsed.namespace().namespace_name().str_content(), @@ -48,5 +49,6 @@ fn parsing_invalid() { let mut dir = VFolder::new(); 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"); } diff --git a/tests/transpiling/main.rs b/tests/transpiling/main.rs index bc4af07..e7fdece 100644 --- a/tests/transpiling/main.rs +++ b/tests/transpiling/main.rs @@ -2,6 +2,7 @@ use shulkerbox::{ datapack::{Command, Condition, Datapack, Execute}, virtual_fs::{VFile, VFolder}, }; +use shulkerscript::base::PrintHandler; #[test] fn transpile_test1() { @@ -9,8 +10,13 @@ fn transpile_test1() { let mut dir = VFolder::new(); dir.add_file("test1.shu", VFile::Text(source.to_string())); - let transpiled = shulkerscript::transpile(&dir, 48, &[("test1".to_string(), "./test1.shu")]) - .expect("Failed to transpile"); + let transpiled = shulkerscript::transpile( + &PrintHandler::default(), + &dir, + 48, + &[("test1".to_string(), "./test1.shu")], + ) + .expect("Failed to transpile"); let expected = { let mut dp = Datapack::new(48);