use std::{fmt::Debug, path::PathBuf}; use thiserror::Error; use crate::{ ast::Block, token_stream::{ TokenStream, TokenStreamError, lexer::{Error as TokenizerError, Token, tokenize}, }, vm::{ClosureRunner, VirtualMachine}, }; mod ast; mod compile; mod token_stream; pub mod vm; #[derive(Error, Debug)] pub enum CompilationError { #[error(transparent)] TokenStreamError(#[from] TokenStreamError), #[error(transparent)] TokenizationError(#[from] TokenizerError), } #[derive(Clone)] pub struct CompilationUnit { pub instructions: Vec, pub state: compile::State, pub constants: Vec, } impl Debug for CompilationUnit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("CompilationUnit") .field("instructions", &self.instructions) .field("state", &self.state) .field("constants", &self.constants) .finish() } } impl CompilationUnit { pub fn with_virtual_machine<'a>(&self, vm: &'a mut VirtualMachine) -> ExecutionUnit<'a> { let chunk_id = vm.new_prototype(self.instructions.clone()); for prototype in &self.state.prototypes { vm.new_prototype(prototype.clone()); } vm.constants = self.constants.clone(); ExecutionUnit { chunk_id, vm } } } pub struct ExecutionUnit<'a> { chunk_id: u32, vm: &'a mut VirtualMachine, } impl<'a> ExecutionUnit<'a> { pub fn execute(self) -> ClosureRunner { let closure = self.vm.create_closure(self.chunk_id); closure.run(Vec::new()) } } pub fn compile( text: &str, unit: Option<&CompilationUnit>, ) -> Result { let file_path = PathBuf::from("../examples/test.lua"); let tokens = tokenize(text)?; let mut stream = TokenStream::from(&file_path, &tokens); // dbg!(&tokens); let chunk = stream.parse::()?; stream.expect(Token::Eof)?; // dbg!(&chunk); let constants = chunk .find_constants( &mut Default::default(), if let Some(unit) = unit { unit.constants.clone() } else { Vec::new() }, ) .into_iter() .collect::>(); let mut state = compile::State { constants: constants.clone(), prototypes: if let Some(unit) = unit { unit.state.prototypes.clone() } else { Vec::new() }, }; let mut scope = Default::default(); let instructions = chunk.compile(&mut state, &mut scope); // dbg!(&instructions); // dbg!(&constants); Ok(CompilationUnit { instructions, state, constants, }) }