replace thiserror with quick_error

This commit is contained in:
2024-11-26 21:47:38 -07:00
parent 51109ee4bb
commit 2372f0c61a
7 changed files with 132 additions and 183 deletions

28
Cargo.lock generated
View File

@@ -404,6 +404,12 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.37" version = "1.0.37"
@@ -565,8 +571,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"quick-error",
"rust_decimal", "rust_decimal",
"thiserror",
] ]
[[package]] [[package]]
@@ -603,26 +609,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.8.0" version = "1.8.0"

View File

@@ -3,13 +3,10 @@ name = "stationlang"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[profile.dev]
panic = "unwind"
[dependencies] [dependencies]
clap = { version = "^4.5", features = ["derive"] } clap = { version = "^4.5", features = ["derive"] }
quick-error = "2.0.1"
rust_decimal = "1.36.0" rust_decimal = "1.36.0"
thiserror = { version = "^2.0" }
[dev-dependencies] [dev-dependencies]
anyhow = { version = "^1.0", features = ["backtrace"] } anyhow = { version = "^1.0", features = ["backtrace"] }

View File

@@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly" channel = "stable"
components = ["rustfmt", "clippy"] components = ["rustfmt", "clippy"]

View File

@@ -1,5 +1,3 @@
use thiserror::Error;
use crate::parser::tree_node::*; use crate::parser::tree_node::*;
use crate::parser::Parser as ASTParser; use crate::parser::Parser as ASTParser;
use std::collections::HashMap; use std::collections::HashMap;
@@ -9,14 +7,21 @@ use std::io::Write;
/// Represents the return keyword. Used as a variable name for the register. /// Represents the return keyword. Used as a variable name for the register.
const RETURN: &'static str = "ret"; const RETURN: &'static str = "ret";
#[derive(Error, Debug)] quick_error! {
#[derive(Debug)]
pub enum CompileError { pub enum CompileError {
#[error(transparent)] ParseError(err: crate::parser::ParseError) {
ParseError(#[from] crate::parser::ParseError), from()
#[error("A fatal error has occurred with the compiler. Scope could not be found.")] display("Parse error: {}", err)
ScopeError, }
#[error(transparent)] ScopeError {
WriteError(#[from] std::io::Error), display("A fatal error has occurred with the compiler. Scope could not be found.")
}
WriteError(err: std::io::Error) {
from()
display("Write error: {}", err)
}
}
} }
pub struct Compiler<'a> { pub struct Compiler<'a> {

View File

@@ -1,4 +1,5 @@
#![feature(error_generic_member_access)] #[macro_use]
extern crate quick_error;
mod compiler; mod compiler;
mod parser; mod parser;
@@ -21,16 +22,26 @@ macro_rules! boxed {
}; };
} }
#[derive(Debug, thiserror::Error)] quick_error! {
#[derive(Debug)]
enum StationlangError { enum StationlangError {
#[error(transparent)] TokenizerError(err: TokenizerError) {
TokenizerError(#[from] TokenizerError), from()
#[error(transparent)] display("Tokenizer error: {}", err)
ParserError(#[from] parser::ParseError), }
#[error(transparent)] ParserError(err: parser::ParseError) {
CompileError(#[from] compiler::CompileError), from()
#[error(transparent)] display("Parser error: {}", err)
IoError(#[from] std::io::Error), }
CompileError(err: compiler::CompileError) {
from()
display("Compile error: {}", err)
}
IoError(err: std::io::Error) {
from()
display("IO error: {}", err)
}
}
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]

View File

@@ -8,31 +8,33 @@ use crate::{
Tokenizer, TokenizerBuffer, TokenizerError, Tokenizer, TokenizerBuffer, TokenizerError,
}, },
}; };
use std::{ use std::io::SeekFrom;
backtrace::{self, Backtrace},
io::SeekFrom,
};
use thiserror::Error;
use tree_node::*; use tree_node::*;
#[derive(Debug, Error)] quick_error! {
#[derive(Debug)]
pub enum ParseError { pub enum ParseError {
#[error(transparent)] TokenizerError(err: TokenizerError) {
TokenizerError(#[from] TokenizerError), from()
#[error("Unexpected token\n\nLine: {0}, Column: {1}\nToken: {2}\n", token.line, token.column, token.token_type)] display("Tokenizer Error: {}", err)
UnexpectedToken { source(err)
token: Token, }
#[backtrace] UnexpectedToken(token: Token) {
backtrace: std::backtrace::Backtrace, display("Unexpected token: {:?}", token)
}, }
#[error("Duplicated Identifer\n\nLine: {0}, Column: {1}\nToken: {2}\n", token.line, token.column, token.token_type)] DuplicateIdentifier(token: Token) {
DuplicateIdentifier { token: Token }, display("Duplicate identifier: {:?}", token)
#[error("Invalid Syntax\n\nLine: {0}, Column: {1}\nReason: {reason}", token.line, token.column)] }
InvalidSyntax { token: Token, reason: String }, InvalidSyntax(token: Token, reason: String) {
#[error("This keyword is not yet implemented\n\nLine: {0}, Column: {1}\nToken: {2}\n", token.line, token.column, token.token_type)] display("Invalid syntax: {:?}, Reason: {}", token, reason)
UnsupportedKeyword { token: Token }, }
#[error("Unexpected EOF")] UnsupportedKeyword(token: Token) {
UnexpectedEOF, display("Unsupported keyword: {:?}", token)
}
UnexpectedEOF {
display("Unexpected EOF")
}
}
} }
macro_rules! self_matches_peek { macro_rules! self_matches_peek {
@@ -57,22 +59,14 @@ macro_rules! extract_token_data {
($token:ident, $pattern:pat, $extraction:expr) => { ($token:ident, $pattern:pat, $extraction:expr) => {
match $token.token_type { match $token.token_type {
$pattern => $extraction, $pattern => $extraction,
_ => { _ => return Err(ParseError::UnexpectedToken($token.clone())),
return Err(ParseError::UnexpectedToken {
token: $token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
})
}
} }
}; };
($token:expr, $pattern:pat, $extraction:expr) => { ($token:expr, $pattern:pat, $extraction:expr) => {
match $token.token_type { match $token.token_type {
$pattern => $extraction, $pattern => $extraction,
_ => { _ => {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken($token.clone()));
token: $token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
})
} }
} }
}; };
@@ -180,9 +174,7 @@ impl Parser {
Keyword::Else Keyword::Else
) => ) =>
{ {
return Err(ParseError::UnsupportedKeyword { return Err(ParseError::UnsupportedKeyword(current_token.clone()))
token: current_token.clone(),
})
} }
// match declarations with a `let` keyword // match declarations with a `let` keyword
@@ -218,10 +210,7 @@ impl Parser {
TokenType::Symbol(Symbol::LParen) => Expression::PriorityExpression(self.priority()?), TokenType::Symbol(Symbol::LParen) => Expression::PriorityExpression(self.priority()?),
_ => { _ => {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
})
} }
}); });
@@ -265,10 +254,7 @@ impl Parser {
{ {
self.invocation().map(Expression::InvocationExpression) self.invocation().map(Expression::InvocationExpression)
} }
_ => Err(ParseError::UnexpectedToken { _ => Err(ParseError::UnexpectedToken(current_token.clone())),
token: current_token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
}),
} }
} }
@@ -281,10 +267,7 @@ impl Parser {
let current_token = token_from_option!(self.get_next()?).clone(); let current_token = token_from_option!(self.get_next()?).clone();
if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token));
token: current_token.clone(),
backtrace: Backtrace::capture(),
});
} }
self.assign_next()?; self.assign_next()?;
@@ -313,10 +296,7 @@ impl Parser {
| Expression::Negation(_) // -1 + 2 | Expression::Negation(_) // -1 + 2
=> {} => {}
_ => { _ => {
return Err(ParseError::InvalidSyntax { return Err(ParseError::InvalidSyntax(current_token.clone(), String::from("Invalid expression for binary operation")))
token: current_token.clone(),
reason: "Invalid expression for binary operation".to_owned(),
})
} }
} }
@@ -338,10 +318,10 @@ impl Parser {
// validate the vectors and make sure operators.len() == expressions.len() - 1 // validate the vectors and make sure operators.len() == expressions.len() - 1
if operators.len() != expressions.len() - 1 { if operators.len() != expressions.len() - 1 {
return Err(ParseError::InvalidSyntax { return Err(ParseError::InvalidSyntax(
token: current_token.clone(), current_token.clone(),
reason: "Invalid number of operators".to_owned(), String::from("Invalid number of operators"),
}); ));
} }
// Every time we find a valid operator, we pop 2 off the expressions and add one back. // Every time we find a valid operator, we pop 2 off the expressions and add one back.
@@ -437,10 +417,10 @@ impl Parser {
// Ensure there is only one expression left in the expressions vector, and no operators left // Ensure there is only one expression left in the expressions vector, and no operators left
if expressions.len() != 1 || !operators.is_empty() { if expressions.len() != 1 || !operators.is_empty() {
return Err(ParseError::InvalidSyntax { return Err(ParseError::InvalidSyntax(
token: current_token.clone(), current_token.clone(),
reason: "Invalid number of operators".to_owned(), String::from("Invalid number of operators"),
}); ));
} }
// Edge case. If the current token is a semi-colon, RParen, we need to set current token to the previous token // Edge case. If the current token is a semi-colon, RParen, we need to set current token to the previous token
@@ -461,10 +441,7 @@ impl Parser {
fn priority(&mut self) -> Result<Box<Expression>, ParseError> { fn priority(&mut self) -> Result<Box<Expression>, ParseError> {
let current_token = token_from_option!(self.current_token); let current_token = token_from_option!(self.current_token);
if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
});
} }
self.assign_next()?; self.assign_next()?;
@@ -472,10 +449,7 @@ impl Parser {
let current_token = token_from_option!(self.get_next()?); let current_token = token_from_option!(self.get_next()?);
if !token_matches!(current_token, TokenType::Symbol(Symbol::RParen)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::RParen)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
});
} }
Ok(boxed!(expression)) Ok(boxed!(expression))
@@ -491,10 +465,7 @@ impl Parser {
// Ensure the next token is a left parenthesis // Ensure the next token is a left parenthesis
let current_token = token_from_option!(self.get_next()?); let current_token = token_from_option!(self.get_next()?);
if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: std::backtrace::Backtrace::capture(),
});
} }
let mut arguments = Vec::<Expression>::new(); let mut arguments = Vec::<Expression>::new();
@@ -508,10 +479,10 @@ impl Parser {
let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?;
if let Expression::BlockExpression(_) = expression { if let Expression::BlockExpression(_) = expression {
return Err(ParseError::InvalidSyntax { return Err(ParseError::InvalidSyntax(
token: current_token, current_token,
reason: "Block expressions are not allowed in function invocations".to_owned(), String::from("Block expressions are not allowed in function invocations"),
}); ));
} }
arguments.push(expression); arguments.push(expression);
@@ -520,10 +491,9 @@ impl Parser {
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
{ {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(
token: token_from_option!(self.get_next()?).clone(), token_from_option!(self.get_next()?).clone(),
backtrace: backtrace::Backtrace::capture(), ));
});
} }
// edge case: if the next token is not a right parenthesis, increment the current token // edge case: if the next token is not a right parenthesis, increment the current token
@@ -547,10 +517,7 @@ impl Parser {
// sanity check: make sure the current token is a left brace // sanity check: make sure the current token is a left brace
if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: backtrace::Backtrace::capture(),
});
} }
while !self_matches_peek!( while !self_matches_peek!(
@@ -580,10 +547,7 @@ impl Parser {
fn declaration(&mut self) -> Result<Expression, ParseError> { fn declaration(&mut self) -> Result<Expression, ParseError> {
let current_token = token_from_option!(self.current_token); let current_token = token_from_option!(self.current_token);
if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) { if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: backtrace::Backtrace::capture(),
});
} }
let identifier = extract_token_data!( let identifier = extract_token_data!(
token_from_option!(self.get_next()?), token_from_option!(self.get_next()?),
@@ -594,10 +558,7 @@ impl Parser {
let current_token = token_from_option!(self.get_next()?).clone(); let current_token = token_from_option!(self.get_next()?).clone();
if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token,
backtrace: backtrace::Backtrace::capture(),
});
} }
self.assign_next()?; self.assign_next()?;
@@ -606,10 +567,7 @@ impl Parser {
// make sure the next token is a semi-colon // make sure the next token is a semi-colon
let current_token = token_from_option!(self.get_next()?); let current_token = token_from_option!(self.get_next()?);
if !token_matches!(current_token, TokenType::Symbol(Symbol::Semicolon)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::Semicolon)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: backtrace::Backtrace::capture(),
});
} }
Ok(Expression::DeclarationExpression( Ok(Expression::DeclarationExpression(
@@ -623,12 +581,7 @@ impl Parser {
let literal = match current_token.token_type { let literal = match current_token.token_type {
TokenType::Number(ref num) => Literal::Number(num.clone()), TokenType::Number(ref num) => Literal::Number(num.clone()),
TokenType::String(ref string) => Literal::String(string.clone()), TokenType::String(ref string) => Literal::String(string.clone()),
_ => { _ => return Err(ParseError::UnexpectedToken(current_token.clone())),
return Err(ParseError::UnexpectedToken {
token: current_token.clone(),
backtrace: backtrace::Backtrace::capture(),
})
}
}; };
Ok(literal) Ok(literal)
@@ -638,10 +591,7 @@ impl Parser {
let current_token = token_from_option!(self.current_token); let current_token = token_from_option!(self.current_token);
// Sanify check that the current token is a `fn` keyword // Sanify check that the current token is a `fn` keyword
if !self_matches_current!(self, TokenType::Keyword(Keyword::Fn)) { if !self_matches_current!(self, TokenType::Keyword(Keyword::Fn)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: Backtrace::capture(),
});
} }
let fn_ident = extract_token_data!( let fn_ident = extract_token_data!(
@@ -653,10 +603,7 @@ impl Parser {
// make sure next token is a left parenthesis // make sure next token is a left parenthesis
let current_token = token_from_option!(self.get_next()?); let current_token = token_from_option!(self.get_next()?);
if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: Backtrace::capture(),
});
} }
let mut arguments = Vec::<String>::new(); let mut arguments = Vec::<String>::new();
@@ -672,9 +619,7 @@ impl Parser {
extract_token_data!(current_token, TokenType::Identifier(ref id), id.clone()); extract_token_data!(current_token, TokenType::Identifier(ref id), id.clone());
if arguments.contains(&argument) { if arguments.contains(&argument) {
return Err(ParseError::DuplicateIdentifier { return Err(ParseError::DuplicateIdentifier(current_token.clone()));
token: current_token.clone(),
});
} }
arguments.push(argument); arguments.push(argument);
@@ -683,10 +628,9 @@ impl Parser {
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
{ {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(
token: token_from_option!(self.get_next()?).clone(), token_from_option!(self.get_next()?).clone(),
backtrace: Backtrace::capture(), ));
});
} }
// edge case: if the next token is not a right parenthesis, increment the current token // edge case: if the next token is not a right parenthesis, increment the current token
@@ -701,10 +645,7 @@ impl Parser {
// make sure the next token is a left brace // make sure the next token is a left brace
let current_token = token_from_option!(self.get_next()?); let current_token = token_from_option!(self.get_next()?);
if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) {
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken(current_token.clone()));
token: current_token.clone(),
backtrace: Backtrace::capture(),
});
}; };
Ok(FunctionExpression { Ok(FunctionExpression {

View File

@@ -1,5 +1,6 @@
pub mod token; pub mod token;
use crate::boxed;
use rust_decimal::Decimal; use rust_decimal::Decimal;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
@@ -7,23 +8,31 @@ use std::{
io::{BufReader, Cursor, Read, Seek, SeekFrom}, io::{BufReader, Cursor, Read, Seek, SeekFrom},
path::PathBuf, path::PathBuf,
}; };
use thiserror::Error;
use token::{Keyword, Number, Symbol, Token, TokenType}; use token::{Keyword, Number, Symbol, Token, TokenType};
use crate::boxed; quick_error! {
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum TokenizerError { pub enum TokenizerError {
#[error("IO Error: {0}")] IOError(err: std::io::Error) {
IOError(#[from] std::io::Error), from()
#[error("Number Parse Error \"{0}\"\nLine: {1}, Column: {2}")] display("IO Error: {}", err)
NumberParseError(std::num::ParseIntError, usize, usize), source(err)
#[error("Decimal Parse Error \"{0}\"\nLine: {1}, Column: {2}")] }
DecimalParseError(rust_decimal::Error, usize, usize), NumberParseError(err: std::num::ParseIntError, line: usize, column: usize) {
#[error("Unknown Symbol \"{0}\"\nLine: {1}, Column: {2}")] display("Number Parse Error: {}\nLine: {}, Column: {}", err, line, column)
UnknownSymbolError(char, usize, usize), source(err)
#[error("Unknown Keyword or Identifier \"{0}\"\nLine: {1}, Column: {2}")] }
UnknownKeywordOrIdentifierError(String, usize, usize), DecimalParseError(err: rust_decimal::Error, line: usize, column: usize) {
display("Decimal Parse Error: {}\nLine: {}, Column: {}", err, line, column)
source(err)
}
UnknownSymbolError(char: char, line: usize, column: usize) {
display("Unknown Symbol: {}\nLine: {}, Column: {}", char, line, column)
}
UnknownKeywordOrIdentifierError(val: String, line: usize, column: usize) {
display("Unknown Keyword or Identifier: {}\nLine: {}, Column: {}", val, line, column)
}
}
} }
pub trait Tokenize: Read + Seek {} pub trait Tokenize: Read + Seek {}