Add some compilation
This commit is contained in:
parent
d74a887c4e
commit
50f6459abe
135
src/compile.rs
135
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<Constant>,
|
||||
}
|
||||
|
||||
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<String, u16>,
|
||||
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<Constant> {
|
||||
let mut constants = HashSet::new();
|
||||
@ -19,6 +47,16 @@ impl Block {
|
||||
|
||||
constants
|
||||
}
|
||||
|
||||
pub fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec<Instruction> {
|
||||
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<Instruction> {
|
||||
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<Instruction>, Vec<u16>) {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,9 @@ fn main() {
|
||||
|
||||
dbg!(&chunk);
|
||||
|
||||
let constants = chunk.find_constants();
|
||||
let constants = chunk.find_constants().into_iter().collect::<Vec<_>>();
|
||||
dbg!(&constants);
|
||||
|
||||
let instructions = chunk.compile(&mut compile::State { constants }, &mut Default::default());
|
||||
dbg!(&instructions);
|
||||
}
|
||||
|
||||
15
src/vm.rs
15
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),
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user