remove boxed errors
This commit is contained in:
@@ -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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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::<Vec<String>>()
|
||||
.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(())
|
||||
|
||||
Reference in New Issue
Block a user