From a259d204be1184dea98514b7ca844fd86b43e47b Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 21 Dec 2025 15:42:00 +0100 Subject: [PATCH] allow dynamic calls --- src/analyzer.rs | 37 ++++++++++++++++++++++++------------- src/codegen_x86_64.rs | 41 +++++++++++++++++++++-------------------- src/main.rs | 16 +++++----------- 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index 7a4a809..85220ff 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -120,20 +120,31 @@ impl Analyzer { paren, args, } => { - let callee = match callee.as_ref() { - Expr::Variable(name) => name.lexeme.clone(), - _ => return error!(&paren.loc, "tried to call a non-constant expression"), - }; - - if let Some(arity) = self.functions.get(&callee) { - if *arity >= 0 && *arity != args.len() as i32 { - return error!( - &paren.loc, - format!("expected {} arguments, got {}", arity, args.len()) - ); + if let Expr::Variable(callee_name) = *callee.clone() { + if callee_name.lexeme.starts_with("_builtin_") + || self.functions.contains_key(&callee_name.lexeme) + { + // its a function (defined/builtin/extern) + if let Some(arity) = self.functions.get(&callee_name.lexeme) { + if *arity >= 0 && *arity != args.len() as i32 { + return error!( + &paren.loc, + format!("expected {} arguments, got {}", arity, args.len()) + ); + } + } else if !callee_name.lexeme.starts_with("_builtin_") { + return error!( + &paren.loc, + format!("undefined function: {}", callee_name.lexeme) + ); + } + } else { + // its a variable containing function address + self.analyze_expr(callee)?; } - } else if !callee.starts_with("_builtin_") { - return error!(&paren.loc, format!("undefined function: {}", callee)); + } else { + // its an expression that evalutes to function address + self.analyze_expr(callee)?; } for arg in args { diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index b8cc0a7..ddfa06e 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, fmt::Write}; use crate::{ + analyzer::Analyzer, parser::{Expr, Stmt}, tokenizer::{TokenType, ZernError, error}, }; @@ -64,20 +65,22 @@ macro_rules! emit { static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; -pub struct CodegenX86_64 { +pub struct CodegenX86_64<'a> { output: String, data_section: String, label_counter: usize, data_counter: usize, + pub analyzer: &'a mut Analyzer, } -impl CodegenX86_64 { - pub fn new() -> CodegenX86_64 { +impl<'a> CodegenX86_64<'a> { + pub fn new(analyzer: &'a mut Analyzer) -> CodegenX86_64<'a> { CodegenX86_64 { output: String::new(), data_section: String::new(), label_counter: 0, data_counter: 1, + analyzer, } } @@ -470,14 +473,9 @@ _builtin_environ: } Expr::Call { callee, - paren, + paren: _, args, } => { - let callee = match *callee { - Expr::Variable(name) => name.lexeme, - _ => return error!(&paren.loc, "tried to call a non-constant expression"), - }; - for arg in &args { self.compile_expr(env, arg.clone())?; emit!(&mut self.output, " push rax"); @@ -507,19 +505,22 @@ _builtin_environ: } } - match env.get_var(&callee) { - Some(var) => { - emit!( - &mut self.output, - " mov rax, QWORD [rbp-{}]", - var.stack_offset, - ); + if let Expr::Variable(callee_name) = &*callee { + if callee_name.lexeme.starts_with("_builtin_") + || self.analyzer.functions.contains_key(&callee_name.lexeme) + { + // its a function (defined/builtin/extern) + emit!(&mut self.output, " call {}", callee_name.lexeme); + } else { + // its a variable containing function address + self.compile_expr(env, *callee)?; emit!(&mut self.output, " call rax"); } - None => { - emit!(&mut self.output, " call {}", callee); - } - }; + } else { + // its an expression that evalutes to function address + self.compile_expr(env, *callee)?; + emit!(&mut self.output, " call rax"); + } if arg_count > 6 { let num_stack = arg_count - 6; diff --git a/src/main.rs b/src/main.rs index 5afe0b0..4e5f7b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,6 @@ use tokenizer::ZernError; use clap::Parser; fn compile_file_to( - analyzer: &mut analyzer::Analyzer, codegen: &mut codegen_x86_64::CodegenX86_64, filename: &str, source: String, @@ -26,11 +25,11 @@ fn compile_file_to( let statements = parser.parse()?; for stmt in &statements { - analyzer.register_function(stmt)?; + codegen.analyzer.register_function(stmt)?; } for stmt in &statements { - analyzer.analyze_stmt(stmt)?; + codegen.analyzer.analyze_stmt(stmt)?; } for stmt in statements { @@ -62,15 +61,10 @@ fn compile_file(args: Args) -> Result<(), ZernError> { let filename = Path::new(&args.path).file_name().unwrap().to_str().unwrap(); let mut analyzer = analyzer::Analyzer::new(); - let mut codegen = codegen_x86_64::CodegenX86_64::new(); + let mut codegen = codegen_x86_64::CodegenX86_64::new(&mut analyzer); codegen.emit_prologue()?; - compile_file_to( - &mut analyzer, - &mut codegen, - "std.zr", - include_str!("std.zr").into(), - )?; - compile_file_to(&mut analyzer, &mut codegen, filename, source)?; + compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?; + compile_file_to(&mut codegen, filename, source)?; if !args.output_asm { fs::write(format!("{}.s", args.out), codegen.get_output()).unwrap();