From 0dbe7560b60c7e4b2190210730c587e02461d057 Mon Sep 17 00:00:00 2001 From: Toni Date: Wed, 18 Mar 2026 18:53:13 +0100 Subject: [PATCH] refactor the nasty RefCell by parsing everything first --- src/codegen_x86_64.rs | 28 +++++------ src/main.rs | 110 ++++++++++++++++-------------------------- src/typechecker.rs | 39 +++++---------- 3 files changed, 66 insertions(+), 111 deletions(-) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 46fbc78..9fecc46 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, fmt::Write, rc::Rc}; +use std::{collections::HashMap, fmt::Write}; use crate::{ analyzer::Analyzer, @@ -69,16 +69,16 @@ 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: Rc>, + pub analyzer: &'a Analyzer, } -impl CodegenX86_64 { - pub fn new(analyzer: Rc>) -> CodegenX86_64 { +impl<'a> CodegenX86_64<'a> { + pub fn new(analyzer: &'a Analyzer) -> CodegenX86_64<'a> { CodegenX86_64 { output: String::new(), data_section: String::new(), @@ -555,11 +555,11 @@ _builtin_environ: } } Expr::Variable(name) => { - if self.analyzer.borrow().constants.contains_key(&name.lexeme) { + if self.analyzer.constants.contains_key(&name.lexeme) { emit!( &mut self.output, " mov rax, {}", - self.analyzer.borrow().constants[&name.lexeme] + self.analyzer.constants[&name.lexeme] ); } else { let var = match env.get_var(&name.lexeme) { @@ -653,12 +653,7 @@ _builtin_environ: } if let Expr::Variable(callee_name) = &**callee { - if self - .analyzer - .borrow() - .functions - .contains_key(&callee_name.lexeme) - { + if self.analyzer.functions.contains_key(&callee_name.lexeme) { // its a function (defined/builtin/extern) emit!(&mut self.output, " call {}", callee_name.lexeme); } else { @@ -705,7 +700,7 @@ _builtin_environ: } Expr::AddrOf { op, expr } => match *expr.clone() { Expr::Variable(name) => { - if self.analyzer.borrow().functions.contains_key(&name.lexeme) { + 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) { @@ -729,7 +724,7 @@ _builtin_environ: } }, Expr::New(struct_name) => { - let struct_fields = &self.analyzer.borrow().structs[&struct_name.lexeme]; + let struct_fields = &self.analyzer.structs[&struct_name.lexeme]; // TODO: panic on mem.alloc error let memory_size = struct_fields.len() * 8; @@ -774,8 +769,7 @@ _builtin_environ: } }; - let analyzer = self.analyzer.borrow(); - let fields = match analyzer.structs.get(&struct_name) { + let fields = match self.analyzer.structs.get(&struct_name) { Some(f) => f, None => { return error!(&field.loc, format!("unknown struct type: {}", struct_name)); diff --git a/src/main.rs b/src/main.rs index df66e36..da7fdd3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,74 +5,24 @@ mod tokenizer; mod typechecker; use std::{ - cell::RefCell, fs, path::Path, process::{self, Command}, - rc::Rc, }; use tokenizer::ZernError; use clap::Parser; -macro_rules! compile_std { - ($codegen:expr, $typechecker:expr, $analyzer:expr, $( $name:literal ),* $(,)? ) => { - $( - compile_file_to( - $codegen, - $typechecker, - $analyzer, - $name, - include_str!(concat!("std/", $name)).into() - )?; - )* +macro_rules! parse_std_file { + ($statements:expr, $filename:expr) => { + let source: String = include_str!($filename).into(); + let tokenizer = tokenizer::Tokenizer::new($filename.to_owned(), source); + let parser = parser::Parser::new(tokenizer.tokenize()?); + $statements.extend(parser.parse()?); }; } -fn compile_file_to( - codegen: &mut codegen_x86_64::CodegenX86_64, - typechecker: &mut typechecker::TypeChecker, - analyzer: Rc>, - filename: &str, - source: String, -) -> Result<(), ZernError> { - let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source); - let tokens = tokenizer.tokenize()?; - - let parser = parser::Parser::new(tokens); - let statements = parser.parse()?; - - for stmt in &statements { - analyzer.borrow_mut().register_function(stmt)?; - } - - for stmt in &statements { - analyzer.borrow_mut().analyze_stmt(stmt)?; - } - - for stmt in &statements { - typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?; - } - - for stmt in statements { - // top level statements are all function/const/extern declarations so a new env for each - codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?; - } - Ok(()) -} - -fn run_command(cmd: String) { - if !Command::new("sh") - .args(["-c", &cmd]) - .status() - .unwrap() - .success() - { - process::exit(1); - } -} - fn compile_file(args: Args) -> Result<(), ZernError> { let source = match fs::read_to_string(&args.path) { Ok(x) => x, @@ -84,21 +34,34 @@ fn compile_file(args: Args) -> Result<(), ZernError> { let filename = Path::new(&args.path).file_name().unwrap().to_str().unwrap(); - let analyzer = Rc::new(RefCell::new(analyzer::Analyzer::new())); + let mut statements = Vec::new(); - let mut typechecker = typechecker::TypeChecker::new(analyzer.clone()); + parse_std_file!(statements, "std/syscalls.zr"); + parse_std_file!(statements, "std/std.zr"); + parse_std_file!(statements, "std/net.zr"); - let mut codegen = codegen_x86_64::CodegenX86_64::new(analyzer.clone()); + let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source); + let parser = parser::Parser::new(tokenizer.tokenize()?); + statements.extend(parser.parse()?); + + let mut analyzer = analyzer::Analyzer::new(); + for stmt in &statements { + analyzer.register_function(stmt)?; + } + for stmt in &statements { + analyzer.analyze_stmt(stmt)?; + } + + let mut typechecker = typechecker::TypeChecker::new(&analyzer); + for stmt in &statements { + typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?; + } + + let mut codegen = codegen_x86_64::CodegenX86_64::new(&analyzer); codegen.emit_prologue(args.use_gcc)?; - compile_std!( - &mut codegen, - &mut typechecker, - analyzer.clone(), - "syscalls.zr", - "std.zr", - "net.zr" - ); - compile_file_to(&mut codegen, &mut typechecker, analyzer, filename, source)?; + for stmt in statements { + codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?; + } if !args.output_asm { let out = args.out.unwrap_or_else(|| "out".into()); @@ -138,6 +101,17 @@ fn compile_file(args: Args) -> Result<(), ZernError> { Ok(()) } +fn run_command(cmd: String) { + if !Command::new("sh") + .args(["-c", &cmd]) + .status() + .unwrap() + .success() + { + process::exit(1); + } +} + #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { diff --git a/src/typechecker.rs b/src/typechecker.rs index e1b4002..3ec74a4 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::collections::HashMap; use crate::{ analyzer::{Analyzer, Type}, @@ -69,13 +69,13 @@ impl Env { } } -pub struct TypeChecker { - analyzer: Rc>, +pub struct TypeChecker<'a> { + analyzer: &'a Analyzer, current_function_return_type: String, } -impl TypeChecker { - pub fn new(analyzer: Rc>) -> TypeChecker { +impl<'a> TypeChecker<'a> { + pub fn new(analyzer: &'a Analyzer) -> TypeChecker<'a> { TypeChecker { analyzer, current_function_return_type: String::new(), @@ -300,7 +300,7 @@ impl TypeChecker { } } Expr::Variable(name) => { - if self.analyzer.borrow().constants.contains_key(&name.lexeme) { + if self.analyzer.constants.contains_key(&name.lexeme) { Ok("i64".into()) } else { match env.get_var_type(&name.lexeme) { @@ -337,8 +337,7 @@ impl TypeChecker { Expr::MemberAccess { left, field } => { let left_type = self.typecheck_expr(env, left)?; - let analyzer = self.analyzer.borrow(); - let fields = match analyzer.structs.get(&left_type) { + let fields = match self.analyzer.structs.get(&left_type) { Some(f) => f, None => { return error!( @@ -370,14 +369,8 @@ impl TypeChecker { args, } => { if let Expr::Variable(callee_name) = &**callee { - if self - .analyzer - .borrow() - .functions - .contains_key(&callee_name.lexeme) - { - let fn_type = - &self.analyzer.borrow().functions[&callee_name.lexeme].clone(); + if self.analyzer.functions.contains_key(&callee_name.lexeme) { + let fn_type = &self.analyzer.functions[&callee_name.lexeme].clone(); // its a function (defined/builtin/extern) if let Some(params) = fn_type.params.clone() { for (i, arg) in args.iter().enumerate() { @@ -427,7 +420,7 @@ impl TypeChecker { } Expr::AddrOf { op, expr } => match expr.as_ref() { Expr::Variable(name) => { - if self.analyzer.borrow().functions.contains_key(&name.lexeme) { + if self.analyzer.functions.contains_key(&name.lexeme) { Ok("fnptr".into()) } else { Ok("ptr".into()) @@ -438,12 +431,7 @@ impl TypeChecker { } }, Expr::New(struct_name) => { - if !self - .analyzer - .borrow() - .structs - .contains_key(&struct_name.lexeme) - { + if !self.analyzer.structs.contains_key(&struct_name.lexeme) { return error!( &struct_name.loc, format!("unknown struct name: {}", &struct_name.lexeme) @@ -454,8 +442,7 @@ impl TypeChecker { Expr::MemberAccess { left, field } => { let left_type = self.typecheck_expr(env, left)?; - let analyzer = self.analyzer.borrow(); - let fields = match analyzer.structs.get(&left_type) { + let fields = match self.analyzer.structs.get(&left_type) { Some(f) => f, None => { return error!(&field.loc, format!("unknown struct type: {}", left_type)); @@ -486,7 +473,7 @@ impl TypeChecker { if BUILTIN_TYPES.contains(&name) { return true; } - if self.analyzer.borrow().structs.contains_key(name) { + if self.analyzer.structs.contains_key(name) { return true; } false