Add rudamentary compilation
This commit is contained in:
parent
8acf5a75cb
commit
fb851093f0
@ -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()),
|
||||
|
||||
47
src/main.rs
47
src/main.rs
@ -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
154
src/vm.rs
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user