- renamed assembler_runner to just assembler

- implemented type parsing including custom types and generics (useless
  for now as we do no semantic analysis)
- implemented struct literal parsing
- implemented struct definition parsing (no generics yet)
- implemented tuple parsing
- registers are now allocated starting from zero
- updated to-dos
This commit is contained in:
2026-02-10 10:03:48 +00:00
parent 509b3465f1
commit 931af90789
8 changed files with 316 additions and 71 deletions
+11
View File
@@ -65,6 +65,10 @@ impl CodeGenerator {
Declaration::Dependency(Dependency { name, .. }) => {
self.symbols.push(name)
}
Declaration::Struct { .. } => {} /* we can't do any code generation for
* a struct yet. we may need to later
* once these become class-like
* objects with implementations */
}
}
@@ -164,6 +168,8 @@ impl CodeGenerator {
Declaration::Dependency(Dependency { name, path }) => {
self.imports.insert(name, path);
}
Declaration::Struct { .. } => {} /* can't do any codegen for these yet,
* they're just types. */
};
Ok(())
@@ -536,6 +542,11 @@ impl CodeGenerator {
}
Expression::ArrayLiteral { elements, type_id } => todo!(),
Expression::StructLiteral {
name,
fields,
type_id,
} => todo!(),
Expression::Variable { name, .. } => {
if self.is_global(&name.name) {
+23 -18
View File
@@ -18,7 +18,7 @@ pub struct RegisterAllocator {
stack_offset: i32,
/// Track which registers are currently in use
in_use: HashMap<Register, bool>,
in_use: Vec<(Register, bool)>,
}
#[derive(Debug, Clone)]
@@ -85,7 +85,7 @@ impl RegisterAllocator {
// println!("finding! {:#?}", self.in_use);
if let Some(reg) = self.find_free_register() {
self.in_use.insert(reg, true);
self.in_use[reg as usize].1 = true;
return Ok((reg, Vec::new()));
}
@@ -133,7 +133,7 @@ impl RegisterAllocator {
// This is a true temporary - safe to free
if !matches!(reg, Register::Zero | Register::Null) {
self.in_use.insert(reg, false);
self.in_use[reg as usize].1 = false;
}
}
@@ -144,7 +144,7 @@ impl RegisterAllocator {
&& !matches!(reg, Register::Zero | Register::Null)
{
self.register_contents.remove(&reg);
self.in_use.insert(reg, false);
self.in_use[reg as usize].1 = false;
}
self.variable_locations.remove(var);
@@ -252,7 +252,7 @@ impl RegisterAllocator {
.insert(var_name.to_string(), Location::register(*source_reg));
self.register_contents
.insert(*source_reg, var_name.to_string());
self.in_use.insert(*source_reg, true);
self.in_use[*source_reg as usize].1 = true;
return Vec::new();
}
@@ -264,7 +264,7 @@ impl RegisterAllocator {
.insert(var_name.to_string(), Location::register(free_reg));
self.register_contents
.insert(free_reg.clone(), var_name.to_string());
self.in_use.insert(free_reg, true);
self.in_use[free_reg as usize].1 = true;
return vec![format!("\tmov {}, {}", source_reg, free_reg)];
}
@@ -459,26 +459,31 @@ impl RegisterAllocator {
pub fn get_caller_saved_registers(&self) -> Vec<Register> {
self.register_contents
.iter()
.filter(|(reg, _)| *self.in_use.get(*reg).unwrap_or(&false))
.filter(|(reg, _)| {
self.in_use
.get(**reg as usize)
.unwrap_or(&(Register::Null, false))
.1
})
.map(|(reg, _)| reg.clone())
.collect()
}
/// Save caller-saved registers before a function call
/// Returns assembly code to save them
pub fn _save_caller_saved(&mut self) -> Vec<String> {
let mut code = Vec::new();
// pub fn _save_caller_saved(&mut self) -> Vec<String> {
// let mut code = Vec::new();
// For simplicity, save all currently used registers
// In a more sophisticated compiler, you'd only save registers that are live
for (reg, _) in self.register_contents.clone() {
if *self.in_use.get(&reg).unwrap_or(&false) {
code.push(format!("\tpush {}", reg));
}
}
// // For simplicity, save all currently used registers
// // In a more sophisticated compiler, you'd only save registers that are live
// for (reg, _) in self.register_contents.clone() {
// if *self.in_use.get(reg as usize).unwrap_or(&false) {
// code.push(format!("\tpush {}", reg));
// }
// }
code
}
// code
// }
/// Restore caller-saved registers after a function call
/// Returns assembly code to restore them