Add rudamentary compilation
This commit is contained in:
parent
8acf5a75cb
commit
fb851093f0
@ -209,7 +209,7 @@ impl Expression {
|
|||||||
Expression::Literal(literal) => {
|
Expression::Literal(literal) => {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
let reg = scope.register_counter.next();
|
let reg = scope.register_counter.next();
|
||||||
instructions.push(Instruction::GetGlobal(
|
instructions.push(Instruction::LoadK(
|
||||||
reg,
|
reg,
|
||||||
state.get_constant(&match literal {
|
state.get_constant(&match literal {
|
||||||
Literal::Number(value) => Constant::Number(value.to_bits()),
|
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::{
|
use crate::{
|
||||||
ast::{Block, Function},
|
ast::{Block, Function, LuaNumber},
|
||||||
token_stream::{
|
token_stream::{
|
||||||
TokenStream,
|
TokenStream,
|
||||||
lexer::{Token, tokenize},
|
lexer::{Token, tokenize},
|
||||||
},
|
},
|
||||||
|
vm::{RustFunction, VirtualMachine},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
@ -15,6 +16,22 @@ mod vm;
|
|||||||
|
|
||||||
static TEST: &str = include_str!("../examples/test.lua");
|
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() {
|
fn main() {
|
||||||
let file_path = PathBuf::from("../examples/test.lua");
|
let file_path = PathBuf::from("../examples/test.lua");
|
||||||
let tokens = tokenize(TEST).unwrap();
|
let tokens = tokenize(TEST).unwrap();
|
||||||
@ -33,6 +50,30 @@ fn main() {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
dbg!(&constants);
|
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);
|
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 struct Environment {
|
||||||
pub globals: HashMap<Constant, Value>,
|
pub globals: HashMap<Constant, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Number(VMNumber),
|
Number(VMNumber),
|
||||||
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
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 {
|
pub trait RustFunction: Debug {
|
||||||
fn execute(&self, parameters: Vec<Value>) -> Vec<Value>;
|
fn execute(&self, parameters: Vec<Value>) -> Vec<Value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClosureRunner {
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VirtualMachine {
|
||||||
pub environment: Rc<RefCell<Environment>>,
|
pub environment: Rc<RefCell<Environment>>,
|
||||||
pub constants: Vec<Constant>,
|
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