sexp: move error defs to a module

pull/21/head
Ondřej Hruška 4 years ago
parent 6dfe22152c
commit 0fd1c9980b
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 68
      lib/spanned_sexp/src/error.rs
  2. 78
      lib/spanned_sexp/src/lib.rs
  3. 1
      lib/spanned_sexp/src/test.rs

@ -0,0 +1,68 @@
use std::{cmp, fmt};
/// The representation of an s-expression parse error.
pub struct Error {
/// The error message.
pub message: &'static str,
/// The line number on which the error occurred.
pub line: usize,
/// The column number on which the error occurred.
pub column: usize,
/// The index in the given string which caused the error.
pub index: usize,
}
/// Since errors are the uncommon case, they're boxed. This keeps the size of
/// structs down, which helps performance in the common case.
///
/// For example, an `ERes<()>` becomes 8 bytes, instead of the 24 bytes it would
/// be if `Err` were unboxed.
type Err = Box<Error>;
/// Helps clean up type signatures, but shouldn't be exposed to the outside
/// world.
pub(crate) type ERes<T> = Result<T, Err>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}:{}: {}", self.line, self.column, self.message)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self)
}
}
impl std::error::Error for Error {}
pub(crate) fn get_line_and_column(s: &str, pos: usize) -> (usize, usize) {
let mut line: usize = 1;
let mut col: isize = -1;
for c in s.chars().take(pos + 1) {
if c == '\n' {
line += 1;
col = -1;
} else {
col += 1;
}
}
(line, cmp::max(col, 0) as usize)
}
#[cold]
fn err_impl(message: &'static str, s: &str, pos: &usize) -> Err {
let (line, column) = get_line_and_column(s, *pos);
Box::new(Error {
message: message,
line: line,
column: column,
index: *pos,
})
}
/// Build an error with span information
pub(crate) fn err<T>(message: &'static str, s: &str, pos: &usize) -> ERes<T> {
Err(err_impl(message, s, pos))
}

@ -9,14 +9,17 @@
extern crate log; extern crate log;
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp;
use std::error;
use std::fmt; use std::fmt;
use std::str::{self, FromStr}; use std::str::{self, FromStr};
pub use error::Error;
use error::{ERes, err};
#[cfg(test)] #[cfg(test)]
mod test; mod test;
mod error;
/// A single data element in an s-expression. Floats are excluded to ensure /// A single data element in an s-expression. Floats are excluded to ensure
/// atoms may be used as keys in ordered and hashed data structures. /// atoms may be used as keys in ordered and hashed data structures.
/// ///
@ -38,75 +41,6 @@ pub enum Sexp {
List(Vec<Sexp>), List(Vec<Sexp>),
} }
/// The representation of an s-expression parse error.
pub struct Error {
/// The error message.
pub message: &'static str,
/// The line number on which the error occurred.
pub line: usize,
/// The column number on which the error occurred.
pub column: usize,
/// The index in the given string which caused the error.
pub index: usize,
}
impl error::Error for Error {
fn description(&self) -> &str { self.message }
fn cause(&self) -> Option<&dyn error::Error> { None }
}
/// Since errors are the uncommon case, they're boxed. This keeps the size of
/// structs down, which helps performance in the common case.
///
/// For example, an `ERes<()>` becomes 8 bytes, instead of the 24 bytes it would
/// be if `Err` were unboxed.
type Err = Box<Error>;
/// Helps clean up type signatures, but shouldn't be exposed to the outside
/// world.
type ERes<T> = Result<T, Err>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}:{}: {}", self.line, self.column, self.message)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self)
}
}
fn get_line_and_column(s: &str, pos: usize) -> (usize, usize) {
let mut line: usize = 1;
let mut col: isize = -1;
for c in s.chars().take(pos + 1) {
if c == '\n' {
line += 1;
col = -1;
} else {
col += 1;
}
}
(line, cmp::max(col, 0) as usize)
}
#[cold]
fn err_impl(message: &'static str, s: &str, pos: &usize) -> Err {
let (line, column) = get_line_and_column(s, *pos);
Box::new(Error {
message: message,
line: line,
column: column,
index: *pos,
})
}
fn err<T>(message: &'static str, s: &str, pos: &usize) -> ERes<T> {
Err(err_impl(message, s, pos))
}
fn atom_of_string(s: String) -> Atom { fn atom_of_string(s: String) -> Atom {
match FromStr::from_str(&s) { match FromStr::from_str(&s) {
@ -281,7 +215,7 @@ pub fn parse(s: &str) -> Result<Sexp, Box<Error>> {
} }
// TODO: Pretty print in lisp convention, instead of all on the same line, // TODO: Pretty print in lisp convention, instead of all on the same line,
// packed as tightly as possible. It's kinda ugly. // packed as tightly as possible. It's kinda ugly.
fn is_num_string(s: &str) -> bool { fn is_num_string(s: &str) -> bool {
let x: Result<i64, _> = FromStr::from_str(&s); let x: Result<i64, _> = FromStr::from_str(&s);

@ -1,4 +1,5 @@
use super::*; use super::*;
use super::error::get_line_and_column;
#[test] #[test]
fn test_hello_world() { fn test_hello_world() {

Loading…
Cancel
Save