Add some compilation

This commit is contained in:
Sofia 2026-03-14 19:24:05 +02:00
parent d74a887c4e
commit 50f6459abe
3 changed files with 151 additions and 4 deletions

View File

@ -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!(),
}
}
}

View File

@ -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);
}

View File

@ -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),
}