shulkerscript-lang/src/lib.rs

190 lines
5.0 KiB
Rust
Raw Normal View History

2024-03-27 19:27:11 +01:00
//! The `ShulkerScript` language.
//!
//! `ShulkerScript` is a simple, imperative scripting language for creating Minecraft data packs.
#![deny(
missing_debug_implementations,
missing_copy_implementations,
clippy::nursery,
rustdoc::broken_intra_doc_links,
clippy::missing_errors_doc
)]
2024-03-27 21:39:56 +01:00
#![warn(missing_docs, clippy::all, clippy::pedantic)]
2024-03-27 19:27:11 +01:00
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
pub use shulkerbox;
2024-03-27 19:27:11 +01:00
pub mod base;
pub mod lexical;
2024-03-27 21:39:56 +01:00
pub mod syntax;
pub mod transpile;
2024-03-27 19:27:11 +01:00
2024-04-01 20:42:38 +02:00
use std::{cell::Cell, fmt::Display, path::Path};
2024-03-27 19:27:11 +01:00
use base::{source_file::SourceFile, Handler, Result};
2024-04-01 20:42:38 +02:00
use syntax::syntax_tree::program::Program;
#[cfg(feature = "shulkerbox")]
use transpile::transpiler::Transpiler;
2024-03-27 19:27:11 +01:00
2024-04-03 00:45:34 +02:00
#[cfg(feature = "shulkerbox")]
use shulkerbox::{datapack::Datapack, util::compile::CompileOptions, virtual_fs::VFolder};
2024-03-27 21:39:56 +01:00
use crate::{base::Error, lexical::token_stream::TokenStream, syntax::parser::Parser};
2024-03-27 19:27:11 +01:00
2024-04-01 20:42:38 +02:00
/// Converts the given source code to tokens.
///
/// # Errors
/// - If an error occurs while reading the file.
pub fn tokenize(path: &Path) -> Result<TokenStream> {
let source_file = SourceFile::load(path)?;
let printer = Printer::new();
Ok(TokenStream::tokenize(&source_file, &printer))
}
/// Parses the given source code.
///
/// # Errors
/// - If an error occurs while reading the file.
/// - If an error occurs while parsing the source code.
pub fn parse(path: &Path) -> Result<Program> {
let source_file = SourceFile::load(path)?;
let printer = Printer::new();
let tokens = TokenStream::tokenize(&source_file, &printer);
if printer.has_printed() {
return Err(Error::Other(
"An error occurred while tokenizing the source code.",
));
}
let mut parser = Parser::new(&tokens);
let program = parser.parse_program(&printer).ok_or(Error::Other(
"An error occured while parsing the source code.",
))?;
2024-04-03 00:45:34 +02:00
if printer.has_printed() {
return Err(Error::Other(
"An error occurred while parsing the source code.",
));
}
2024-04-01 20:42:38 +02:00
Ok(program)
}
2024-04-03 00:45:34 +02:00
/// Transpiles the given source code into a shulkerbox [`Datapack`].
///
/// # 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.
#[cfg(feature = "shulkerbox")]
pub fn transpile(path: &Path) -> Result<Datapack> {
let source_file = SourceFile::load(path)?;
let printer = Printer::new();
let tokens = TokenStream::tokenize(&source_file, &printer);
if printer.has_printed() {
return Err(Error::Other(
"An error occurred while tokenizing the source code.",
));
}
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.",
));
}
let mut transpiler = Transpiler::new("shulkerscript-pack", 27);
transpiler.transpile(&program, &printer)?;
let datapack = transpiler.into_datapack();
2024-04-03 00:45:34 +02:00
Ok(datapack)
}
2024-03-27 19:27:11 +01:00
/// Compiles the given source code.
///
/// # Errors
/// - If an error occurs while reading the file.
2024-04-03 00:45:34 +02:00
/// - If an error occurs while parsing the source code.
/// - If an error occurs while transpiling the source code.
#[cfg(feature = "shulkerbox")]
2024-04-01 20:42:38 +02:00
pub fn compile(path: &Path) -> Result<VFolder> {
2024-03-27 19:27:11 +01:00
let source_file = SourceFile::load(path)?;
let printer = Printer::new();
let tokens = TokenStream::tokenize(&source_file, &printer);
// println!("tokens: {tokens:#?}");
2024-03-27 19:27:11 +01:00
if printer.has_printed() {
return Err(Error::Other(
"An error occurred while tokenizing the source code.",
));
}
2024-03-27 21:39:56 +01:00
let mut parser = Parser::new(&tokens);
let program = parser.parse_program(&printer).ok_or(Error::Other(
2024-03-27 21:39:56 +01:00
"An error occured while parsing the source code.",
))?;
2024-04-03 00:45:34 +02:00
if printer.has_printed() {
return Err(Error::Other(
"An error occurred while parsing the source code.",
));
}
// println!("program: {program:#?}");
let mut transpiler = Transpiler::new("shulkerscript-pack", 27);
transpiler.transpile(&program, &printer)?;
let datapack = transpiler.into_datapack();
2024-03-27 21:39:56 +01:00
2024-04-03 00:45:34 +02:00
// println!("datapack: {datapack:#?}");
2024-03-27 21:39:56 +01:00
if printer.has_printed() {
return Err(Error::Other(
2024-04-03 00:45:34 +02:00
"An error occurred while transpiling the source code.",
2024-03-27 21:39:56 +01:00
));
}
Ok(datapack.compile(&CompileOptions::default()))
2024-03-27 19:27:11 +01:00
}
struct Printer {
printed: Cell<bool>,
}
impl Printer {
/// Creates a new [`Printer`].
fn new() -> Self {
Self {
printed: Cell::new(false),
}
}
fn has_printed(&self) -> bool {
self.printed.get()
}
}
impl<E: Display> Handler<E> for Printer {
fn receive(&self, error: E) {
eprintln!("{error}");
self.printed.set(true);
}
}