Unify error types ♾

This commit is contained in:
Laurenz 2019-12-04 20:20:02 +01:00
parent 9fb31defd0
commit f72b1505be
14 changed files with 68 additions and 97 deletions

View File

@ -64,14 +64,14 @@ impl<'a> ArgParser<'a> {
if self.positional_index == self.args.positional.len() {
Ok(())
} else {
pr!("unexpected argument");
error!(unexpected_argument);
}
}
/// Covert an option to a result with an error on `None`.
fn expected<T>(val: Option<Spanned<T::Output>>) -> ParseResult<Spanned<T::Output>>
where T: Argument<'a> {
val.ok_or_else(|| pr!(@"expected {}", T::ERROR_MESSAGE))
val.ok_or_else(|| error!(@"expected {}", T::ERROR_MESSAGE))
}
}
@ -93,10 +93,10 @@ macro_rules! arg {
const ERROR_MESSAGE: &'static str = $err;
fn from_expr(expr: &'a Spanned<Expression>) -> ParseResult<Spanned<Self::Output>> {
#[allow(unreachable_patterns)]
#[allow(unreachable_code)]
match &expr.val {
$wanted => Ok(Spanned::new($converted, expr.span)),
_ => pr!("expected {}", $err),
_ => error!("expected {}", $err),
}
}
}
@ -179,7 +179,7 @@ impl AlignmentKey {
Right if horizontal => axes.right(),
Top if !horizontal => axes.top(),
Bottom if !horizontal => axes.bottom(),
_ => lr!(
_ => error!(
"invalid alignment `{}` for {} axis",
format!("{:?}", self).to_lowercase(),
format!("{:?}", axis).to_lowercase()

View File

@ -111,7 +111,7 @@ macro_rules! function {
macro_rules! parse {
(forbidden: $body:expr) => {
if $body.is_some() {
pr!("unexpected body");
error!("unexpected body");
}
};
@ -127,23 +127,16 @@ macro_rules! parse {
if let Some(body) = $body {
$crate::syntax::parse(body, $ctx)?
} else {
pr!("expected body");
error!("expected body");
}
)
}
/// Early-return with a formatted parsing error or yield
/// an error expression without returning when prefixed with `@`.
/// Early-return with a formatted typesetting error or construct an error
/// expression without returning when prefixed with `@`.
#[macro_export]
macro_rules! pr {
(@$($tts:tt)*) => ($crate::syntax::ParseError::new(format!($($tts)*)));
($($tts:tt)*) => (return Err(pr!(@$($tts)*)););
}
/// Early-return with a formatted layouting error or yield
/// an error expression without returning when prefixed with `@`.
#[macro_export]
macro_rules! lr {
(@$($tts:tt)*) => ($crate::layout::LayoutError::new(format!($($tts)*)));
($($tts:tt)*) => (return Err(lr!(@$($tts)*)););
macro_rules! error {
(@unexpected_argument) => (error!(@"unexpected argument"));
(@$($tts:tt)*) => ($crate::TypesetError::with_message(format!($($tts)*)));
($($tts:tt)*) => (return Err(error!(@$($tts)*)););
}

View File

@ -16,7 +16,7 @@ pub mod prelude {
pub use super::args::*;
pub use super::{Scope, ParseFunc, LayoutFunc, Command, Commands};
pub use crate::syntax::{SyntaxTree, FuncHeader, FuncArgs, Expression, Spanned, Span};
pub use crate::syntax::{parse, ParseContext, ParseError, ParseResult};
pub use crate::syntax::{parse, ParseContext, ParseResult};
pub use crate::size::{Size, Size2D, SizeBox};
pub use crate::style::{PageStyle, TextStyle};
pub use crate::layout::{
@ -24,8 +24,7 @@ pub mod prelude {
LayoutContext, LayoutSpace, LayoutSpaces,
LayoutAxes, Axis, GenericAxisKind, SpecificAxisKind,
LayoutAlignment, Alignment,
SpacingKind,
LayoutError, LayoutResult,
SpacingKind, LayoutResult,
};
}

View File

@ -230,7 +230,8 @@ impl FlexLayouter {
while size.x > self.line.usable {
if self.stack.space_is_last() {
lr!("box does not fit into line");
error!("box of size {} does not fit into line of size {}",
size.x, self.line.usable);
}
self.stack.finish_space(true);

View File

@ -5,8 +5,8 @@ use std::io::{self, Write};
use smallvec::SmallVec;
use toddle::query::{FontClass, SharedFontLoader};
use toddle::Error as FontError;
use crate::TypesetResult;
use crate::func::Command;
use crate::size::{Size, Size2D, SizeBox};
use crate::style::{LayoutStyle, TextStyle};
@ -366,22 +366,5 @@ impl Serialize for MultiLayout {
}
}
/// The error type for layouting.
pub struct LayoutError(String);
/// The result type for layouting.
pub type LayoutResult<T> = Result<T, LayoutError>;
impl LayoutError {
/// Create a new layout error with a message.
pub fn new<S: Into<String>>(message: S) -> LayoutError {
LayoutError(message.into())
}
}
error_type! {
err: LayoutError,
show: f => f.write_str(&err.0),
from: (std::io::Error, LayoutError::new(err.to_string())),
from: (FontError, LayoutError::new(err.to_string())),
}
pub type LayoutResult<T> = TypesetResult<T>;

View File

@ -108,7 +108,8 @@ impl StackLayouter {
// Find the first (sub-)space that fits the layout.
while !self.sub.usable.fits(new_size) {
if self.space_is_last() && self.space_is_empty() {
lr!("box does not fit into stack");
error!("box of size {} does not fit into remaining stack of size {}",
size, self.sub.usable - Size2D::with_y(self.sub.size.y));
}
self.finish_space(true);

View File

@ -116,6 +116,6 @@ impl<'a, 'p> TextLayouter<'a, 'p> {
self.classes.pop();
}
lr!("no suitable font for character `{}`", c);
error!("no suitable font for character `{}`", c);
}
}

View File

@ -111,7 +111,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
SetTextStyle(style) => self.style.text = style,
SetPageStyle(style) => {
if !self.ctx.top_level {
lr!("page style cannot only be altered in the top-level context");
error!("the page style cannot only be altered from a top-level context");
}
self.style.page = style;

View File

@ -18,13 +18,15 @@ pub extern crate toddle;
use std::cell::RefCell;
use smallvec::smallvec;
use toddle::query::{FontLoader, FontProvider, SharedFontLoader};
use toddle::Error as FontError;
use crate::func::Scope;
use crate::layout::{layout_tree, MultiLayout, LayoutContext};
use crate::layout::{LayoutAxes, LayoutAlignment, Axis, Alignment};
use crate::layout::{LayoutError, LayoutResult, LayoutSpace};
use crate::syntax::{SyntaxTree, parse, ParseContext, ParseError, ParseResult};
use crate::layout::{LayoutResult, LayoutSpace};
use crate::syntax::{parse, SyntaxTree, ParseContext, Span, ParseResult};
use crate::style::{LayoutStyle, PageStyle, TextStyle};
#[macro_use]
@ -116,24 +118,31 @@ impl<'p> Typesetter<'p> {
}
}
/// The general error type for typesetting.
pub enum TypesetError {
/// An error that occured in the parsing step.
Parse(ParseError),
/// An error that occured in the layouting step.
Layout(LayoutError),
/// The result type for typesetting.
pub type TypesetResult<T> = Result<T, TypesetError>;
/// The error type for typesetting.
pub struct TypesetError {
message: String,
span: Option<Span>,
}
impl TypesetError {
/// Create a new typesetting error.
pub fn with_message(message: String) -> TypesetError {
TypesetError { message, span: None }
}
}
error_type! {
err: TypesetError,
show: f => match err {
TypesetError::Parse(e) => write!(f, "{}", e),
TypesetError::Layout(e) => write!(f, "{}", e),
show: f => {
write!(f, "{}", err.message)?;
if let Some(span) = err.span {
write!(f, " at {}", span)?;
}
Ok(())
},
source: match err {
TypesetError::Parse(e) => Some(e),
TypesetError::Layout(e) => Some(e),
},
from: (ParseError, TypesetError::Parse(err)),
from: (LayoutError, TypesetError::Layout(err)),
from: (std::io::Error, TypesetError::with_message(err.to_string())),
from: (FontError, TypesetError::with_message(err.to_string())),
}

View File

@ -19,7 +19,7 @@ function! {
"vertical" => Key::Axis(AxisKey::Vertical),
"primary" => Key::Axis(AxisKey::Primary),
"secondary" => Key::Axis(AxisKey::Secondary),
_ => pr!("unexpected argument"),
_ => error!(unexpected_argument),
};
let value = AlignmentKey::parse(arg.val.1.val)?;

View File

@ -17,7 +17,7 @@ function! {
"height" | "h" => AxisKey::Vertical,
"primary-size" => AxisKey::Primary,
"secondary-size" => AxisKey::Secondary,
_ => pr!("unexpected argument"),
_ => error!(unexpected_argument),
};
let size = ArgParser::convert::<ArgSize>(arg.val.1.val)?;

View File

@ -128,7 +128,7 @@ function! {
"vertical-origin" => AxisAligned(AxisKey::Vertical, Origin),
"vertical-end" => AxisAligned(AxisKey::Vertical, End),
_ => pr!("unexpected argument"),
_ => error!(unexpected_argument),
};
let size = ArgParser::convert::<ArgSize>(arg.val.1.val)?;
@ -200,13 +200,13 @@ function! {
"vertical" => AxisKey::Vertical,
"primary" => AxisKey::Primary,
"secondary" => AxisKey::Secondary,
_ => pr!("unexpected argument"),
_ => error!(unexpected_argument),
};
let spacing = SpacingValue::from_expr(arg.val.1.val)?;
Spacing { axis, spacing }
} else {
pr!("expected axis and expression")
error!("expected axis and expression")
}
};
@ -236,7 +236,7 @@ impl SpacingValue {
Ok(match expr.val {
Expression::Size(s) => SpacingValue::Absolute(*s),
Expression::Num(f) => SpacingValue::Relative(*f as f32),
_ => pr!("invalid spacing: expected size or number"),
_ => error!("invalid spacing: expected size or number"),
})
}
}

View File

@ -12,7 +12,7 @@ mod span;
pub use span::{Span, Spanned};
pub use tokens::{tokenize, Tokens};
pub use parsing::{parse, ParseContext, ParseError, ParseResult};
pub use parsing::{parse, ParseContext, ParseResult};
/// A logical unit of the incoming text stream.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]

View File

@ -2,6 +2,7 @@
use unicode_xid::UnicodeXID;
use crate::TypesetResult;
use crate::func::{LayoutFunc, Scope};
use crate::size::Size;
use super::*;
@ -69,7 +70,7 @@ impl<'s> Parser<'s> {
match token.val {
// Functions.
LeftBracket => self.parse_func()?,
RightBracket => return Err(ParseError::new("unexpected closing bracket")),
RightBracket => error!("unexpected closing bracket"),
// Modifiers.
Underscore => self.append_consumed(Node::ToggleItalics, token.span),
@ -120,10 +121,10 @@ impl<'s> Parser<'s> {
if is_identifier(word) {
Ok(Spanned::new(word.to_owned(), span))
} else {
pr!("invalid identifier: '{}'", word);
error!("invalid identifier: `{}`", word);
}
}
_ => pr!("expected identifier"),
_ => error!("expected identifier"),
}?;
self.skip_white();
@ -132,7 +133,7 @@ impl<'s> Parser<'s> {
let args = match self.tokens.next().map(Spanned::value) {
Some(Token::RightBracket) => FuncArgs::new(),
Some(Token::Colon) => self.parse_func_args()?,
_ => pr!("expected arguments or closing bracket"),
_ => error!("expected arguments or closing bracket"),
};
let end = self.tokens.string_index();
@ -158,7 +159,7 @@ impl<'s> Parser<'s> {
match self.tokens.next().map(Spanned::value) {
Some(Token::Comma) => {},
Some(Token::RightBracket) => break,
_ => pr!("expected comma or closing bracket"),
_ => error!("expected comma or closing bracket"),
}
}
@ -183,7 +184,7 @@ impl<'s> Parser<'s> {
self.skip_white();
let name = token.span_map(|_| name.to_string());
let next = self.tokens.next().ok_or_else(|| pr!(@"expected value"))?;
let next = self.tokens.next().ok_or_else(|| error!(@"expected expression"))?;
let val = Self::parse_expression(next)?;
let span = Span::merge(name.span, val.span);
@ -218,8 +219,7 @@ impl<'s> Parser<'s> {
Expression::Ident(text.to_owned())
}
}
_ => pr!("expected expression"),
_ => error!("expected expression"),
}, token.span))
}
@ -231,7 +231,7 @@ impl<'s> Parser<'s> {
.ctx
.scope
.get_parser(&header.name.val)
.ok_or_else(|| pr!(@"unknown function: '{}'", &header.name.val))?;
.ok_or_else(|| error!(@"unknown function: `{}`", &header.name.val))?;
let has_body = self.tokens.peek().map(Spanned::value) == Some(Token::LeftBracket);
@ -243,7 +243,7 @@ impl<'s> Parser<'s> {
let start = self.tokens.string_index();
let end = find_closing_bracket(&self.src[start..])
.map(|end| start + end)
.ok_or_else(|| ParseError::new("expected closing bracket"))?;
.ok_or_else(|| error!(@"expected closing bracket"))?;
// Parse the body.
let body_string = &self.src[start..end];
@ -299,7 +299,7 @@ impl<'s> Parser<'s> {
state = NewlineState::Zero;
match token.val {
Token::LineComment(_) | Token::BlockComment(_) => self.advance(),
Token::StarSlash => pr!("unexpected end of block comment"),
Token::StarSlash => error!("unexpected end of block comment"),
_ => break,
}
}
@ -431,23 +431,8 @@ fn is_identifier(string: &str) -> bool {
true
}
/// The error type for parsing.
pub struct ParseError(String);
/// The result type for parsing.
pub type ParseResult<T> = Result<T, ParseError>;
impl ParseError {
/// Create a new parse error with a message.
pub fn new<S: Into<String>>(message: S) -> ParseError {
ParseError(message.into())
}
}
error_type! {
err: ParseError,
show: f => f.write_str(&err.0),
}
pub type ParseResult<T> = TypesetResult<T>;
#[cfg(test)]