ferrite-lua/src/lib.rs
2026-03-17 21:56:42 +02:00

117 lines
2.7 KiB
Rust

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<vm::Instruction>,
pub state: compile::State,
pub constants: Vec<vm::Constant>,
}
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<CompilationUnit, CompilationError> {
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::<Block>()?;
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::<Vec<_>>();
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,
})
}