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 mod base;
|
2024-03-28 01:17:17 +01:00
|
|
|
pub mod compile;
|
2024-03-27 19:27:11 +01:00
|
|
|
pub mod lexical;
|
2024-03-27 21:39:56 +01:00
|
|
|
pub mod syntax;
|
2024-03-27 19:27:11 +01:00
|
|
|
|
|
|
|
use std::{cell::Cell, fmt::Display, path::PathBuf};
|
|
|
|
|
|
|
|
use base::{source_file::SourceFile, Handler, Result};
|
2024-03-28 01:17:17 +01:00
|
|
|
use compile::compiler::Compiler;
|
|
|
|
use shulkerbox::{util::compile::CompileOptions, virtual_fs::VFolder};
|
2024-03-27 19:27:11 +01:00
|
|
|
|
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
|
|
|
|
|
|
|
/// Compiles the given source code.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
/// - If an error occurs while reading the file.
|
2024-03-28 01:17:17 +01:00
|
|
|
pub fn compile(path: PathBuf) -> 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);
|
|
|
|
|
2024-03-29 18:26:43 +01:00
|
|
|
// 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);
|
2024-03-28 01:17:17 +01:00
|
|
|
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-03-29 18:26:43 +01:00
|
|
|
// println!("program: {program:#?}");
|
2024-03-28 01:17:17 +01:00
|
|
|
|
|
|
|
let mut compiler = Compiler::new();
|
|
|
|
let datapack = compiler.compile(&program, &printer)?;
|
2024-03-27 21:39:56 +01:00
|
|
|
|
|
|
|
if printer.has_printed() {
|
|
|
|
return Err(Error::Other(
|
|
|
|
"An error occurred while parsing the source code.",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-03-28 01:17:17 +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);
|
|
|
|
}
|
|
|
|
}
|