From 316e60eedbea54a06676070f58de65d14580fb03 Mon Sep 17 00:00:00 2001 From: Toni Date: Tue, 10 Mar 2026 18:32:58 +0100 Subject: [PATCH] add Stmt::Struct and Expr::New --- src/analyzer.rs | 2 ++ src/codegen_x86_64.rs | 12 +++++++++--- src/parser.rs | 40 +++++++++++++++++++++++++++++++++++++++- src/tokenizer.rs | 4 ++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index 1b33d95..44f5020 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -117,6 +117,7 @@ impl Analyzer { } self.functions.insert(name.lexeme.clone(), -1); } + Stmt::Struct { name: _, fields: _ } => todo!(), } Ok(()) } @@ -188,6 +189,7 @@ impl Analyzer { Expr::AddrOf { op: _, expr } => { self.analyze_expr(expr)?; } + Expr::New(_) => {} } Ok(()) } diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 40040a7..dcd54ab 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -6,8 +6,9 @@ use crate::{ tokenizer::{TokenType, ZernError, error}, }; -pub struct Var { +struct Var { pub stack_offset: usize, + pub var_type: String, } pub struct Env { @@ -37,19 +38,20 @@ impl Env { self.scopes.pop(); } - pub fn define_var(&mut self, name: String, _var_type: String) -> usize { + pub fn define_var(&mut self, name: String, var_type: String) -> usize { let offset = self.next_offset; self.next_offset += 8; self.scopes.last_mut().unwrap().insert( name, Var { stack_offset: offset, + var_type, }, ); offset } - pub fn get_var(&self, name: &str) -> Option<&Var> { + fn get_var(&self, name: &str) -> Option<&Var> { for scope in self.scopes.iter().rev() { if let Some(var) = scope.get(name) { return Some(var); @@ -315,6 +317,9 @@ _builtin_environ: Stmt::Extern(name) => { emit!(&mut self.output, "extern {}", name.lexeme); } + Stmt::Struct { name: _, fields: _ } => { + // handled in the analyzer + } } Ok(()) } @@ -622,6 +627,7 @@ _builtin_environ: return error!(&op.loc, "can only take address of variables and functions"); } }, + Expr::New(_) => todo!(), } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 8135faa..b25849b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -45,6 +45,10 @@ pub enum Stmt { Break, Continue, Extern(Token), + Struct { + name: Token, + fields: Vec, + }, } #[derive(Debug, Clone)] @@ -84,6 +88,7 @@ pub enum Expr { op: Token, expr: Box, }, + New(Token), } // TODO: currently they are all just 64 bit values @@ -127,6 +132,9 @@ impl Parser { if self.match_token(&[TokenType::KeywordConst]) { return self.const_declaration(); } + if self.match_token(&[TokenType::KeywordStruct]) { + return self.struct_declaration(); + } return error!( self.peek().loc, "statements not allowed outside function body" @@ -182,6 +190,29 @@ impl Parser { }) } + fn struct_declaration(&mut self) -> Result { + let name = self.consume(TokenType::Identifier, "expected struct name")?; + + self.consume(TokenType::Indent, "expected indent after struct name")?; + + let mut fields = vec![]; + while !self.eof() && !self.check(&TokenType::Dedent) { + let var_name = self.consume(TokenType::Identifier, "expected field name")?; + 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 }); + } + + self.consume(TokenType::Dedent, "expected dedent after the struct fields")?; + + Ok(Stmt::Struct { name, fields }) + } + fn let_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected variable name")?; @@ -524,10 +555,17 @@ impl Parser { self.consume(TokenType::RightBracket, "expected ']' after values")?; Ok(Expr::ArrayLiteral(xs)) + } else if self.match_token(&[TokenType::KeywordNew]) { + let struct_name = + self.consume(TokenType::Identifier, "expected struct name after 'new'")?; + Ok(Expr::New(struct_name)) } else if self.match_token(&[TokenType::Identifier]) { Ok(Expr::Variable(self.previous().clone())) } else { - error!(self.peek().loc, "expected expression") + error!( + self.peek().loc, + format!("expected expression, got '{}'", self.peek().lexeme) + ) } } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 441db72..9dacccf 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -52,6 +52,8 @@ pub enum TokenType { KeywordContinue, KeywordExtern, KeywordExport, + KeywordStruct, + KeywordNew, Indent, Dedent, @@ -347,6 +349,8 @@ impl Tokenizer { "continue" => TokenType::KeywordContinue, "extern" => TokenType::KeywordExtern, "export" => TokenType::KeywordExport, + "struct" => TokenType::KeywordStruct, + "new" => TokenType::KeywordNew, "true" => TokenType::True, "false" => TokenType::False, _ => TokenType::Identifier,