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