117 lines
2.7 KiB
Rust
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,
|
|
})
|
|
}
|