forgot to commit these
This commit is contained in:
@@ -0,0 +1,610 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
backend::dsa::registers::Register,
|
||||
model::{CompilerError, Expression},
|
||||
};
|
||||
|
||||
pub struct CodeGen {
|
||||
// For building the final program
|
||||
program: InsBlock,
|
||||
|
||||
// For generating temporary blocks
|
||||
label_counter: usize,
|
||||
stack_offset: i32,
|
||||
}
|
||||
|
||||
impl CodeGen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
program: InsBlock::new(),
|
||||
label_counter: 0,
|
||||
stack_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit directly to program (for top-level constructs)
|
||||
pub fn emit(&mut self, instr: Instruction) {
|
||||
self.program.push(instr);
|
||||
}
|
||||
|
||||
/// Emit a block to program
|
||||
pub fn emit_block(&mut self, block: InsBlock) {
|
||||
self.program.append(block);
|
||||
}
|
||||
|
||||
/// Build expression (returns block for composition)
|
||||
pub fn build_expr(&mut self, expr: &Expression) -> Result<InsBlock, CompilerError> {
|
||||
// ... returns InstrBlock
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get final output
|
||||
pub fn finish(mut self) -> String {
|
||||
// Optimize before final output
|
||||
// self.program.remove_dead_code();
|
||||
// self.program.optimize_peephole();
|
||||
|
||||
self.program
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InsBlock {
|
||||
instructions: Vec<Instruction>,
|
||||
}
|
||||
|
||||
impl InsBlock {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
instructions: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, instr: Instruction) {
|
||||
self.instructions.push(instr);
|
||||
}
|
||||
|
||||
pub fn append(&mut self, mut other: Self) {
|
||||
self.instructions.append(&mut other.instructions);
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, instrs: impl IntoIterator<Item = Instruction>) {
|
||||
self.instructions.extend(instrs);
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.instructions.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.instructions.len()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Instruction> {
|
||||
self.instructions.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Instruction {
|
||||
// Labels and comments
|
||||
Label(Label),
|
||||
Comment(String),
|
||||
|
||||
// Data movement
|
||||
Mov {
|
||||
src: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Movs {
|
||||
src: Register,
|
||||
dest: Register,
|
||||
},
|
||||
|
||||
// Memory operations
|
||||
Ldb {
|
||||
addr: MemOperand,
|
||||
dest: Register,
|
||||
},
|
||||
Ldh {
|
||||
addr: MemOperand,
|
||||
dest: Register,
|
||||
},
|
||||
Ldw {
|
||||
addr: MemOperand,
|
||||
dest: Register,
|
||||
},
|
||||
Stb {
|
||||
src: Register,
|
||||
addr: MemOperand,
|
||||
},
|
||||
Sth {
|
||||
src: Register,
|
||||
addr: MemOperand,
|
||||
},
|
||||
Stw {
|
||||
src: Register,
|
||||
addr: MemOperand,
|
||||
},
|
||||
|
||||
// Immediate loads
|
||||
Lli {
|
||||
imm: Imm,
|
||||
dest: Register,
|
||||
},
|
||||
Lui {
|
||||
imm: Imm,
|
||||
dest: Register,
|
||||
},
|
||||
|
||||
// Arithmetic
|
||||
Add {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Sub {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
IAdd {
|
||||
src: Register,
|
||||
imm: Imm,
|
||||
dest: Option<Register>,
|
||||
},
|
||||
ISub {
|
||||
src: Register,
|
||||
imm: Imm,
|
||||
dest: Option<Register>,
|
||||
},
|
||||
Inc {
|
||||
reg: Register,
|
||||
},
|
||||
Dec {
|
||||
reg: Register,
|
||||
},
|
||||
|
||||
// Bitwise
|
||||
And {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Or {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Xor {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Not {
|
||||
src: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Nand {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Nor {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
Xnor {
|
||||
src1: Register,
|
||||
src2: Register,
|
||||
dest: Register,
|
||||
},
|
||||
|
||||
// Shifts
|
||||
Shl {
|
||||
src1: Register,
|
||||
r_shamt: Register,
|
||||
i_shamt: u16,
|
||||
dest: Register,
|
||||
},
|
||||
Shr {
|
||||
src1: Register,
|
||||
rsh: Register,
|
||||
ish: u16,
|
||||
dest: Register,
|
||||
},
|
||||
|
||||
// Comparison
|
||||
Cmp {
|
||||
reg1: Register,
|
||||
reg2: Register,
|
||||
},
|
||||
|
||||
// Jumps
|
||||
Jmp {
|
||||
target: Label,
|
||||
},
|
||||
Jeq {
|
||||
target: Label,
|
||||
},
|
||||
Jne {
|
||||
target: Label,
|
||||
},
|
||||
Jgt {
|
||||
target: Label,
|
||||
},
|
||||
Jge {
|
||||
target: Label,
|
||||
},
|
||||
Jlt {
|
||||
target: Label,
|
||||
},
|
||||
Jle {
|
||||
target: Label,
|
||||
},
|
||||
|
||||
// Stack
|
||||
Push {
|
||||
reg: Register,
|
||||
},
|
||||
Pop {
|
||||
reg: Register,
|
||||
},
|
||||
|
||||
// Function calls
|
||||
Call {
|
||||
target: String,
|
||||
}, // namespace::function
|
||||
Return,
|
||||
|
||||
// System
|
||||
Hlt,
|
||||
Nop,
|
||||
Int {
|
||||
code: u8,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for Instruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Label(l) => write!(f, "{}:", l),
|
||||
Self::Comment(c) => write!(f, "; {}", c),
|
||||
|
||||
Self::Mov { src, dest } => write!(f, " mov {}, {}", src, dest),
|
||||
Self::Movs { src, dest } => write!(f, " movs {}, {}", src, dest),
|
||||
|
||||
Self::Ldb { addr, dest } => {
|
||||
write!(f, " ldb {}, {}", format_mem_operand(addr), dest)
|
||||
}
|
||||
Self::Ldh { addr, dest } => {
|
||||
write!(f, " ldh {}, {}", format_mem_operand(addr), dest)
|
||||
}
|
||||
Self::Ldw { addr, dest } => {
|
||||
write!(f, " ldw {}, {}", format_mem_operand(addr), dest)
|
||||
}
|
||||
// Self::Ldbs { addr, dest } => {
|
||||
// write!(f, " ldbs {}, {}", format_mem_operand(addr), dest)
|
||||
// }
|
||||
// Self::Ldhs { addr, dest } => {
|
||||
// write!(f, " ldhs {}, {}", format_mem_operand(addr), dest)
|
||||
// }
|
||||
// Self::Ldws { addr, dest } => {
|
||||
// write!(f, " ldws {}, {}", format_mem_operand(addr), dest)
|
||||
// }
|
||||
Self::Stb { src, addr } => {
|
||||
write!(f, " stb {}, {}", src, format_mem_operand(addr))
|
||||
}
|
||||
Self::Sth { src, addr } => {
|
||||
write!(f, " sth {}, {}", src, format_mem_operand(addr))
|
||||
}
|
||||
Self::Stw { src, addr } => {
|
||||
write!(f, " stw {}, {}", src, format_mem_operand(addr))
|
||||
}
|
||||
|
||||
Self::Lli { imm, dest } => write!(f, " lli {}, {}", imm, dest),
|
||||
Self::Lui { imm, dest } => write!(f, " lui {}, {}", imm, dest),
|
||||
|
||||
// arithmetic
|
||||
Self::Add { src1, src2, dest } => {
|
||||
write!(f, " add {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Sub { src1, src2, dest } => {
|
||||
write!(f, " sub {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::And { src1, src2, dest } => {
|
||||
write!(f, " and {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Or { src1, src2, dest } => {
|
||||
write!(f, " or {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Nand { src1, src2, dest } => {
|
||||
write!(f, " nand {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Xor { src1, src2, dest } => {
|
||||
write!(f, " xor {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Nor { src1, src2, dest } => {
|
||||
write!(f, " nor {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::Not { src, dest } => {
|
||||
write!(f, " not {} {}", src, dest)
|
||||
}
|
||||
Self::Xnor { src1, src2, dest } => {
|
||||
write!(f, " xnor {}, {}, {}", src1, src2, dest)
|
||||
}
|
||||
Self::IAdd { src, imm, dest } => {
|
||||
if let Some(d) = dest {
|
||||
write!(f, " iadd {}, {}, {}", src, imm, d)
|
||||
} else {
|
||||
write!(f, " iadd {}, {}", src, imm)
|
||||
}
|
||||
}
|
||||
Self::ISub { src, imm, dest } => {
|
||||
if let Some(d) = dest {
|
||||
write!(f, " isub {}, {}, {}", src, imm, d)
|
||||
} else {
|
||||
write!(f, " isub {}, {}", src, imm)
|
||||
}
|
||||
}
|
||||
|
||||
// shift instructions
|
||||
Self::Shl {
|
||||
src1,
|
||||
r_shamt,
|
||||
i_shamt,
|
||||
dest,
|
||||
} => {
|
||||
write!(f, " shl {}, {}, {}, {}", src1, r_shamt, i_shamt, dest)
|
||||
}
|
||||
Self::Shr {
|
||||
src1,
|
||||
rsh: r_shamt,
|
||||
ish: i_shamt,
|
||||
dest,
|
||||
} => {
|
||||
write!(f, " shl {}, {}, {}, {}", src1, r_shamt, i_shamt, dest)
|
||||
}
|
||||
|
||||
// increment instructions
|
||||
Self::Inc { reg } => write!(f, " inc {}", reg),
|
||||
Self::Dec { reg } => write!(f, " dec {}", reg),
|
||||
|
||||
Self::Cmp { reg1, reg2 } => write!(f, " cmp {}, {}", reg1, reg2),
|
||||
|
||||
// jump instructions
|
||||
Self::Jmp { target } => write!(f, " jmp {}", target),
|
||||
Self::Jeq { target } => write!(f, " jeq {}", target),
|
||||
Self::Jne { target } => write!(f, " jne {}", target),
|
||||
Self::Jgt { target } => write!(f, " jgt {}", target),
|
||||
Self::Jge { target } => write!(f, " jge {}", target),
|
||||
Self::Jlt { target } => write!(f, " jlt {}", target),
|
||||
Self::Jle { target } => write!(f, " jle {}", target),
|
||||
|
||||
// stack pseudoinstructions
|
||||
Self::Push { reg } => write!(f, " push {}", reg),
|
||||
Self::Pop { reg } => write!(f, " pop {}", reg),
|
||||
|
||||
// call & return pseudoinstructions
|
||||
Self::Call { target } => write!(f, " call {}", target),
|
||||
Self::Return => write!(f, " return"),
|
||||
|
||||
// misc instructions
|
||||
Self::Int { code } => write!(f, " int {}", code),
|
||||
Self::Hlt => write!(f, " hlt"),
|
||||
Self::Nop => write!(f, " nop"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
// Movement
|
||||
pub fn mov(src: Register, dest: Register) -> Self {
|
||||
Self::Mov { src, dest }
|
||||
}
|
||||
|
||||
// Memory loads
|
||||
pub fn ldw_reg(base: Register, dest: Register) -> Self {
|
||||
Self::Ldw {
|
||||
addr: MemOperand::RegIndirect(base),
|
||||
dest,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ldw_reg_offset(base: Register, offset: i32, dest: Register) -> Self {
|
||||
Self::Ldw {
|
||||
addr: MemOperand::RegOffset(base, offset),
|
||||
dest,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ldw_label(label: impl Into<Label>, dest: Register) -> Self {
|
||||
Self::Ldw {
|
||||
addr: MemOperand::Label(label.into()),
|
||||
dest,
|
||||
}
|
||||
}
|
||||
|
||||
// Memory stores
|
||||
pub fn stw_reg(src: Register, base: Register) -> Self {
|
||||
Self::Stw {
|
||||
src,
|
||||
addr: MemOperand::RegIndirect(base),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stw_reg_offset(src: Register, base: Register, offset: i32) -> Self {
|
||||
Self::Stw {
|
||||
src,
|
||||
addr: MemOperand::RegOffset(base, offset),
|
||||
}
|
||||
}
|
||||
|
||||
// Arithmetic
|
||||
pub fn add(src1: Register, src2: Register, dest: Register) -> Self {
|
||||
Self::Add { src1, src2, dest }
|
||||
}
|
||||
|
||||
pub fn sub(src1: Register, src2: Register, dest: Register) -> Self {
|
||||
Self::Sub { src1, src2, dest }
|
||||
}
|
||||
|
||||
pub fn iadd(src: Register, imm: i32) -> Self {
|
||||
Self::IAdd {
|
||||
src,
|
||||
imm: Imm(imm),
|
||||
dest: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iadd_dest(src: Register, imm: i32, dest: Register) -> Self {
|
||||
Self::IAdd {
|
||||
src,
|
||||
imm: Imm(imm),
|
||||
dest: Some(dest),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inc(reg: Register) -> Self {
|
||||
Self::Inc { reg }
|
||||
}
|
||||
|
||||
pub fn dec(reg: Register) -> Self {
|
||||
Self::Dec { reg }
|
||||
}
|
||||
|
||||
// Immediate loads
|
||||
pub fn load_imm32(value: u32, dest: Register) -> Vec<Self> {
|
||||
let lower = (value & 0xFFFF) as i32;
|
||||
let upper = ((value >> 16) & 0xFFFF) as i32;
|
||||
|
||||
vec![
|
||||
Self::Lli {
|
||||
imm: Imm(lower),
|
||||
dest,
|
||||
},
|
||||
Self::Lui {
|
||||
imm: Imm(upper),
|
||||
dest,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Control flow
|
||||
pub fn label(name: impl Into<String>) -> Self {
|
||||
Self::Label(Label(name.into()))
|
||||
}
|
||||
|
||||
pub fn jmp(target: impl Into<Label>) -> Self {
|
||||
Self::Jmp {
|
||||
target: target.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jeq(target: impl Into<Label>) -> Self {
|
||||
Self::Jeq {
|
||||
target: target.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmp(reg1: Register, reg2: Register) -> Self {
|
||||
Self::Cmp { reg1, reg2 }
|
||||
}
|
||||
|
||||
// Stack
|
||||
pub fn push(reg: Register) -> Self {
|
||||
Self::Push { reg }
|
||||
}
|
||||
|
||||
pub fn pop(reg: Register) -> Self {
|
||||
Self::Pop { reg }
|
||||
}
|
||||
|
||||
// Functions
|
||||
pub fn call(target: impl Into<String>) -> Self {
|
||||
Self::Call {
|
||||
target: target.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int(code: u8) -> Self {
|
||||
Self::Int { code }
|
||||
}
|
||||
|
||||
pub fn ret() -> Self {
|
||||
Self::Return
|
||||
}
|
||||
|
||||
// Utilities
|
||||
pub fn comment(text: impl Into<String>) -> Self {
|
||||
Self::Comment(text.into())
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience trait for Label conversion
|
||||
impl From<String> for Label {
|
||||
fn from(s: String) -> Self {
|
||||
Label(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Label {
|
||||
fn from(s: &str) -> Self {
|
||||
Label(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn format_mem_operand(op: &MemOperand) -> String {
|
||||
match op {
|
||||
MemOperand::RegIndirect(reg) => format!("{}", reg),
|
||||
MemOperand::RegOffset(reg, offset) => {
|
||||
if *offset >= 0 {
|
||||
format!("{}, {}", reg, offset)
|
||||
} else {
|
||||
format!("{}, {}", reg, offset)
|
||||
}
|
||||
}
|
||||
MemOperand::Label(label) => format!("{}", label),
|
||||
MemOperand::LabelOffset(label, offset) => {
|
||||
format!("{}, {}", label, offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory operand for loads/stores
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MemOperand {
|
||||
/// Register indirect: [reg]
|
||||
RegIndirect(Register),
|
||||
/// Register with offset: [reg + offset]
|
||||
RegOffset(Register, i32),
|
||||
/// Label: [label]
|
||||
Label(Label),
|
||||
/// Label with offset: [label + offset]
|
||||
LabelOffset(Label, i32),
|
||||
}
|
||||
|
||||
/// Immediate value (16-bit or 32-bit)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Imm(pub i32);
|
||||
|
||||
impl fmt::Display for Imm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Label reference
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Label(pub String);
|
||||
|
||||
impl fmt::Display for Label {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
pub struct FunctionContext {
|
||||
name: String,
|
||||
|
||||
stack_offset: i32,
|
||||
|
||||
registers: [(Register, bool); 16],
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
use crate::{
|
||||
backend::dsa::{
|
||||
instruction::{InsBlock, Reg},
|
||||
registers::Register,
|
||||
},
|
||||
model::{CompilerError, TypeId},
|
||||
};
|
||||
|
||||
pub struct Variable {
|
||||
name: String,
|
||||
|
||||
/// the type of the variable.
|
||||
r#type: TypeId,
|
||||
|
||||
/// size taken up in bytes.
|
||||
/// if size > 4, value must be stored on the stack.
|
||||
size: usize,
|
||||
|
||||
// location
|
||||
/// this must be None if it cannot be stored in a register.
|
||||
allocated_register: Option<Register>,
|
||||
|
||||
/// represents the offset from the base pointer (Bpr) of the stack frame.
|
||||
/// needs to be signed as offset is positive for function args and negative for local
|
||||
/// variables. as we can't access values at negative offsets, we use the following
|
||||
/// formula: addr = Spr + offset - (Spr - Bpr) where we know (Spr-Bpr) at compile
|
||||
/// time.
|
||||
bpr_offset: Option<isize>,
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
pub fn new_uninit(name: String, r#type: TypeId) -> Self {
|
||||
Self {
|
||||
name,
|
||||
size: r#type.size(),
|
||||
r#type,
|
||||
allocated_register: None,
|
||||
bpr_offset: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_register(
|
||||
&mut self,
|
||||
scope: &'_ mut Scope,
|
||||
) -> Result<Register, CompilerError> {
|
||||
if self.size > 4 {
|
||||
return Err(CompilerError::Generic(format!(
|
||||
"Type {} cannot be allocated a register as it has a size of {} bytes",
|
||||
self.r#type, self.size
|
||||
)));
|
||||
}
|
||||
|
||||
todo!("integrate with register alloc logic")
|
||||
|
||||
// self.allocated_register = Some(...)
|
||||
}
|
||||
|
||||
fn alloc_stack(&mut self, scope: &'_ mut Scope) -> Result<usize, CompilerError> {
|
||||
todo!("integrate with stack alloc logic")
|
||||
|
||||
// self.bpr_offset = Some(...)
|
||||
}
|
||||
|
||||
pub fn load(&mut self, scope: &'_ mut Scope) -> Result<Register, CompilerError> {
|
||||
todo!("load var from stack to reg (if possible)")
|
||||
}
|
||||
|
||||
pub fn new_local(
|
||||
name: String,
|
||||
r#type: TypeId,
|
||||
scope: &'_ mut Scope,
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut var = Self::new_uninit(name, r#type);
|
||||
var.alloc_register(scope)?;
|
||||
Ok(var)
|
||||
}
|
||||
|
||||
pub fn new_stack(
|
||||
name: String,
|
||||
r#type: TypeId,
|
||||
scope: &'_ mut Scope,
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut init = Self::new_uninit(name, r#type);
|
||||
init.alloc_stack(scope)?;
|
||||
Ok(init)
|
||||
}
|
||||
|
||||
pub fn drop(&mut self, scope: &'_ mut Scope) -> Result<(), CompilerError> {
|
||||
if let Some(reg) = self.allocated_register {
|
||||
todo!("dealloc reg in current function")
|
||||
}
|
||||
|
||||
if let Some(offset) = self.bpr_offset {
|
||||
todo!("free stack slot in current function")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn spill(&mut self, scope: &'_ mut Scope) -> Result<(), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// scope object
|
||||
pub struct Scope<'a> {
|
||||
/// outer scope, for a function this will be the global scope.
|
||||
parent: Option<&'a mut Scope<'a>>,
|
||||
|
||||
/// is the scope a function body or just a loop?
|
||||
/// depending on the type, ending a scope will have different behaviour
|
||||
r#type: ScopeType,
|
||||
|
||||
/// variables
|
||||
variables: HashMap<String, Variable>,
|
||||
|
||||
/// tells us if a given register is being used or not.
|
||||
/// this can be an array as registers have u8 representation.
|
||||
in_use: [(Register, bool); 16],
|
||||
|
||||
stack_offset: i32,
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
pub fn new(parent: &'a mut Scope<'a>, r#type: ScopeType) -> Scope<'a> {
|
||||
Self {
|
||||
stack_offset: parent.stack_offset,
|
||||
parent: Some(parent),
|
||||
r#type,
|
||||
variables: HashMap::new(),
|
||||
in_use: Register::get_gp().map(|reg| (reg, false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stack_offset(&self) -> i32 {
|
||||
self.stack_offset
|
||||
}
|
||||
|
||||
pub fn stack_offset_mut(&mut self) -> &mut i32 {
|
||||
&mut self.stack_offset
|
||||
}
|
||||
|
||||
pub fn close(&mut self) -> Result<(), CompilerError> {
|
||||
// closing a scope means we need to drop all variables in scope and free registers.
|
||||
for (name, var) in self.variables {
|
||||
if let Some(reg) = var.allocated_register {
|
||||
|
||||
}
|
||||
|
||||
if let Some(off)
|
||||
}
|
||||
|
||||
for reg in self.in_use
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn alloc_temp_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn alloc_var_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn alloc_var_stack(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn free_var_stack(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn free_temp_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
enum ScopeType {
|
||||
Function,
|
||||
IfBlock,
|
||||
LoopBlock,
|
||||
}
|
||||
Reference in New Issue
Block a user