From 35f0823432c9126b133fe2fa82e2c2e9a8b1626b Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 1 Jun 2025 16:41:51 +0200 Subject: [PATCH] remove boxed errors --- src/codegen_x86_64.rs | 199 +++++++++++++++++++++++------------------- src/main.rs | 41 ++++++--- src/parser.rs | 46 +++++----- src/tokenizer.rs | 12 +-- 4 files changed, 168 insertions(+), 130 deletions(-) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 0538b8b..2d6b3d6 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, error::Error, fmt::Write}; +use std::{collections::HashMap, fmt::Write}; use crate::{ parser::{Expr, Stmt}, @@ -51,6 +51,12 @@ impl Env { } } +macro_rules! emit { + ($($arg:tt)*) => { + let _ = writeln!($($arg)*); + }; +} + pub struct CodegenX86_64 { output: String, data_section: String, @@ -94,26 +100,26 @@ impl CodegenX86_64 { ) } - pub fn emit_prologue(&mut self) -> Result<(), Box> { - writeln!( + pub fn emit_prologue(&mut self) -> Result<(), ZernError> { + emit!( &mut self.output, " section .text extern printf extern puts print equ puts -" - )?; +", + ); Ok(()) } - pub fn emit_epilogue(&mut self) -> Result<(), Box> { - writeln!(&mut self.output, "section .note.GNU-stack")?; - writeln!(&mut self.output, " db 0")?; + pub fn emit_epilogue(&mut self) -> Result<(), ZernError> { + emit!(&mut self.output, "section .note.GNU-stack"); + emit!(&mut self.output, " db 0"); Ok(()) } - pub fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box> { + pub fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), ZernError> { match stmt { Stmt::Expression(expr) => self.compile_expr(env, expr)?, Stmt::Let { @@ -126,7 +132,7 @@ print equ puts self.compile_expr(env, initializer)?; let offset = env.define_var(name.lexeme.clone(), var_type.lexeme); - writeln!(&mut self.output, " mov QWORD [rbp-{}], rax", offset)?; + emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); } Stmt::Block(statements) => { env.push_scope(); @@ -144,25 +150,25 @@ print equ puts let end_label = self.label(); self.compile_expr(env, condition)?; - writeln!(&mut self.output, " test rax, rax")?; - writeln!(&mut self.output, " je {}", else_label)?; + emit!(&mut self.output, " test rax, rax"); + emit!(&mut self.output, " je {}", else_label); self.compile_stmt(env, *then_branch.clone())?; - writeln!(&mut self.output, " jmp {}", end_label)?; - writeln!(&mut self.output, "{}:", else_label)?; + emit!(&mut self.output, " jmp {}", end_label); + emit!(&mut self.output, "{}:", else_label); self.compile_stmt(env, *else_branch.clone())?; - writeln!(&mut self.output, "{}:", end_label)?; + emit!(&mut self.output, "{}:", end_label); } Stmt::While { condition, body } => { let begin_label = self.label(); let end_label = self.label(); - writeln!(&mut self.output, "{}:", begin_label)?; + emit!(&mut self.output, "{}:", begin_label); self.compile_expr(env, condition)?; - writeln!(&mut self.output, " test rax, rax")?; - writeln!(&mut self.output, " je {}", end_label)?; + emit!(&mut self.output, " test rax, rax"); + emit!(&mut self.output, " je {}", end_label); self.compile_stmt(env, *body.clone())?; - writeln!(&mut self.output, " jmp {}", begin_label)?; - writeln!(&mut self.output, "{}:", end_label)?; + emit!(&mut self.output, " jmp {}", begin_label); + emit!(&mut self.output, "{}:", end_label); } Stmt::Function { name, @@ -172,115 +178,130 @@ print equ puts } => { assert!(return_type.lexeme == "I64"); // TODO - writeln!(&mut self.output, "global {}", name.lexeme)?; - writeln!(&mut self.output, "{}:", name.lexeme)?; - writeln!(&mut self.output, " push rbp")?; - writeln!(&mut self.output, " mov rbp, rsp")?; - writeln!(&mut self.output, " sub rsp, 256")?; // TODO + emit!(&mut self.output, "global {}", name.lexeme); + emit!(&mut self.output, "{}:", name.lexeme); + emit!(&mut self.output, " push rbp"); + emit!(&mut self.output, " mov rbp, rsp"); + emit!(&mut self.output, " sub rsp, 256"); // TODO for (i, param) in params.iter().enumerate() { let offset = env .define_var(param.var_name.lexeme.clone(), param.var_type.lexeme.clone()); - writeln!( + emit!( &mut self.output, " mov QWORD [rbp-{}], {}", offset, - CodegenX86_64::nth_register(i) - )?; + CodegenX86_64::nth_register(i), + ); } self.compile_stmt(env, *body)?; - writeln!(&mut self.output, " mov rax, 0")?; // TODO: remove default return value - writeln!(&mut self.output, " mov rsp, rbp")?; - writeln!(&mut self.output, " pop rbp")?; - writeln!(&mut self.output, " ret")?; + emit!(&mut self.output, " mov rax, 0"); // TODO: remove default return value + emit!(&mut self.output, " mov rsp, rbp"); + emit!(&mut self.output, " pop rbp"); + emit!(&mut self.output, " ret"); } Stmt::Return(expr) => { self.compile_expr(env, expr)?; - writeln!(&mut self.output, " mov rsp, rbp")?; - writeln!(&mut self.output, " pop rbp")?; - writeln!(&mut self.output, " ret")?; + emit!(&mut self.output, " mov rsp, rbp"); + emit!(&mut self.output, " pop rbp"); + emit!(&mut self.output, " ret"); } } Ok(()) } - pub fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box> { + pub fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), ZernError> { match expr { Expr::Binary { left, op, right } => { self.compile_expr(env, *left)?; - writeln!(&mut self.output, " push rax")?; + emit!(&mut self.output, " push rax"); self.compile_expr(env, *right)?; - writeln!(&mut self.output, " mov rbx, rax")?; - writeln!(&mut self.output, " pop rax")?; + emit!(&mut self.output, " mov rbx, rax"); + emit!(&mut self.output, " pop rax"); match op.token_type { - TokenType::Plus => writeln!(&mut self.output, " add rax, rbx")?, - TokenType::Minus => writeln!(&mut self.output, " sub rax, rbx")?, - TokenType::Star => writeln!(&mut self.output, " imul rax, rbx")?, + TokenType::Plus => { + emit!(&mut self.output, " add rax, rbx"); + } + TokenType::Minus => { + emit!(&mut self.output, " sub rax, rbx"); + } + TokenType::Star => { + emit!(&mut self.output, " imul rax, rbx"); + } TokenType::Slash => { - writeln!(&mut self.output, " cqo")?; - writeln!(&mut self.output, " idiv rbx")?; + emit!(&mut self.output, " cqo"); + emit!(&mut self.output, " idiv rbx"); } TokenType::Mod => { - writeln!(&mut self.output, " cqo")?; - writeln!(&mut self.output, " idiv rbx")?; - writeln!(&mut self.output, " mov rax, rdx")?; + emit!(&mut self.output, " cqo"); + emit!(&mut self.output, " idiv rbx"); + emit!(&mut self.output, " mov rax, rdx"); + } + TokenType::Xor => { + emit!(&mut self.output, " xor rax, rbx"); + } + TokenType::And => { + emit!(&mut self.output, " and rax, rbx"); + } + TokenType::Or => { + emit!(&mut self.output, " or rax, rbx"); } - TokenType::Xor => writeln!(&mut self.output, " xor rax, rbx")?, - TokenType::And => writeln!(&mut self.output, " and rax, rbx")?, - TokenType::Or => writeln!(&mut self.output, " or rax, rbx")?, TokenType::DoubleEqual => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " sete al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " sete al"); + emit!(&mut self.output, " movzx rax, al"); } TokenType::NotEqual => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " setne al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " setne al"); + emit!(&mut self.output, " movzx rax, al"); } TokenType::Greater => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " setg al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " setg al"); + emit!(&mut self.output, " movzx rax, al"); } TokenType::GreaterEqual => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " setge al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " setge al"); + emit!(&mut self.output, " movzx rax, al"); } TokenType::Less => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " setl al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " setl al"); + emit!(&mut self.output, " movzx rax, al"); } TokenType::LessEqual => { - writeln!(&mut self.output, " cmp rax, rbx")?; - writeln!(&mut self.output, " setle al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " cmp rax, rbx"); + emit!(&mut self.output, " setle al"); + emit!(&mut self.output, " movzx rax, al"); } _ => unreachable!(), } } Expr::Grouping(expr) => self.compile_expr(env, *expr)?, Expr::Literal(token) => match token.token_type { - TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?, + TokenType::Number => { + emit!(&mut self.output, " mov rax, {}", token.lexeme); + } TokenType::String => { // TODO: actual string parsing in the tokenizer let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n"); let charcodes = value .chars() - .map(|x| format!("{}", x as u8)) + .map(|x| (x as u8).to_string()) .collect::>() .join(","); - writeln!( + emit!( &mut self.data_section, " S{} db {},0", - self.data_counter, charcodes - )?; - writeln!(&mut self.output, " mov rax, S{}", self.data_counter)?; + self.data_counter, + charcodes, + ); + emit!(&mut self.output, " mov rax, S{}", self.data_counter); self.data_counter += 1; } _ => unreachable!(), @@ -288,11 +309,13 @@ print equ puts Expr::Unary { op, right } => { self.compile_expr(env, *right)?; match op.token_type { - TokenType::Minus => writeln!(&mut self.output, " neg rax")?, + TokenType::Minus => { + emit!(&mut self.output, " neg rax"); + } TokenType::Bang => { - writeln!(&mut self.output, " test rax, rax")?; - writeln!(&mut self.output, " sete al")?; - writeln!(&mut self.output, " movzx rax, al")?; + emit!(&mut self.output, " test rax, rax"); + emit!(&mut self.output, " sete al"); + emit!(&mut self.output, " movzx rax, al"); } _ => unreachable!(), } @@ -304,11 +327,11 @@ print equ puts return error!(name.loc, format!("undefined variable: {}", &name.lexeme)); } }; - writeln!( + emit!( &mut self.output, " mov rax, QWORD [rbp-{}]", - var.stack_offset - )? + var.stack_offset, + ); } Expr::Assign { name, value } => { self.compile_expr(env, *value)?; @@ -319,11 +342,11 @@ print equ puts return error!(name.loc, format!("undefined variable: {}", &name.lexeme)); } }; - writeln!( + emit!( &mut self.output, " mov QWORD [rbp-{}], rax", - var.stack_offset - )?; + var.stack_offset, + ); } Expr::Call { callee, @@ -337,14 +360,14 @@ print equ puts for (i, arg) in args.iter().enumerate() { self.compile_expr(env, arg.clone())?; - writeln!( + emit!( &mut self.output, " mov {}, rax", - CodegenX86_64::nth_register(i) - )?; + CodegenX86_64::nth_register(i), + ); } - writeln!(&mut self.output, " call {}", callee)?; + emit!(&mut self.output, " call {}", callee); } } Ok(()) diff --git a/src/main.rs b/src/main.rs index 1c04280..ee0f5c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,15 +3,21 @@ mod parser; mod tokenizer; use std::{ - env, - error::Error, - fs, + env, fs, path::Path, process::{self, Command}, }; -fn compile_file(path: String) -> Result<(), Box> { - let source = fs::read_to_string(path.clone())?; +use tokenizer::ZernError; + +fn compile_file(path: String) -> Result<(), ZernError> { + let source = match fs::read_to_string(path.clone()) { + Ok(x) => x, + Err(_) => { + eprintln!("\x1b[91mERROR\x1b[0m: failed to open {}", path); + process::exit(1); + } + }; let filename = Path::new(&path).file_name().unwrap().to_str().unwrap(); @@ -29,27 +35,38 @@ fn compile_file(path: String) -> Result<(), Box> { } codegen.emit_epilogue()?; - fs::write("out.s", codegen.get_output())?; + // TODO: handle error + fs::write("out.s", codegen.get_output()).unwrap(); + + // TODO: stop on nasm/gcc error Command::new("nasm") .args(["-f", "elf64", "-o", "out.o", "out.s"]) - .status()?; + .status() + .unwrap(); // TODO: drop libc entirely Command::new("./musl-1.2.4/root/bin/musl-gcc") .args(["-static", "-o", "out", "out.o"]) - .status()?; + .status() + .unwrap(); Ok(()) } -fn main() -> Result<(), Box> { +fn main() { let mut args = env::args(); - let path = args.nth(1).unwrap(); + let _ = args.next(); + + let path = match args.next() { + Some(x) => x, + None => { + eprintln!("\x1b[91mERROR\x1b[0m: expected an argument"); + process::exit(1); + } + }; if let Err(err) = compile_file(path) { eprintln!("{}", err); process::exit(1); } - - Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 42abd4d..7f0ba5f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,3 @@ -use std::error::Error; - use crate::tokenizer::{Token, TokenType, ZernError, error}; #[derive(Debug, Clone)] @@ -75,7 +73,7 @@ impl Parser { } } - pub fn parse(mut self) -> Result, Box> { + pub fn parse(mut self) -> Result, ZernError> { let mut statements = vec![]; while !self.eof() { statements.push(self.declaration()?); @@ -83,7 +81,7 @@ impl Parser { Ok(statements) } - fn declaration(&mut self) -> Result> { + fn declaration(&mut self) -> Result { if !self.is_inside_function { if self.match_token(&[TokenType::KeywordFunc]) { return self.func_declaration(); @@ -103,7 +101,7 @@ impl Parser { } // TOOD: parse return type - fn func_declaration(&mut self) -> Result> { + fn func_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected function name")?; self.consume(TokenType::LeftBracket, "expected '[' after function name")?; @@ -136,7 +134,7 @@ impl Parser { }) } - fn let_declaration(&mut self) -> Result> { + fn let_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected variable name")?; self.consume(TokenType::Colon, "expected ':' after variable name")?; let var_type = self.consume(TokenType::Identifier, "expected variable type")?; @@ -149,7 +147,7 @@ impl Parser { }) } - fn block(&mut self) -> Result> { + fn block(&mut self) -> Result { self.consume(TokenType::Indent, "expected an indent")?; let mut statements = vec![]; @@ -160,7 +158,7 @@ impl Parser { Ok(Stmt::Block(statements)) } - fn statement(&mut self) -> Result> { + fn statement(&mut self) -> Result { if self.match_token(&[TokenType::KeywordIf]) { self.if_statement() } else if self.match_token(&[TokenType::KeywordWhile]) { @@ -172,11 +170,11 @@ impl Parser { } } - fn return_statement(&mut self) -> Result> { + fn return_statement(&mut self) -> Result { Ok(Stmt::Return(self.expression()?)) } - fn if_statement(&mut self) -> Result> { + fn if_statement(&mut self) -> Result { let condition = self.expression()?; let then_branch = self.block()?; let else_branch = if self.match_token(&[TokenType::KeywordElse]) { @@ -195,7 +193,7 @@ impl Parser { }) } - fn while_statement(&mut self) -> Result> { + fn while_statement(&mut self) -> Result { let condition = self.expression()?; let body = self.block()?; Ok(Stmt::While { @@ -204,11 +202,11 @@ impl Parser { }) } - fn expression(&mut self) -> Result> { + fn expression(&mut self) -> Result { self.assignment() } - fn assignment(&mut self) -> Result> { + fn assignment(&mut self) -> Result { let expr = self.pipe()?; if self.match_token(&[TokenType::Equal]) { @@ -227,7 +225,7 @@ impl Parser { Ok(expr) } - fn pipe(&mut self) -> Result> { + fn pipe(&mut self) -> Result { let mut expr = self.logical_or()?; while self.match_token(&[TokenType::Pipe]) { @@ -257,7 +255,7 @@ impl Parser { Ok(expr) } - fn logical_or(&mut self) -> Result> { + fn logical_or(&mut self) -> Result { let mut expr = self.logical_and()?; while self.match_token(&[TokenType::Or]) { @@ -273,7 +271,7 @@ impl Parser { Ok(expr) } - fn logical_and(&mut self) -> Result> { + fn logical_and(&mut self) -> Result { let mut expr = self.equality()?; while self.match_token(&[TokenType::And]) { @@ -289,7 +287,7 @@ impl Parser { Ok(expr) } - fn equality(&mut self) -> Result> { + fn equality(&mut self) -> Result { let mut expr = self.comparison()?; while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) { @@ -305,7 +303,7 @@ impl Parser { Ok(expr) } - fn comparison(&mut self) -> Result> { + fn comparison(&mut self) -> Result { let mut expr = self.term()?; while self.match_token(&[ @@ -326,7 +324,7 @@ impl Parser { Ok(expr) } - fn term(&mut self) -> Result> { + fn term(&mut self) -> Result { let mut expr = self.factor()?; while self.match_token(&[TokenType::Plus, TokenType::Minus, TokenType::Xor]) { @@ -342,7 +340,7 @@ impl Parser { Ok(expr) } - fn factor(&mut self) -> Result> { + fn factor(&mut self) -> Result { let mut expr = self.unary()?; while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Mod]) { @@ -358,7 +356,7 @@ impl Parser { Ok(expr) } - fn unary(&mut self) -> Result> { + fn unary(&mut self) -> Result { if self.match_token(&[TokenType::Bang, TokenType::Minus]) { let op = self.previous().clone(); let right = self.unary()?; @@ -371,7 +369,7 @@ impl Parser { self.call() } - fn call(&mut self) -> Result> { + fn call(&mut self) -> Result { let mut expr = self.primary()?; while self.match_token(&[TokenType::LeftParen]) { @@ -397,7 +395,7 @@ impl Parser { Ok(expr) } - fn primary(&mut self) -> Result> { + fn primary(&mut self) -> Result { if self.match_token(&[TokenType::Number, TokenType::String]) { Ok(Expr::Literal(self.previous().clone())) } else if self.match_token(&[TokenType::LeftParen]) { @@ -411,7 +409,7 @@ impl Parser { } } - fn consume(&mut self, token_type: TokenType, message: &str) -> Result> { + fn consume(&mut self, token_type: TokenType, message: &str) -> Result { if self.check(&token_type) { Ok(self.advance().clone()) } else { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 1d635bf..4ff4222 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -1,4 +1,4 @@ -use std::{cmp::Ordering, error::Error, fmt}; +use std::{cmp::Ordering, fmt}; #[derive(Debug, Clone, PartialEq)] pub enum TokenType { @@ -59,10 +59,10 @@ impl std::error::Error for ZernError {} macro_rules! error { ($loc:expr, $msg:expr) => { - Err(Box::new(ZernError { + Err(ZernError { loc: $loc.clone(), message: $msg.into(), - })) + }) }; } @@ -115,7 +115,7 @@ impl Tokenizer { } } - pub fn tokenize(mut self) -> Result, Box> { + pub fn tokenize(mut self) -> Result, ZernError> { while !self.eof() { self.start = self.current; self.scan_token()?; @@ -129,7 +129,7 @@ impl Tokenizer { Ok(self.tokens) } - fn scan_token(&mut self) -> Result<(), Box> { + fn scan_token(&mut self) -> Result<(), ZernError> { match self.advance() { '(' => self.add_token(TokenType::LeftParen), ')' => self.add_token(TokenType::RightParen), @@ -224,7 +224,7 @@ impl Tokenizer { Ok(()) } - fn handle_indentation(&mut self) -> Result<(), Box> { + fn handle_indentation(&mut self) -> Result<(), ZernError> { if self.peek() == '\n' { return Ok(()); }