diff --git a/src/compile.rs b/src/compile.rs index 39da5b7..580f1f9 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,14 +1,42 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use crate::{ ast::{AccessModifier, Block, Expression, Literal, Statement}, - vm::{Constant, VMNumber}, + vm::{Constant, Instruction, VMNumber}, }; -struct State { +pub struct State { pub constants: Vec, } +impl State { + pub fn get_constant(&self, value: &Constant) -> u32 { + self.constants + .iter() + .enumerate() + .find(|(i, c)| *c == value) + .unwrap() + .0 as u32 + } +} + +#[derive(Clone, Debug, Default)] +pub struct Scope { + pub locals: HashMap, + pub register_counter: LocalCounter, +} + +#[derive(Clone, Debug, Default)] +pub struct LocalCounter(u16); + +impl LocalCounter { + pub fn next(&mut self) -> u16 { + let temp = self.0; + self.0 += 1; + temp + } +} + impl Block { pub fn find_constants(&self) -> HashSet { let mut constants = HashSet::new(); @@ -19,6 +47,16 @@ impl Block { constants } + + pub fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { + let mut instructions = Vec::new(); + + for statement in &self.statements { + instructions.extend(statement.kind.compile(state, &mut scope.clone())); + } + + instructions + } } impl Statement { @@ -41,6 +79,32 @@ impl Statement { } } } + + pub fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { + let mut instructions = Vec::new(); + + match self { + Statement::Assignment(access_modifier, name, expr) => { + let (instr, regs) = expr.kind.compile(state, scope, 1); + instructions.extend(instr); + match access_modifier { + AccessModifier::Local => { + let reg = scope.register_counter.next(); + scope.locals.insert(name.kind.clone(), reg); + instructions.push(Instruction::Move(reg, *regs.get(0).unwrap())); + } + AccessModifier::Global => { + let global = state.get_constant(&Constant::String(name.kind.clone())); + instructions.push(Instruction::SetGlobal(*regs.get(0).unwrap(), global)); + } + } + } + Statement::Return(node) => todo!(), + Statement::If(node, block) => todo!(), + } + + instructions + } } impl Expression { @@ -71,4 +135,69 @@ impl Expression { }, } } + + pub fn compile( + &self, + state: &mut State, + scope: &mut Scope, + expected_values: usize, + ) -> (Vec, Vec) { + match self { + Expression::ValueRef(name) => { + if let Some(local) = scope.locals.get(name) { + (Vec::new(), vec![*local]) + } else { + let mut instructions = Vec::new(); + let reg = scope.register_counter.next(); + instructions.push(Instruction::GetGlobal( + reg, + state.get_constant(&Constant::String(name.clone())), + )); + (instructions, vec![reg]) + } + } + Expression::BinOp(binary_operator, node, node1) => todo!(), + Expression::FunctionDefinition(nodes, block) => todo!(), + Expression::FunctionCall(expr, params) => { + let function_register = scope.register_counter.next(); + + let mut param_regs = Vec::new(); + for _ in 0..params.kind.0.len() { + param_regs.push(scope.register_counter.next()); + } + let first_param_reg = param_regs.first().unwrap(); + let last_param_reg = param_regs.last().unwrap(); + + let mut return_regs = Vec::new(); + for i in 0..expected_values { + let return_reg = i as u16 + function_register; + if return_reg > *last_param_reg { + return_regs.push(scope.register_counter.next()); + } else { + return_regs.push(return_reg); + } + } + + let mut instructions = Vec::new(); + let (instr, registers) = expr.kind.compile(state, scope, 1); + instructions.extend(instr); + instructions.push(Instruction::Move( + function_register, + *registers.first().unwrap(), + )); + + for (i, param) in params.kind.0.iter().enumerate() { + let (instr, registers) = param.kind.compile(state, scope, 1); + instructions.extend(instr); + instructions.push(Instruction::Move( + *first_param_reg + i as u16, + *registers.first().unwrap(), + )); + } + + (instructions, return_regs) + } + Expression::Literal(literal) => todo!(), + } + } } diff --git a/src/main.rs b/src/main.rs index 9e0d44c..e35f89f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,9 @@ fn main() { dbg!(&chunk); - let constants = chunk.find_constants(); + let constants = chunk.find_constants().into_iter().collect::>(); dbg!(&constants); + + let instructions = chunk.compile(&mut compile::State { constants }, &mut Default::default()); + dbg!(&instructions); } diff --git a/src/vm.rs b/src/vm.rs index a817cce..0127cd5 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -21,3 +21,18 @@ impl Debug for Constant { } } } + +#[derive(Debug, Clone, Copy)] +pub enum Instruction { + /// R(A) := R(B) + Move(u16, u16), + /// R(A) := K(Bx) + LoadK(u16, u32), + /// G[K(Bx)] := R(A) + SetGlobal(u16, u32), + /// R(A) := G[K(Bx)] + GetGlobal(u16, u32), + /// [func] [params.len()] [ret_regs.len()] + /// R(A), ... R(A+C-2) := R(A)(R(A+1), ... R(A+B-1)) + Call(u16, u16, u16), +}