Merge pull request #5 from typst/problems-and-error-macro
Rename errors to problems and make error! macro more ergonomic
This commit is contained in:
commit
e7ffdde43d
73
src/error.rs
73
src/error.rs
@ -1,73 +0,0 @@
|
||||
//! Errors in source code.
|
||||
//!
|
||||
//! There are no fatal errors in _Typst_. The document will always compile and
|
||||
//! yield a layout. However, this is a best effort process and bad things will
|
||||
//! still generate errors and warnings.
|
||||
|
||||
use serde::Serialize;
|
||||
use crate::syntax::span::SpanVec;
|
||||
|
||||
|
||||
/// A spanned list of errors.
|
||||
pub type Errors = SpanVec<Error>;
|
||||
|
||||
/// An error that arose in parsing or layouting.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct Error {
|
||||
/// An error message describing the problem.
|
||||
pub message: String,
|
||||
/// How severe / important the error is.
|
||||
pub severity: Severity,
|
||||
}
|
||||
|
||||
/// How severe / important an error is.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Severity {
|
||||
/// Something in the code is not good.
|
||||
Warning,
|
||||
/// Something in the code is wrong!
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Create a new error from message and severity.
|
||||
pub fn new(message: impl Into<String>, severity: Severity) -> Error {
|
||||
Error { message: message.into(), severity }
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an error with formatted message and optionally severity and / or
|
||||
/// span.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use typstc::err;
|
||||
/// # use typstc::syntax::span::Span;
|
||||
/// # let span = Span::ZERO;
|
||||
/// # let value = 0;
|
||||
///
|
||||
/// // With span and default severity `Error`.
|
||||
/// err!(span; "the wrong {}", value);
|
||||
///
|
||||
/// // With no span and severity `Warning`.
|
||||
/// err!(@Warning: span; "non-fatal!");
|
||||
///
|
||||
/// // Without span and default severity.
|
||||
/// err!("no spans here ...");
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! err {
|
||||
(@$severity:ident: $span:expr; $($args:tt)*) => {
|
||||
$crate::syntax::span::Spanned { v: err!(@$severity: $($args)*), span: $span }
|
||||
};
|
||||
|
||||
(@$severity:ident: $($args:tt)*) => {
|
||||
$crate::error::Error {
|
||||
message: format!($($args)*),
|
||||
severity: $crate::error::Severity::$severity,
|
||||
}
|
||||
};
|
||||
|
||||
($($tts:tt)*) => { err!(@Error: $($tts)*) };
|
||||
}
|
10
src/func.rs
10
src/func.rs
@ -7,7 +7,7 @@ use crate::syntax::span::Spanned;
|
||||
|
||||
/// Types that are useful for creating your own functions.
|
||||
pub mod prelude {
|
||||
pub use crate::{function, body, err};
|
||||
pub use crate::{function, body, error, warning};
|
||||
pub use crate::layout::prelude::*;
|
||||
pub use crate::layout::Command::{self, *};
|
||||
pub use crate::style::{LayoutStyle, PageStyle, TextStyle};
|
||||
@ -55,8 +55,8 @@ pub trait ParseFunc {
|
||||
///
|
||||
/// parse(header, body, ctx, f) {
|
||||
/// let body = body!(opt: body, ctx, f);
|
||||
/// let hidden = header.args.pos.get::<bool>(&mut f.errors)
|
||||
/// .or_missing(&mut f.errors, header.name.span, "hidden")
|
||||
/// let hidden = header.args.pos.get::<bool>(&mut f.problems)
|
||||
/// .or_missing(&mut f.problems, header.name.span, "hidden")
|
||||
/// .unwrap_or(false);
|
||||
///
|
||||
/// HiderFunc { body: if hidden { None } else { body } }
|
||||
@ -132,7 +132,7 @@ macro_rules! function {
|
||||
let func = $code;
|
||||
|
||||
for arg in header.args.into_iter() {
|
||||
feedback.errors.push(err!(arg.span; "unexpected argument"));
|
||||
error!(@feedback, arg.span, "unexpected argument");
|
||||
}
|
||||
|
||||
$crate::Pass::new(func, feedback)
|
||||
@ -189,7 +189,7 @@ macro_rules! body {
|
||||
|
||||
(nope: $body:expr, $feedback:expr) => {
|
||||
if let Some(body) = $body {
|
||||
$feedback.errors.push($crate::err!(body.span; "unexpected body"));
|
||||
error!(@$feedback, body.span, "unexpected body");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -245,8 +245,10 @@ impl<'a> ModelLayouter<'a> {
|
||||
BreakParagraph => self.layout_paragraph(),
|
||||
BreakPage => {
|
||||
if self.ctx.nested {
|
||||
self.feedback.errors.push(err!(model_span;
|
||||
"page break cannot be issued from nested context"));
|
||||
error!(
|
||||
@self.feedback, model_span,
|
||||
"page break cannot be issued from nested context",
|
||||
);
|
||||
} else {
|
||||
self.layouter.finish_space(true)
|
||||
}
|
||||
@ -258,8 +260,10 @@ impl<'a> ModelLayouter<'a> {
|
||||
}
|
||||
SetPageStyle(style) => {
|
||||
if self.ctx.nested {
|
||||
self.feedback.errors.push(err!(model_span;
|
||||
"page style cannot be changed from nested context"));
|
||||
error!(
|
||||
@self.feedback, model_span,
|
||||
"page style cannot be changed from nested context",
|
||||
);
|
||||
} else {
|
||||
self.style.page = style;
|
||||
|
||||
|
14
src/lib.rs
14
src/lib.rs
@ -27,7 +27,7 @@ use toddle::{Font, OwnedData};
|
||||
use toddle::query::{FontLoader, SharedFontLoader};
|
||||
use toddle::query::{FontProvider, FontIndex, FontDescriptor};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::problem::Problems;
|
||||
use crate::layout::MultiLayout;
|
||||
use crate::style::{LayoutStyle, PageStyle, TextStyle};
|
||||
use crate::syntax::{SyntaxModel, Scope, Decoration, ParseContext, parse};
|
||||
@ -43,7 +43,7 @@ macro_rules! pub_use_mod {
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
pub mod error;
|
||||
pub mod problem;
|
||||
pub mod export;
|
||||
#[macro_use]
|
||||
pub mod func;
|
||||
@ -175,8 +175,8 @@ impl<T> Pass<T> {
|
||||
/// User feedback data accumulated during a compilation pass.
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct Feedback {
|
||||
/// Errors in the source.
|
||||
pub errors: SpanVec<Error>,
|
||||
/// Problems in the source code.
|
||||
pub problems: Problems,
|
||||
/// Decorations of the source code for semantic syntax highlighting.
|
||||
pub decos: SpanVec<Decoration>,
|
||||
}
|
||||
@ -185,7 +185,7 @@ impl Feedback {
|
||||
/// Create a new feedback instance without errors and decos.
|
||||
pub fn new() -> Feedback {
|
||||
Feedback {
|
||||
errors: vec![],
|
||||
problems: vec![],
|
||||
decos: vec![],
|
||||
}
|
||||
}
|
||||
@ -198,14 +198,14 @@ impl Feedback {
|
||||
|
||||
/// Add other feedback data to this feedback.
|
||||
pub fn extend(&mut self, other: Feedback) {
|
||||
self.errors.extend(other.errors);
|
||||
self.problems.extend(other.problems);
|
||||
self.decos.extend(other.decos);
|
||||
}
|
||||
|
||||
/// Add more feedback whose spans are local and need to be offset by an
|
||||
/// `offset` to be correct for this feedbacks context.
|
||||
pub fn extend_offset(&mut self, offset: Position, other: Feedback) {
|
||||
self.errors.extend(offset_spans(offset, other.errors));
|
||||
self.problems.extend(offset_spans(offset, other.problems));
|
||||
self.decos.extend(offset_spans(offset, other.decos));
|
||||
}
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ function! {
|
||||
}
|
||||
|
||||
parse(header, body, ctx, f) {
|
||||
let list = header.args.pos.get_all::<StringLike>(&mut f.errors)
|
||||
let list = header.args.pos.get_all::<StringLike>(&mut f.problems)
|
||||
.map(|s| s.0.to_lowercase())
|
||||
.collect();
|
||||
|
||||
let tuples: Vec<_> = header.args.key
|
||||
.get_all::<String, Tuple>(&mut f.errors)
|
||||
.get_all::<String, Tuple>(&mut f.problems)
|
||||
.collect();
|
||||
|
||||
let classes = tuples.into_iter()
|
||||
.map(|(class, mut tuple)| {
|
||||
let fallback = tuple.get_all::<StringLike>(&mut f.errors)
|
||||
let fallback = tuple.get_all::<StringLike>(&mut f.problems)
|
||||
.map(|s| s.0.to_lowercase())
|
||||
.collect();
|
||||
(class.to_lowercase(), fallback)
|
||||
@ -37,7 +37,7 @@ function! {
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
styled(&self.body, ctx, Some(()),
|
||||
|s, _| {
|
||||
if !self.list.is_empty() {
|
||||
@ -64,12 +64,12 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
FontStyleFunc {
|
||||
body: body!(opt: body, ctx, f),
|
||||
style: header.args.pos.get::<FontStyle>(&mut f.errors)
|
||||
.or_missing(&mut f.errors, header.name.span, "style"),
|
||||
style: header.args.pos.get::<FontStyle>(&mut f.problems)
|
||||
.or_missing(&mut f.problems, header.name.span, "style"),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
styled(&self.body, ctx, self.style, |t, s| t.variant.style = s)
|
||||
}
|
||||
}
|
||||
@ -84,22 +84,24 @@ function! {
|
||||
|
||||
parse(header, body, ctx, f) {
|
||||
let body = body!(opt: body, ctx, f);
|
||||
let weight = header.args.pos.get::<Spanned<(FontWeight, bool)>>(&mut f.errors)
|
||||
let weight = header.args.pos.get::<Spanned<(FontWeight, bool)>>(&mut f.problems)
|
||||
.map(|Spanned { v: (weight, is_clamped), span }| {
|
||||
if is_clamped {
|
||||
f.errors.push(err!(@Warning: span;
|
||||
"weight should be between \
|
||||
100 and 900, clamped to {}", weight.0));
|
||||
warning!(
|
||||
@f, span,
|
||||
"weight should be between 100 and 900, clamped to {}",
|
||||
weight.0,
|
||||
);
|
||||
}
|
||||
|
||||
weight
|
||||
})
|
||||
.or_missing(&mut f.errors, header.name.span, "weight");
|
||||
.or_missing(&mut f.problems, header.name.span, "weight");
|
||||
|
||||
FontWeightFunc { body, weight }
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
styled(&self.body, ctx, self.weight, |t, w| t.variant.weight = w)
|
||||
}
|
||||
}
|
||||
@ -115,12 +117,12 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
FontSizeFunc {
|
||||
body: body!(opt: body, ctx, f),
|
||||
size: header.args.pos.get::<FSize>(&mut f.errors)
|
||||
.or_missing(&mut f.errors, header.name.span, "size")
|
||||
size: header.args.pos.get::<FSize>(&mut f.problems)
|
||||
.or_missing(&mut f.problems, header.name.span, "size")
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
styled(&self.body, ctx, self.size, |t, s| {
|
||||
match s {
|
||||
FSize::Absolute(size) => {
|
||||
|
@ -13,14 +13,14 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
AlignFunc {
|
||||
body: body!(opt: body, ctx, f),
|
||||
map: PosAxisMap::parse::<AxisKey>(&mut f.errors, &mut header.args),
|
||||
map: PosAxisMap::parse::<AxisKey>(&mut f.problems, &mut header.args),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, f) {
|
||||
ctx.base = ctx.spaces[0].dimensions;
|
||||
|
||||
let map = self.map.dedup(&mut f.errors, ctx.axes, |alignment| {
|
||||
let map = self.map.dedup(&mut f.problems, ctx.axes, |alignment| {
|
||||
alignment.axis().map(|s| s.to_generic(ctx.axes))
|
||||
});
|
||||
|
||||
@ -29,8 +29,10 @@ function! {
|
||||
if let Some(generic) = alignment.to_generic(ctx.axes, axis) {
|
||||
*ctx.alignment.get_mut(axis) = generic;
|
||||
} else {
|
||||
f.errors.push(err!(span;
|
||||
"invalid alignment `{}` for {} axis", alignment, axis));
|
||||
error!(
|
||||
@f, span,
|
||||
"invalid alignment `{}` for {} axis", alignment, axis,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,14 +61,14 @@ function! {
|
||||
DirectionFunc {
|
||||
name_span: header.name.span,
|
||||
body: body!(opt: body, ctx, f),
|
||||
map: PosAxisMap::parse::<AxisKey>(&mut f.errors, &mut header.args),
|
||||
map: PosAxisMap::parse::<AxisKey>(&mut f.problems, &mut header.args),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, f) {
|
||||
ctx.base = ctx.spaces[0].dimensions;
|
||||
|
||||
let map = self.map.dedup(&mut f.errors, ctx.axes, |direction| {
|
||||
let map = self.map.dedup(&mut f.problems, ctx.axes, |direction| {
|
||||
Some(direction.axis().to_generic(ctx.axes))
|
||||
});
|
||||
|
||||
@ -76,9 +78,11 @@ function! {
|
||||
map.with(Secondary, |&dir| axes.secondary = dir);
|
||||
|
||||
if axes.primary.axis() == axes.secondary.axis() {
|
||||
f.errors.push(err!(self.name_span;
|
||||
error!(
|
||||
@f, self.name_span,
|
||||
"invalid aligned primary and secondary axes: `{}`, `{}`",
|
||||
ctx.axes.primary, ctx.axes.secondary));
|
||||
ctx.axes.primary, ctx.axes.secondary,
|
||||
);
|
||||
} else {
|
||||
ctx.axes = axes;
|
||||
}
|
||||
@ -106,8 +110,8 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
BoxFunc {
|
||||
body: body!(opt: body, ctx, f).unwrap_or(SyntaxModel::new()),
|
||||
extents: AxisMap::parse::<ExtentKey>(&mut f.errors, &mut header.args.key),
|
||||
debug: header.args.key.get::<bool>(&mut f.errors, "debug"),
|
||||
extents: AxisMap::parse::<ExtentKey>(&mut f.problems, &mut header.args.key),
|
||||
debug: header.args.key.get::<bool>(&mut f.problems, "debug"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +123,7 @@ function! {
|
||||
ctx.debug = debug;
|
||||
}
|
||||
|
||||
let map = self.extents.dedup(&mut f.errors, ctx.axes);
|
||||
let map = self.extents.dedup(&mut f.problems, ctx.axes);
|
||||
for &axis in &[Horizontal, Vertical] {
|
||||
if let Some(psize) = map.get(axis) {
|
||||
let size = psize.scaled(ctx.base.get(axis));
|
||||
|
@ -59,7 +59,7 @@ function! {
|
||||
ValFunc { body: body!(opt: body, ctx, f) }
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
match &self.body {
|
||||
Some(model) => vec![LayoutSyntaxModel(model)],
|
||||
None => vec![],
|
||||
|
@ -15,9 +15,9 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
body!(nope: body, f);
|
||||
PageSizeFunc {
|
||||
paper: header.args.pos.get::<Paper>(&mut f.errors),
|
||||
extents: AxisMap::parse::<ExtentKey>(&mut f.errors, &mut header.args.key),
|
||||
flip: header.args.key.get::<bool>(&mut f.errors, "flip").unwrap_or(false),
|
||||
paper: header.args.pos.get::<Paper>(&mut f.problems),
|
||||
extents: AxisMap::parse::<ExtentKey>(&mut f.problems, &mut header.args.key),
|
||||
flip: header.args.key.get::<bool>(&mut f.problems, "flip").unwrap_or(false),
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ function! {
|
||||
style.class = PaperClass::Custom;
|
||||
}
|
||||
|
||||
let map = self.extents.dedup(&mut f.errors, ctx.axes);
|
||||
let map = self.extents.dedup(&mut f.problems, ctx.axes);
|
||||
map.with(Horizontal, |&width| style.dimensions.x = width);
|
||||
map.with(Vertical, |&height| style.dimensions.y = height);
|
||||
|
||||
@ -53,13 +53,13 @@ function! {
|
||||
parse(header, body, ctx, f) {
|
||||
body!(nope: body, f);
|
||||
PageMarginsFunc {
|
||||
padding: PaddingMap::parse(&mut f.errors, &mut header.args),
|
||||
padding: PaddingMap::parse(&mut f.problems, &mut header.args),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, f) {
|
||||
let mut style = ctx.style.page;
|
||||
self.padding.apply(&mut f.errors, ctx.axes, &mut style.margins);
|
||||
self.padding.apply(&mut f.problems, ctx.axes, &mut style.margins);
|
||||
vec![SetPageStyle(style)]
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ function! {
|
||||
pub struct LineBreakFunc;
|
||||
|
||||
parse(default)
|
||||
layout(self, ctx, errors) { vec![BreakLine] }
|
||||
layout(self, ctx, f) { vec![BreakLine] }
|
||||
}
|
||||
|
||||
function! {
|
||||
@ -22,7 +22,7 @@ function! {
|
||||
pub struct ParBreakFunc;
|
||||
|
||||
parse(default)
|
||||
layout(self, ctx, errors) { vec![BreakParagraph] }
|
||||
layout(self, ctx, f) { vec![BreakParagraph] }
|
||||
}
|
||||
|
||||
function! {
|
||||
@ -31,7 +31,7 @@ function! {
|
||||
pub struct PageBreakFunc;
|
||||
|
||||
parse(default)
|
||||
layout(self, ctx, errors) { vec![BreakPage] }
|
||||
layout(self, ctx, f) { vec![BreakPage] }
|
||||
}
|
||||
|
||||
function! {
|
||||
@ -50,13 +50,13 @@ function! {
|
||||
ContentSpacingFunc {
|
||||
body: body!(opt: body, ctx, f),
|
||||
content: meta,
|
||||
spacing: header.args.pos.get::<f64>(&mut f.errors)
|
||||
spacing: header.args.pos.get::<f64>(&mut f.problems)
|
||||
.map(|num| num as f32)
|
||||
.or_missing(&mut f.errors, header.name.span, "spacing"),
|
||||
.or_missing(&mut f.problems, header.name.span, "spacing"),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
styled(&self.body, ctx, self.spacing, |t, s| match self.content {
|
||||
Word => t.word_spacing_scale = s,
|
||||
Line => t.line_spacing_scale = s,
|
||||
@ -88,15 +88,15 @@ function! {
|
||||
body!(nope: body, f);
|
||||
SpacingFunc {
|
||||
spacing: if let Some(axis) = meta {
|
||||
header.args.pos.get::<FSize>(&mut f.errors)
|
||||
header.args.pos.get::<FSize>(&mut f.problems)
|
||||
.map(|s| (AxisKey::Specific(axis), s))
|
||||
} else {
|
||||
header.args.key.get_with_key::<AxisKey, FSize>(&mut f.errors)
|
||||
}.or_missing(&mut f.errors, header.name.span, "spacing"),
|
||||
header.args.key.get_with_key::<AxisKey, FSize>(&mut f.problems)
|
||||
}.or_missing(&mut f.problems, header.name.span, "spacing"),
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) {
|
||||
layout(self, ctx, f) {
|
||||
if let Some((axis, spacing)) = self.spacing {
|
||||
let axis = axis.to_generic(ctx.axes);
|
||||
let spacing = spacing.scaled(ctx.style.text.font_size());
|
||||
|
94
src/problem.rs
Normal file
94
src/problem.rs
Normal file
@ -0,0 +1,94 @@
|
||||
//! Problems (errors / warnings) in _Typst_ documents.
|
||||
//!
|
||||
//! There are no fatal errors in _Typst_. The document will always compile and
|
||||
//! yield a layout. However, this is a best effort process and bad things will
|
||||
//! still generate errors and warnings.
|
||||
|
||||
use serde::Serialize;
|
||||
use crate::syntax::span::SpanVec;
|
||||
|
||||
|
||||
/// A list of spanned problems.
|
||||
pub type Problems = SpanVec<Problem>;
|
||||
|
||||
/// A problem that arose in parsing or layouting.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct Problem {
|
||||
/// How severe / important the problem is.
|
||||
pub severity: Severity,
|
||||
/// A message describing the problem.
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
/// How severe / important a problem is.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Severity {
|
||||
/// Something in the code is not good.
|
||||
Warning,
|
||||
/// Something in the code is wrong!
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Problem {
|
||||
/// Create a new problem from message and severity.
|
||||
pub fn new(message: impl Into<String>, severity: Severity) -> Self {
|
||||
Self { message: message.into(), severity }
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a problem with `Error` severity.
|
||||
///
|
||||
/// ```
|
||||
/// # use typstc::error;
|
||||
/// # use typstc::syntax::span::Span;
|
||||
/// # use typstc::Feedback;
|
||||
/// # let span = Span::ZERO;
|
||||
/// # let mut feedback = Feedback::new();
|
||||
/// # let name = "";
|
||||
/// // Create formatted error values.
|
||||
/// let error = error!("expected {}", name);
|
||||
///
|
||||
/// // Create spanned errors.
|
||||
/// let spanned = error!(span, "there is an error here");
|
||||
///
|
||||
/// // Create an error and directly add it to existing feedback.
|
||||
/// error!(@feedback, span, "oh no!");
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($tts:tt)*) => {
|
||||
$crate::__impl_problem!($crate::problem::Severity::Error; $($tts)*)
|
||||
};
|
||||
}
|
||||
|
||||
/// Construct a problem with `Warning` severity.
|
||||
///
|
||||
/// This works exactly like `error!`. See its documentation for more
|
||||
/// information.
|
||||
#[macro_export]
|
||||
macro_rules! warning {
|
||||
($($tts:tt)*) => {
|
||||
$crate::__impl_problem!($crate::problem::Severity::Warning; $($tts)*)
|
||||
};
|
||||
}
|
||||
|
||||
/// Backs the `error!` and `warning!` macros.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __impl_problem {
|
||||
($severity:expr; @$feedback:expr, $($tts:tt)*) => {
|
||||
$feedback.problems.push($crate::__impl_problem!($severity; $($tts)*));
|
||||
};
|
||||
|
||||
($severity:expr; $fmt:literal $($tts:tt)*) => {
|
||||
$crate::problem::Problem::new(format!($fmt $($tts)*), $severity)
|
||||
};
|
||||
|
||||
($severity:expr; $span:expr, $fmt:literal $($tts:tt)*) => {
|
||||
$crate::syntax::span::Spanned::new(
|
||||
$crate::__impl_problem!($severity; $fmt $($tts)*),
|
||||
$span,
|
||||
)
|
||||
};
|
||||
}
|
@ -6,7 +6,7 @@ use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use std::u8;
|
||||
|
||||
use crate::error::Errors;
|
||||
use crate::problem::Problems;
|
||||
use crate::size::Size;
|
||||
use super::func::{Key, Value};
|
||||
use super::span::{Span, Spanned};
|
||||
@ -258,28 +258,28 @@ impl Tuple {
|
||||
}
|
||||
|
||||
/// Extract (and remove) the first matching value and remove and generate
|
||||
/// errors for all previous items that did not match.
|
||||
pub fn get<V: Value>(&mut self, errors: &mut Errors) -> Option<V> {
|
||||
/// problems for all previous items that did not match.
|
||||
pub fn get<V: Value>(&mut self, problems: &mut Problems) -> Option<V> {
|
||||
while !self.items.is_empty() {
|
||||
let expr = self.items.remove(0);
|
||||
let span = expr.span;
|
||||
match V::parse(expr) {
|
||||
Ok(output) => return Some(output),
|
||||
Err(err) => errors.push(Spanned { v: err, span }),
|
||||
Err(v) => problems.push(Spanned { v, span }),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Extract and return an iterator over all values that match and generate
|
||||
/// errors for all items that do not match.
|
||||
pub fn get_all<'a, V: Value>(&'a mut self, errors: &'a mut Errors)
|
||||
/// problems for all items that do not match.
|
||||
pub fn get_all<'a, V: Value>(&'a mut self, problems: &'a mut Problems)
|
||||
-> impl Iterator<Item=V> + 'a {
|
||||
self.items.drain(..).filter_map(move |expr| {
|
||||
let span = expr.span;
|
||||
match V::parse(expr) {
|
||||
Ok(output) => Some(output),
|
||||
Err(err) => { errors.push(Spanned { v: err, span }); None }
|
||||
Err(v) => { problems.push(Spanned { v, span }); None }
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -400,9 +400,9 @@ impl Object {
|
||||
///
|
||||
/// Inserts an error if the value does not match. If the key is not
|
||||
/// contained, no error is inserted.
|
||||
pub fn get<V: Value>(&mut self, errors: &mut Errors, key: &str) -> Option<V> {
|
||||
pub fn get<V: Value>(&mut self, problems: &mut Problems, key: &str) -> Option<V> {
|
||||
let index = self.pairs.iter().position(|pair| pair.v.key.v.as_str() == key)?;
|
||||
self.get_index::<V>(errors, index)
|
||||
self.get_index::<V>(problems, index)
|
||||
}
|
||||
|
||||
/// Extract (and remove) a pair with a matching key and value.
|
||||
@ -411,12 +411,12 @@ impl Object {
|
||||
/// found, no error is inserted.
|
||||
pub fn get_with_key<K: Key, V: Value>(
|
||||
&mut self,
|
||||
errors: &mut Errors,
|
||||
problems: &mut Problems,
|
||||
) -> Option<(K, V)> {
|
||||
for (index, pair) in self.pairs.iter().enumerate() {
|
||||
let key = Spanned { v: pair.v.key.v.as_str(), span: pair.v.key.span };
|
||||
if let Some(key) = K::parse(key) {
|
||||
return self.get_index::<V>(errors, index).map(|value| (key, value));
|
||||
return self.get_index::<V>(problems, index).map(|value| (key, value));
|
||||
}
|
||||
}
|
||||
None
|
||||
@ -427,7 +427,7 @@ impl Object {
|
||||
/// Inserts errors for values that do not match.
|
||||
pub fn get_all<'a, K: Key, V: Value>(
|
||||
&'a mut self,
|
||||
errors: &'a mut Errors,
|
||||
problems: &'a mut Problems,
|
||||
) -> impl Iterator<Item=(K, V)> + 'a {
|
||||
let mut index = 0;
|
||||
std::iter::from_fn(move || {
|
||||
@ -436,7 +436,7 @@ impl Object {
|
||||
let key = Spanned { v: key.v.as_str(), span: key.span };
|
||||
|
||||
Some(if let Some(key) = K::parse(key) {
|
||||
self.get_index::<V>(errors, index).map(|v| (key, v))
|
||||
self.get_index::<V>(problems, index).map(|v| (key, v))
|
||||
} else {
|
||||
index += 1;
|
||||
None
|
||||
@ -456,20 +456,20 @@ impl Object {
|
||||
/// ```
|
||||
pub fn get_all_spanned<'a, K: Key + 'a, V: Value + 'a>(
|
||||
&'a mut self,
|
||||
errors: &'a mut Errors,
|
||||
problems: &'a mut Problems,
|
||||
) -> impl Iterator<Item=Spanned<(K, V)>> + 'a {
|
||||
self.get_all::<Spanned<K>, Spanned<V>>(errors)
|
||||
self.get_all::<Spanned<K>, Spanned<V>>(problems)
|
||||
.map(|(k, v)| Spanned::new((k.v, v.v), Span::merge(k.span, v.span)))
|
||||
}
|
||||
|
||||
/// Extract the argument at the given index and insert an error if the value
|
||||
/// does not match.
|
||||
fn get_index<V: Value>(&mut self, errors: &mut Errors, index: usize) -> Option<V> {
|
||||
fn get_index<V: Value>(&mut self, problems: &mut Problems, index: usize) -> Option<V> {
|
||||
let expr = self.pairs.remove(index).v.value;
|
||||
let span = expr.span;
|
||||
match V::parse(expr) {
|
||||
Ok(output) => Some(output),
|
||||
Err(err) => { errors.push(Spanned { v: err, span }); None }
|
||||
Err(v) => { problems.push(Spanned { v, span }); None }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Deduplicating maps and keys for argument parsing.
|
||||
|
||||
use crate::error::Errors;
|
||||
use crate::problem::Problems;
|
||||
use crate::layout::prelude::*;
|
||||
use crate::size::{PSize, ValueBox};
|
||||
use crate::syntax::span::Spanned;
|
||||
@ -12,7 +12,7 @@ use super::*;
|
||||
/// A map which deduplicates redundant arguments.
|
||||
///
|
||||
/// Whenever a duplicate argument is inserted into the map, through the
|
||||
/// functions `from_iter`, `insert` or `extend` an errors is added to the error
|
||||
/// functions `from_iter`, `insert` or `extend` an problems is added to the error
|
||||
/// list that needs to be passed to those functions.
|
||||
///
|
||||
/// All entries need to have span information to enable the error reporting.
|
||||
@ -28,27 +28,27 @@ impl<K, V> DedupMap<K, V> where K: Eq {
|
||||
}
|
||||
|
||||
/// Create a new map from an iterator of spanned keys and values.
|
||||
pub fn from_iter<I>(errors: &mut Errors, iter: I) -> DedupMap<K, V>
|
||||
pub fn from_iter<I>(problems: &mut Problems, iter: I) -> DedupMap<K, V>
|
||||
where I: IntoIterator<Item=Spanned<(K, V)>> {
|
||||
let mut map = DedupMap::new();
|
||||
map.extend(errors, iter);
|
||||
map.extend(problems, iter);
|
||||
map
|
||||
}
|
||||
|
||||
/// Add a spanned key-value pair.
|
||||
pub fn insert(&mut self, errors: &mut Errors, entry: Spanned<(K, V)>) {
|
||||
pub fn insert(&mut self, problems: &mut Problems, entry: Spanned<(K, V)>) {
|
||||
if self.map.iter().any(|e| e.v.0 == entry.v.0) {
|
||||
errors.push(err!(entry.span; "duplicate argument"));
|
||||
problems.push(error!(entry.span, "duplicate argument"));
|
||||
} else {
|
||||
self.map.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add multiple spanned key-value pairs.
|
||||
pub fn extend<I>(&mut self, errors: &mut Errors, items: I)
|
||||
pub fn extend<I>(&mut self, problems: &mut Problems, items: I)
|
||||
where I: IntoIterator<Item=Spanned<(K, V)>> {
|
||||
for item in items.into_iter() {
|
||||
self.insert(errors, item);
|
||||
self.insert(problems, item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,15 +71,15 @@ impl<K, V> DedupMap<K, V> where K: Eq {
|
||||
}
|
||||
|
||||
/// Create a new map where keys and values are mapped to new keys and
|
||||
/// values. When the mapping introduces new duplicates, errors are
|
||||
/// values. When the mapping introduces new duplicates, problems are
|
||||
/// generated.
|
||||
pub fn dedup<F, K2, V2>(&self, errors: &mut Errors, mut f: F) -> DedupMap<K2, V2>
|
||||
pub fn dedup<F, K2, V2>(&self, problems: &mut Problems, mut f: F) -> DedupMap<K2, V2>
|
||||
where F: FnMut(&K, &V) -> (K2, V2), K2: Eq {
|
||||
let mut map = DedupMap::new();
|
||||
|
||||
for Spanned { v: (key, value), span } in self.map.iter() {
|
||||
let (key, value) = f(key, value);
|
||||
map.insert(errors, Spanned { v: (key, value), span: *span });
|
||||
map.insert(problems, Spanned { v: (key, value), span: *span });
|
||||
}
|
||||
|
||||
map
|
||||
@ -98,21 +98,21 @@ pub struct AxisMap<V>(DedupMap<AxisKey, V>);
|
||||
impl<V: Value> AxisMap<V> {
|
||||
/// Parse an axis map from the object.
|
||||
pub fn parse<K>(
|
||||
errors: &mut Errors,
|
||||
problems: &mut Problems,
|
||||
object: &mut Object,
|
||||
) -> AxisMap<V> where K: Key + Into<AxisKey> {
|
||||
let values: Vec<_> = object
|
||||
.get_all_spanned::<K, V>(errors)
|
||||
.get_all_spanned::<K, V>(problems)
|
||||
.map(|s| s.map(|(k, v)| (k.into(), v)))
|
||||
.collect();
|
||||
|
||||
AxisMap(DedupMap::from_iter(errors, values))
|
||||
AxisMap(DedupMap::from_iter(problems, values))
|
||||
}
|
||||
|
||||
/// Deduplicate from specific or generic to just specific axes.
|
||||
pub fn dedup(&self, errors: &mut Errors, axes: LayoutAxes) -> DedupMap<SpecificAxis, V>
|
||||
pub fn dedup(&self, problems: &mut Problems, axes: LayoutAxes) -> DedupMap<SpecificAxis, V>
|
||||
where V: Clone {
|
||||
self.0.dedup(errors, |key, val| (key.to_specific(axes), val.clone()))
|
||||
self.0.dedup(problems, |key, val| (key.to_specific(axes), val.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,23 +124,23 @@ pub struct PosAxisMap<V>(DedupMap<PosAxisKey, V>);
|
||||
impl<V: Value> PosAxisMap<V> {
|
||||
/// Parse a positional/axis map from the function arguments.
|
||||
pub fn parse<K>(
|
||||
errors: &mut Errors,
|
||||
problems: &mut Problems,
|
||||
args: &mut FuncArgs,
|
||||
) -> PosAxisMap<V> where K: Key + Into<AxisKey> {
|
||||
let mut map = DedupMap::new();
|
||||
|
||||
for &key in &[PosAxisKey::First, PosAxisKey::Second] {
|
||||
if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(errors) {
|
||||
map.insert(errors, Spanned { v: (key, v), span })
|
||||
if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(problems) {
|
||||
map.insert(problems, Spanned { v: (key, v), span })
|
||||
}
|
||||
}
|
||||
|
||||
let keywords: Vec<_> = args.key
|
||||
.get_all_spanned::<K, V>(errors)
|
||||
.get_all_spanned::<K, V>(problems)
|
||||
.map(|s| s.map(|(k, v)| (PosAxisKey::Keyword(k.into()), v)))
|
||||
.collect();
|
||||
|
||||
map.extend(errors, keywords);
|
||||
map.extend(problems, keywords);
|
||||
|
||||
PosAxisMap(map)
|
||||
}
|
||||
@ -149,7 +149,7 @@ impl<V: Value> PosAxisMap<V> {
|
||||
/// or specific axes to just generic axes.
|
||||
pub fn dedup<F>(
|
||||
&self,
|
||||
errors: &mut Errors,
|
||||
problems: &mut Problems,
|
||||
axes: LayoutAxes,
|
||||
mut f: F,
|
||||
) -> DedupMap<GenericAxis, V>
|
||||
@ -157,7 +157,7 @@ impl<V: Value> PosAxisMap<V> {
|
||||
F: FnMut(&V) -> Option<GenericAxis>,
|
||||
V: Clone,
|
||||
{
|
||||
self.0.dedup(errors, |key, val| {
|
||||
self.0.dedup(problems, |key, val| {
|
||||
(match key {
|
||||
PosAxisKey::First => f(val).unwrap_or(GenericAxis::Primary),
|
||||
PosAxisKey::Second => f(val).unwrap_or(GenericAxis::Secondary),
|
||||
@ -175,20 +175,20 @@ pub struct PaddingMap(DedupMap<PaddingKey<AxisKey>, Option<PSize>>);
|
||||
|
||||
impl PaddingMap {
|
||||
/// Parse a padding map from the function arguments.
|
||||
pub fn parse(errors: &mut Errors, args: &mut FuncArgs) -> PaddingMap {
|
||||
pub fn parse(problems: &mut Problems, args: &mut FuncArgs) -> PaddingMap {
|
||||
let mut map = DedupMap::new();
|
||||
|
||||
let all = args.pos.get::<Spanned<Defaultable<PSize>>>(errors);
|
||||
let all = args.pos.get::<Spanned<Defaultable<PSize>>>(problems);
|
||||
if let Some(Spanned { v, span }) = all {
|
||||
map.insert(errors, Spanned { v: (PaddingKey::All, v.into()), span });
|
||||
map.insert(problems, Spanned { v: (PaddingKey::All, v.into()), span });
|
||||
}
|
||||
|
||||
let paddings: Vec<_> = args.key
|
||||
.get_all_spanned::<PaddingKey<AxisKey>, Defaultable<PSize>>(errors)
|
||||
.get_all_spanned::<PaddingKey<AxisKey>, Defaultable<PSize>>(problems)
|
||||
.map(|s| s.map(|(k, v)| (k, v.into())))
|
||||
.collect();
|
||||
|
||||
map.extend(errors, paddings);
|
||||
map.extend(problems, paddings);
|
||||
|
||||
PaddingMap(map)
|
||||
}
|
||||
@ -196,13 +196,13 @@ impl PaddingMap {
|
||||
/// Apply the specified padding on a value box of optional, scalable sizes.
|
||||
pub fn apply(
|
||||
&self,
|
||||
errors: &mut Errors,
|
||||
problems: &mut Problems,
|
||||
axes: LayoutAxes,
|
||||
padding: &mut ValueBox<Option<PSize>>
|
||||
) {
|
||||
use PaddingKey::*;
|
||||
|
||||
let map = self.0.dedup(errors, |key, &val| {
|
||||
let map = self.0.dedup(problems, |key, &val| {
|
||||
(match key {
|
||||
All => All,
|
||||
Both(axis) => Both(axis.to_specific(axes)),
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Primitives for argument parsing in library functions.
|
||||
|
||||
use std::iter::FromIterator;
|
||||
use crate::error::{Error, Errors};
|
||||
use crate::problem::{Problem, Problems};
|
||||
use super::expr::{Expr, Ident, Tuple, Object, Pair};
|
||||
use super::span::{Span, Spanned};
|
||||
|
||||
@ -84,13 +84,13 @@ pub enum FuncArg {
|
||||
pub trait OptionExt: Sized {
|
||||
/// Add an error about a missing argument `arg` with the given span if the
|
||||
/// option is `None`.
|
||||
fn or_missing(self, errors: &mut Errors, span: Span, arg: &str) -> Self;
|
||||
fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self;
|
||||
}
|
||||
|
||||
impl<T> OptionExt for Option<T> {
|
||||
fn or_missing(self, errors: &mut Errors, span: Span, arg: &str) -> Self {
|
||||
fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self {
|
||||
if self.is_none() {
|
||||
errors.push(err!(span; "missing argument: {}", arg));
|
||||
problems.push(error!(span, "missing argument: {}", arg));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -23,20 +23,20 @@ use self::AlignmentValue::*;
|
||||
/// # Example implementation
|
||||
/// An implementation for `bool` might look as follows:
|
||||
/// ```
|
||||
/// # use typstc::err;
|
||||
/// # use typstc::error::Error;
|
||||
/// # use typstc::error;
|
||||
/// # use typstc::problem::Problem;
|
||||
/// # use typstc::syntax::expr::Expr;
|
||||
/// # use typstc::syntax::func::Value;
|
||||
/// # use typstc::syntax::span::Spanned;
|
||||
/// # struct Bool; /*
|
||||
/// impl Value for bool {
|
||||
/// # */ impl Value for Bool {
|
||||
/// fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
/// fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
/// match expr.v {
|
||||
/// # /*
|
||||
/// Expr::Bool(b) => Ok(b),
|
||||
/// # */ Expr::Bool(_) => Ok(Bool),
|
||||
/// other => Err(err!("expected bool, found {}", other.name())),
|
||||
/// other => Err(error!("expected bool, found {}", other.name())),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
@ -44,11 +44,11 @@ use self::AlignmentValue::*;
|
||||
pub trait Value: Sized {
|
||||
/// Parse an expression into this value or return an error if the expression
|
||||
/// is valid for this value type.
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error>;
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem>;
|
||||
}
|
||||
|
||||
impl<V: Value> Value for Spanned<V> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
let span = expr.span;
|
||||
V::parse(expr).map(|v| Spanned { v, span })
|
||||
}
|
||||
@ -58,12 +58,13 @@ impl<V: Value> Value for Spanned<V> {
|
||||
macro_rules! value {
|
||||
($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => {
|
||||
impl Value for $type {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
#[allow(unreachable_patterns)]
|
||||
match expr.v {
|
||||
$($p => Ok($r)),*,
|
||||
other => Err(err!("expected {}, found {}",
|
||||
$name, other.name())),
|
||||
other => Err(
|
||||
error!("expected {}, found {}", $name, other.name())
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,7 +121,7 @@ impl From<StringLike> for String {
|
||||
pub struct Defaultable<V>(pub Option<V>);
|
||||
|
||||
impl<V: Value> Value for Defaultable<V> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
Ok(Defaultable(match expr.v {
|
||||
Expr::Ident(ident) if ident.as_str() == "default" => None,
|
||||
_ => Some(V::parse(expr)?)
|
||||
@ -135,16 +136,16 @@ impl<V> From<Defaultable<V>> for Option<V> {
|
||||
}
|
||||
|
||||
impl Value for FontStyle {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
FontStyle::from_name(Ident::parse(expr)?.as_str())
|
||||
.ok_or_else(|| err!("invalid font style"))
|
||||
.ok_or_else(|| error!("invalid font style"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The additional boolean specifies whether a number was clamped into the range
|
||||
/// 100 - 900 to make it a valid font weight.
|
||||
impl Value for (FontWeight, bool) {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
match expr.v {
|
||||
Expr::Number(weight) => {
|
||||
let weight = weight.round();
|
||||
@ -158,30 +159,31 @@ impl Value for (FontWeight, bool) {
|
||||
}
|
||||
Expr::Ident(id) => {
|
||||
FontWeight::from_name(id.as_str())
|
||||
.ok_or_else(|| err!("invalid font weight"))
|
||||
.ok_or_else(|| error!("invalid font weight"))
|
||||
.map(|weight| (weight, false))
|
||||
}
|
||||
other => Err(err!("expected identifier or number, \
|
||||
found {}", other.name())),
|
||||
other => Err(
|
||||
error!("expected identifier or number, found {}", other.name())
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for Paper {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
Paper::from_name(Ident::parse(expr)?.as_str())
|
||||
.ok_or_else(|| err!("invalid paper type"))
|
||||
.ok_or_else(|| error!("invalid paper type"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for Direction {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
Ok(match Ident::parse(expr)?.as_str() {
|
||||
"left-to-right" | "ltr" | "LTR" => LeftToRight,
|
||||
"right-to-left" | "rtl" | "RTL" => RightToLeft,
|
||||
"top-to-bottom" | "ttb" | "TTB" => TopToBottom,
|
||||
"bottom-to-top" | "btt" | "BTT" => BottomToTop,
|
||||
_ => return Err(err!("invalid direction"))
|
||||
_ => return Err(error!("invalid direction"))
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -248,7 +250,7 @@ impl AlignmentValue {
|
||||
}
|
||||
|
||||
impl Value for AlignmentValue {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Error> {
|
||||
fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
|
||||
Ok(match Ident::parse(expr)?.as_str() {
|
||||
"origin" => Align(Origin),
|
||||
"center" => Align(Center),
|
||||
@ -257,7 +259,7 @@ impl Value for AlignmentValue {
|
||||
"top" => Top,
|
||||
"right" => Right,
|
||||
"bottom" => Bottom,
|
||||
_ => return Err(err!("invalid alignment"))
|
||||
_ => return Err(error!("invalid alignment"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +49,7 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Pass<SyntaxModel>
|
||||
feedback.extend_offset(span.start, parsed.feedback);
|
||||
|
||||
if !terminated {
|
||||
feedback.errors.push(err!(Span::at(span.end);
|
||||
"expected closing bracket"));
|
||||
error!(@feedback, Span::at(span.end), "expected closing bracket");
|
||||
}
|
||||
|
||||
parsed.output
|
||||
@ -62,8 +61,7 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Pass<SyntaxModel>
|
||||
|
||||
Token::Raw { raw, terminated } => {
|
||||
if !terminated {
|
||||
feedback.errors.push(err!(Span::at(span.end);
|
||||
"expected backtick"));
|
||||
error!(@feedback, Span::at(span.end), "expected backtick");
|
||||
}
|
||||
|
||||
Node::Raw(unescape_raw(raw))
|
||||
@ -72,7 +70,7 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Pass<SyntaxModel>
|
||||
Token::Text(text) => Node::Text(text.to_string()),
|
||||
|
||||
other => {
|
||||
feedback.errors.push(err!(span; "unexpected {}", other.name()));
|
||||
error!(@feedback, span, "unexpected {}", other.name());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@ -129,7 +127,7 @@ impl<'s> FuncParser<'s> {
|
||||
|
||||
// The fallback parser was returned. Invalid function.
|
||||
Err(parser) => {
|
||||
self.feedback.errors.push(err!(header.name.span; "unknown function"));
|
||||
error!(@self.feedback, header.name.span, "unknown function");
|
||||
(parser, Decoration::InvalidFuncName)
|
||||
}
|
||||
};
|
||||
@ -270,10 +268,10 @@ impl<'s> FuncParser<'s> {
|
||||
let expr = binop(Box::new(o1), Box::new(o2));
|
||||
return Some(Spanned::new(expr, span));
|
||||
} else {
|
||||
self.feedback.errors.push(err!(
|
||||
Span::merge(next.span, o1.span);
|
||||
error!(
|
||||
@self.feedback, Span::merge(next.span, o1.span),
|
||||
"missing right {}", operand_name,
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,7 +290,7 @@ impl<'s> FuncParser<'s> {
|
||||
let span = Span::merge(first.span, factor.span);
|
||||
Some(Spanned::new(Expr::Neg(Box::new(factor)), span))
|
||||
} else {
|
||||
self.feedback.errors.push(err!(first.span; "dangling minus"));
|
||||
error!(@self.feedback, first.span, "dangling minus");
|
||||
None
|
||||
}
|
||||
} else {
|
||||
@ -333,7 +331,7 @@ impl<'s> FuncParser<'s> {
|
||||
take!(Expr::Color(color))
|
||||
} else {
|
||||
// Heal color by assuming black
|
||||
self.feedback.errors.push(err!(first.span; "invalid color"));
|
||||
error!(@self.feedback, first.span, "invalid color");
|
||||
take!(Expr::Color(RgbaColor::new_healed(0, 0, 0, 255)))
|
||||
}
|
||||
},
|
||||
@ -517,14 +515,16 @@ impl<'s> FuncParser<'s> {
|
||||
/// Add an error about an expected `thing` which was not found, showing
|
||||
/// what was found instead.
|
||||
fn expected_found(&mut self, thing: &str, found: Spanned<Token>) {
|
||||
self.feedback.errors.push(err!(found.span;
|
||||
"expected {}, found {}", thing, found.v.name()));
|
||||
error!(
|
||||
@self.feedback, found.span,
|
||||
"expected {}, found {}", thing, found.v.name(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add an error about an `thing` which was expected but not found at the
|
||||
/// given position.
|
||||
fn expected_at(&mut self, thing: &str, pos: Position) {
|
||||
self.feedback.errors.push(err!(Span::at(pos); "expected {}", thing));
|
||||
error!(@self.feedback, Span::at(pos), "expected {}", thing);
|
||||
}
|
||||
|
||||
/// Add a expected-found-error if `found` is `Some` and an expected-error
|
||||
@ -726,7 +726,7 @@ mod tests {
|
||||
p!($source => [$($model)*], []);
|
||||
};
|
||||
|
||||
($source:expr => [$($model:tt)*], [$($errors:tt)*] $(, [$($decos:tt)*])? $(,)?) => {
|
||||
($source:expr => [$($model:tt)*], [$($problems:tt)*] $(, [$($decos:tt)*])? $(,)?) => {
|
||||
let mut scope = Scope::new::<DebugFn>();
|
||||
scope.add::<DebugFn>("f");
|
||||
scope.add::<DebugFn>("n");
|
||||
@ -740,12 +740,12 @@ mod tests {
|
||||
let (exp, cmp) = spanned![vec $($model)*];
|
||||
check($source, exp, pass.output.nodes, cmp);
|
||||
|
||||
// Test errors
|
||||
let (exp, cmp) = spanned![vec $($errors)*];
|
||||
// Test problems
|
||||
let (exp, cmp) = spanned![vec $($problems)*];
|
||||
let exp = exp.into_iter()
|
||||
.map(|s: Spanned<&str>| s.map(|e| e.to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
let found = pass.feedback.errors.into_iter()
|
||||
let found = pass.feedback.problems.into_iter()
|
||||
.map(|s| s.map(|e| e.message))
|
||||
.collect::<Vec<_>>();
|
||||
check($source, exp, found, cmp);
|
||||
|
@ -76,7 +76,7 @@ pub struct Span {
|
||||
}
|
||||
|
||||
impl Span {
|
||||
/// A dummy span.
|
||||
/// The zero span.
|
||||
pub const ZERO: Span = Span { start: Position::ZERO, end: Position::ZERO };
|
||||
|
||||
/// Create a new span from start and end positions.
|
||||
|
@ -29,7 +29,7 @@ where T: Debug + PartialEq + SpanlessEq {
|
||||
/// spanned![(0:0, 0:5, "hello"), (0:5, 0:3, "world")]
|
||||
/// ```
|
||||
/// The span information can simply be omitted to create a vector with items
|
||||
/// that are spanned with dummy zero spans.
|
||||
/// that are spanned with zero spans.
|
||||
macro_rules! spanned {
|
||||
(item ($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({
|
||||
#[allow(unused_imports)]
|
||||
@ -80,7 +80,7 @@ function! {
|
||||
}
|
||||
}
|
||||
|
||||
layout(self, ctx, errors) { vec![] }
|
||||
layout(self, ctx, f) { vec![] }
|
||||
}
|
||||
|
||||
/// Compares elements by only looking at values and ignoring spans.
|
||||
|
@ -123,14 +123,14 @@ fn test(name: &str, src: &str) -> DynResult<()> {
|
||||
fn compile(typesetter: &Typesetter, src: &str) -> MultiLayout {
|
||||
if cfg!(debug_assertions) {
|
||||
let typeset = block_on(typesetter.typeset(src));
|
||||
let errors = typeset.feedback.errors;
|
||||
let problems = typeset.feedback.problems;
|
||||
|
||||
if !errors.is_empty() {
|
||||
for error in errors {
|
||||
if !problems.is_empty() {
|
||||
for problem in problems {
|
||||
println!(" {:?} {:?}: {}",
|
||||
error.v.severity,
|
||||
error.span,
|
||||
error.v.message
|
||||
problem.v.severity,
|
||||
problem.span,
|
||||
problem.v.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user