Add rudamentary compilation

This commit is contained in:
Sofia 2026-03-14 22:21:06 +02:00
parent 8acf5a75cb
commit fb851093f0
3 changed files with 196 additions and 7 deletions

View File

@ -209,7 +209,7 @@ impl Expression {
Expression::Literal(literal) => {
let mut instructions = Vec::new();
let reg = scope.register_counter.next();
instructions.push(Instruction::GetGlobal(
instructions.push(Instruction::LoadK(
reg,
state.get_constant(&match literal {
Literal::Number(value) => Constant::Number(value.to_bits()),

View File

@ -1,11 +1,12 @@
use std::path::PathBuf;
use std::{cell::RefCell, path::PathBuf, rc::Rc};
use crate::{
ast::{Block, Function},
ast::{Block, Function, LuaNumber},
token_stream::{
TokenStream,
lexer::{Token, tokenize},
},
vm::{RustFunction, VirtualMachine},
};
mod ast;
@ -15,6 +16,22 @@ mod vm;
static TEST: &str = include_str!("../examples/test.lua");
#[derive(Debug)]
pub struct Max;
impl RustFunction for Max {
fn execute(&self, parameters: Vec<vm::Value>) -> Vec<vm::Value> {
let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil);
let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil);
match lhs.lt(&rhs) {
vm::Value::Number(value) => {
let res = LuaNumber::from_bits(value);
vec![if res > 0. { rhs } else { lhs }]
}
_ => vec![vm::Value::Nil],
}
}
}
fn main() {
let file_path = PathBuf::from("../examples/test.lua");
let tokens = tokenize(TEST).unwrap();
@ -33,6 +50,30 @@ fn main() {
.collect::<Vec<_>>();
dbg!(&constants);
let instructions = chunk.compile(&mut compile::State { constants }, &mut Default::default());
let instructions = chunk.compile(
&mut compile::State {
constants: constants.clone(),
},
&mut Default::default(),
);
dbg!(&instructions);
let mut vm = VirtualMachine {
environment: Default::default(),
constants,
prototypes: Default::default(),
};
vm.prototypes.insert(0, instructions);
vm.environment.borrow_mut().globals.insert(
vm::Constant::String("max".to_owned()),
vm::Value::RustFunction(Rc::new(RefCell::new(Max))),
);
let closure = vm.create_closure(0);
let mut run = closure.run();
while run.next() {}
dbg!(vm.environment.borrow());
}

154
src/vm.rs
View File

@ -49,22 +49,170 @@ impl Debug for Instruction {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct Environment {
pub globals: HashMap<Constant, Value>,
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub enum Value {
Number(VMNumber),
RustFunction(Rc<RefCell<dyn RustFunction>>),
Function(Closure),
Nil,
}
impl Value {
pub fn add(&self, other: &Value) -> Value {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) + LuaNumber::from_bits(*rhs);
Value::Number(res.to_bits())
}
_ => Value::Nil,
}
}
pub fn lt(&self, other: &Value) -> Value {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) < LuaNumber::from_bits(*rhs);
Value::Number((res as u64 as f64).to_bits())
}
_ => Value::Nil,
}
}
}
impl Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Number(arg0) => f
.debug_tuple("Number")
.field(&LuaNumber::from_bits(*arg0))
.finish(),
Self::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
Self::Function(arg0) => f.debug_tuple("Function").field(arg0).finish(),
Self::Nil => write!(f, "Nil"),
}
}
}
pub trait RustFunction: Debug {
fn execute(&self, parameters: Vec<Value>) -> Vec<Value>;
}
pub struct ClosureRunner {
#[derive(Debug, Clone)]
pub struct VirtualMachine {
pub environment: Rc<RefCell<Environment>>,
pub constants: Vec<Constant>,
pub prototypes: HashMap<u32, Vec<Instruction>>,
}
impl VirtualMachine {
pub fn create_closure(&self, prototype: u32) -> Closure {
Closure {
vm: self.clone(),
prototype,
environment: self.environment.clone(),
upvalues: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct Closure {
pub vm: VirtualMachine,
pub prototype: u32,
pub environment: Rc<RefCell<Environment>>,
pub upvalues: HashMap<u16, Rc<RefCell<Value>>>,
}
impl Closure {
pub fn run(&self) -> ClosureRunner {
ClosureRunner {
closure: self.clone(),
program_counter: 0,
stack: HashMap::new(),
}
}
}
pub struct ClosureRunner {
pub closure: Closure,
pub program_counter: usize,
pub stack: HashMap<u16, Value>,
}
impl ClosureRunner {
pub fn next(&mut self) -> bool {
let instructions = self
.closure
.vm
.prototypes
.get(&self.closure.prototype)
.unwrap();
let constants = &self.closure.vm.constants;
if let Some(instr) = instructions.get(self.program_counter) {
match instr {
Instruction::Move(a, b) => {
self.stack.insert(*a, self.stack.get(b).unwrap().clone());
}
Instruction::LoadK(reg, constant) => {
self.stack.insert(
*reg,
match constants.get(*constant as usize).unwrap() {
Constant::String(_) => todo!(),
Constant::Number(value) => Value::Number(*value),
},
);
}
Instruction::SetGlobal(reg, global) => {
self.closure.environment.borrow_mut().globals.insert(
constants.get(*global as usize).unwrap().clone(),
self.stack.get(reg).unwrap().clone(),
);
}
Instruction::GetGlobal(reg, global) => {
if let Some(global) = self
.closure
.environment
.borrow()
.globals
.get(constants.get(*global as usize).unwrap())
{
self.stack.insert(*reg, global.clone());
} else {
todo!("Global not found: {:?}", constants.get(*global as usize))
}
}
Instruction::Call(func_reg, param_len, ret_len) => {
match self.stack.get(func_reg).unwrap_or(&Value::Nil) {
Value::RustFunction(func) => {
let mut params = Vec::new();
for i in 0..*param_len {
params.push(self.stack.get(&(func_reg + i + 1)).unwrap().clone());
}
let ret_values = func.borrow_mut().execute(params);
for i in 0..=(*ret_len - 2) {
self.stack.insert(
*func_reg + i,
ret_values.get(i as usize).cloned().unwrap_or(Value::Nil),
);
}
}
Value::Function(_) => todo!(),
_ => panic!(),
}
}
};
self.program_counter += 1;
true
} else {
false
}
}
}