From d55ca11658c529375d8832d6837ea358eb279336 Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 21 Dec 2025 16:11:15 +0100 Subject: [PATCH] addr-of operator --- src/analyzer.rs | 3 +++ src/codegen_x86_64.rs | 25 +++++++++++++++++++++++++ src/parser.rs | 12 ++++++++++++ src/tokenizer.rs | 2 ++ test.zr | 2 +- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index 85220ff..36644ab 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -160,6 +160,9 @@ impl Analyzer { self.analyze_expr(expr)?; self.analyze_expr(index)?; } + Expr::AddrOf { op: _, expr } => { + self.analyze_expr(expr)?; + } } Ok(()) } diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index ddfa06e..4ae8361 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -548,6 +548,31 @@ _builtin_environ: emit!(&mut self.output, " add rdi, rax"); emit!(&mut self.output, " call _builtin_read8"); } + Expr::AddrOf { op, expr } => match *expr { + Expr::Variable(name) => { + if self.analyzer.functions.contains_key(&name.lexeme) { + emit!(&mut self.output, " mov rax, {}", name.lexeme); + } else { + let var = match env.get_var(&name.lexeme) { + Some(x) => x, + None => { + return error!( + name.loc, + format!("undefined variable: {}", &name.lexeme) + ); + } + }; + emit!( + &mut self.output, + " lea rax, QWORD [rbp-{}]", + var.stack_offset, + ); + } + } + _ => { + return error!(&op.loc, "can only take address of variables and functions"); + } + }, } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index d90ad45..e975c2e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -71,6 +71,10 @@ pub enum Expr { expr: Box, index: Box, }, + AddrOf { + op: Token, + expr: Box, + }, } // TODO: currently they are all just 8 byte values @@ -408,6 +412,14 @@ impl Parser { } fn unary(&mut self) -> Result { + if self.match_token(&[TokenType::At]) { + let op = self.previous().clone(); + let right = self.unary()?; + return Ok(Expr::AddrOf { + op, + expr: Box::new(right), + }); + } if self.match_token(&[TokenType::Bang, TokenType::Minus]) { let op = self.previous().clone(); let right = self.unary()?; diff --git a/src/tokenizer.rs b/src/tokenizer.rs index c23133a..d86c659 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -18,6 +18,7 @@ pub enum TokenType { BitAnd, BitOr, Pipe, + At, DoubleDot, ShiftLeft, ShiftRight, @@ -154,6 +155,7 @@ impl Tokenizer { '%' => self.add_token(TokenType::Mod), '^' => self.add_token(TokenType::Xor), ':' => self.add_token(TokenType::Colon), + '@' => self.add_token(TokenType::At), '.' => { if self.match_char('.') { self.add_token(TokenType::DoubleDot) diff --git a/test.zr b/test.zr index 811ac70..d08fb0a 100644 --- a/test.zr +++ b/test.zr @@ -1,5 +1,5 @@ func run_test[x: String] : Void - if str.equal(x, "raylib.zr") | str.equal(x, "x11.zr") | str.equal(x, "sqlite_todo.zr") + if str.equal(x, "puzzles") | str.equal(x, "raylib.zr") | str.equal(x, "x11.zr") | str.equal(x, "sqlite_todo.zr") io.print("\033[93mSkipping ") io.print(x) io.println("...\033[0m")