Prettier error handling
This commit is contained in:
parent
8818536717
commit
a225105f09
33
src/brian.rs
33
src/brian.rs
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
|
error::Error,
|
||||||
|
fmt::Display,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,6 +290,25 @@ pub enum ProgramError {
|
||||||
TapeSizeExceededLimit,
|
TapeSizeExceededLimit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ProgramError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
ProgramError::DataPointerUnderflow => "data pointer underflow",
|
||||||
|
ProgramError::IntegerOverflow => "integer overflow",
|
||||||
|
ProgramError::IntegerUnderflow => "integer underflow",
|
||||||
|
ProgramError::InputReadError => "input read error",
|
||||||
|
ProgramError::UnmatchedOpeningBracket => "unmatched `[`",
|
||||||
|
ProgramError::UnmatchedClosingBracket => "unmatched `]`",
|
||||||
|
ProgramError::TapeSizeExceededLimit => "tape size exceeded",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Error for ProgramError {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
/// An error that occurred while the interpreter was being run start-to-end all in one go
|
/// An error that occurred while the interpreter was being run start-to-end all in one go
|
||||||
pub enum InterpretError {
|
pub enum InterpretError {
|
||||||
|
@ -297,6 +318,18 @@ pub enum InterpretError {
|
||||||
OutputWriteError,
|
OutputWriteError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for InterpretError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
InterpretError::ProgramError(e) => write!(f, "program error: {}", e),
|
||||||
|
InterpretError::EndOfInput => write!(f, "unexpected end of input"),
|
||||||
|
InterpretError::OutputBufferFull => write!(f, "output buffer full"),
|
||||||
|
InterpretError::OutputWriteError => write!(f, "output write error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Error for InterpretError {}
|
||||||
|
|
||||||
impl From<ProgramError> for InterpretError {
|
impl From<ProgramError> for InterpretError {
|
||||||
fn from(e: ProgramError) -> Self {
|
fn from(e: ProgramError) -> Self {
|
||||||
InterpretError::ProgramError(e)
|
InterpretError::ProgramError(e)
|
||||||
|
|
33
src/error.rs
33
src/error.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::{io, ops::Range};
|
use std::{fmt::Display, io, ops::Range};
|
||||||
|
|
||||||
use crate::{brian::InterpretError, lexer::Token};
|
use crate::{brian::InterpretError, lexer::Token};
|
||||||
|
|
||||||
|
@ -36,6 +36,37 @@ impl Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Error at range {}-{}: {}",
|
||||||
|
self.span.start, self.span.end, self.kind
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
|
impl Display for ErrorKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ErrorKind::SyntaxError(desc) => write!(f, "syntax error: {}", desc),
|
||||||
|
ErrorKind::UnexpectedEof => write!(f, "unexpected end of file"),
|
||||||
|
ErrorKind::UnexpectedToken(token) => write!(f, "unexpected token {:?}", token),
|
||||||
|
ErrorKind::InvalidIdentifier => write!(f, "invalid identifier"),
|
||||||
|
ErrorKind::UnknownVariable(name) => write!(f, "unknown identifier \"{}\"", name),
|
||||||
|
ErrorKind::MeloVariable(name) => write!(f, "banned variable \"{}\"", name),
|
||||||
|
ErrorKind::TypeError(desc) => write!(f, "type error: {}", desc),
|
||||||
|
ErrorKind::TopLevelBreak => write!(f, "can only `break` out of a loop"),
|
||||||
|
ErrorKind::BfInterpretError(err) => write!(f, "brainfuck error: {}", err),
|
||||||
|
// TODO: give concrete numbers here.
|
||||||
|
ErrorKind::MismatchedArgumentError => write!(f, "wrong number of function arguments"),
|
||||||
|
ErrorKind::MissingLhs => write!(f, "missing expression before binary operation"),
|
||||||
|
ErrorKind::IOError(err) => write!(f, "I/O error: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(e: io::Error) -> Self {
|
fn from(e: io::Error) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
19
src/repl.rs
19
src/repl.rs
|
@ -1,4 +1,3 @@
|
||||||
use logos::Source;
|
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
|
|
||||||
use crate::{interpret::ExecEnv, parser::Parser};
|
use crate::{interpret::ExecEnv, parser::Parser};
|
||||||
|
@ -10,7 +9,13 @@ pub fn repl(ast_print: bool) {
|
||||||
let readline = rl.readline(":: ");
|
let readline = rl.readline(":: ");
|
||||||
match readline {
|
match readline {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
if &line == "exit" {
|
// NOTE(Alex): `readline()` leaves a newline at the
|
||||||
|
// end of the string if stdin is connected to a file
|
||||||
|
// or unsupported terminal; this can interfere with
|
||||||
|
// error printing.
|
||||||
|
let line = line.trim_end();
|
||||||
|
|
||||||
|
if line == "exit" {
|
||||||
println!("bye");
|
println!("bye");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -23,16 +28,10 @@ pub fn repl(ast_print: bool) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(e) = value {
|
if let Err(e) = value {
|
||||||
println!(
|
println!("{}", e);
|
||||||
"Error `{:?}` occurred at span: {:?} = `{:?}`",
|
|
||||||
e.kind,
|
|
||||||
e.span.clone(),
|
|
||||||
line.slice(e.span.clone())
|
|
||||||
);
|
|
||||||
|
|
||||||
println!(" | {}", line);
|
println!(" | {}", line);
|
||||||
println!(
|
println!(
|
||||||
" {}{}-- Here",
|
" {}{}",
|
||||||
" ".repeat(e.span.start),
|
" ".repeat(e.span.start),
|
||||||
"^".repeat((e.span.end - e.span.start).max(1))
|
"^".repeat((e.span.end - e.span.start).max(1))
|
||||||
);
|
);
|
||||||
|
|
|
@ -126,7 +126,7 @@ impl Value {
|
||||||
match self {
|
match self {
|
||||||
Value::Int(i) => Ok(i),
|
Value::Int(i) => Ok(i),
|
||||||
_ => Err(Error {
|
_ => Err(Error {
|
||||||
kind: ErrorKind::TypeError(format!("Expected int, got {}", self)),
|
kind: ErrorKind::TypeError(format!("expected int, got {}", self)),
|
||||||
span: span.clone(),
|
span: span.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue