From b79cd46b4b8acc2dfee0cb73eef96b1353de1544 Mon Sep 17 00:00:00 2001 From: Toni Date: Wed, 11 Mar 2026 14:46:44 +0100 Subject: [PATCH] malloc structs and allow using them as types --- src/analyzer.rs | 14 +++++++++++++- src/codegen_x86_64.rs | 26 +++++++++++++++++++++++++- src/parser.rs | 15 --------------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index 44f5020..c4d3d93 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -8,6 +8,7 @@ use crate::{ pub struct Analyzer { pub functions: HashMap, pub constants: HashMap, + pub structs: HashMap>, } impl Analyzer { @@ -15,6 +16,7 @@ impl Analyzer { Analyzer { functions: HashMap::new(), constants: HashMap::new(), + structs: HashMap::new(), } } @@ -117,7 +119,17 @@ impl Analyzer { } self.functions.insert(name.lexeme.clone(), -1); } - Stmt::Struct { name: _, fields: _ } => todo!(), + Stmt::Struct { name, fields } => { + let mut fields_map: HashMap = HashMap::new(); + + let mut offset: usize = 0; + for field in fields { + fields_map.insert(field.var_name.lexeme.clone(), offset); + offset += 8; + } + + self.structs.insert(name.lexeme.clone(), fields_map); + } } Ok(()) } diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index dcd54ab..beab783 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -69,6 +69,9 @@ macro_rules! emit { static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; +// TODO: currently they are all just 64 bit values +static BUILTIN_TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"]; + pub struct CodegenX86_64<'a> { output: String, data_section: String, @@ -170,6 +173,10 @@ _builtin_environ: }, }; + if !self.is_valid_type_name(&var_type) { + return error!(&name.loc, "unrecognized type: ".to_owned() + &var_type); + } + self.compile_expr(env, initializer)?; let offset = env.define_var(name.lexeme.clone(), var_type); emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); @@ -627,8 +634,25 @@ _builtin_environ: return error!(&op.loc, "can only take address of variables and functions"); } }, - Expr::New(_) => todo!(), + Expr::New(struct_name) => { + let struct_fields = &self.analyzer.structs[&struct_name.lexeme]; + + let memory_size = struct_fields.len() * 8; + + emit!(&mut self.output, " mov rdi, {}", memory_size); + emit!(&mut self.output, " call malloc"); + } } Ok(()) } + + fn is_valid_type_name(&self, name: &str) -> bool { + if BUILTIN_TYPES.contains(&name) { + return true; + } + if self.analyzer.structs.contains_key(name) { + return true; + } + false + } } diff --git a/src/parser.rs b/src/parser.rs index b25849b..9452e04 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -91,9 +91,6 @@ pub enum Expr { New(Token), } -// TODO: currently they are all just 64 bit values -static TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"]; - pub struct Parser { tokens: Vec, current: usize, @@ -159,9 +156,6 @@ impl Parser { self.consume(TokenType::Colon, "expected ':' after parameter name")?; let var_type = self.consume(TokenType::Identifier, "expected parameter type")?; - if !TYPES.contains(&var_type.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", var_type.lexeme)); - } params.push(Param { var_type, var_name }); if !self.match_token(&[TokenType::Comma]) { @@ -173,9 +167,6 @@ impl Parser { self.consume(TokenType::RightBracket, "expected ']' after arguments")?; self.consume(TokenType::Colon, "expected ':' after '['")?; let return_type = self.consume(TokenType::Identifier, "expected return type")?; - if !TYPES.contains(&return_type.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", return_type.lexeme)); - } self.is_inside_function = true; let body = Box::new(self.block()?); @@ -201,9 +192,6 @@ impl Parser { self.consume(TokenType::Colon, "expected ':' after field name")?; let var_type = self.consume(TokenType::Identifier, "expected field type")?; - if !TYPES.contains(&var_type.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", var_type.lexeme)); - } fields.push(Param { var_type, var_name }); } @@ -218,9 +206,6 @@ impl Parser { let var_type = if self.match_token(&[TokenType::Colon]) { let token = self.consume(TokenType::Identifier, "expected variable type")?; - if !TYPES.contains(&token.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", token.lexeme)); - } Some(token) } else { None