Reports refactor [1/2]

This commit is contained in:
ef3d0c3e 2024-10-23 22:25:34 +02:00
parent f57173b9be
commit 72954cdad8
20 changed files with 757 additions and 884 deletions

View file

@ -4,9 +4,6 @@ use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use blockquote_style::AuthorPos::After;
use blockquote_style::AuthorPos::Before;
use blockquote_style::BlockquoteStyle;
@ -36,6 +33,8 @@ use crate::parser::style::StyleHolder;
use crate::parser::util::escape_text;
use crate::parser::util::Property;
use crate::parser::util::PropertyParser;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug)]
pub struct Blockquote {
@ -254,7 +253,7 @@ impl Rule for BlockquoteRule {
document: &'a (dyn Document<'a> + 'a),
cursor: Cursor,
_match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
let mut reports = vec![];
let content = cursor.source.content();
@ -273,19 +272,8 @@ impl Rule for BlockquoteRule {
if let Some(properties) = captures.get(1) {
match self.parse_properties(properties) {
Err(err) => {
reports.push(
Report::build(
ReportKind::Warning,
cursor.source.clone(),
properties.start(),
)
.with_message("Invalid Blockquote Properties")
.with_label(
Label::new((cursor.source.clone(), properties.range()))
.with_message(err)
.with_color(state.parser.colors().warning),
)
.finish(),
report_err!(&mut reports, cursor.source.clone(), "Invalid Blockquote Properties".into(),
span(properties.range(), err)
);
return (end_cursor, reports);
}
@ -342,15 +330,8 @@ impl Rule for BlockquoteRule {
} else if elem.downcast_ref::<Blockquote>().is_some() {
parsed_content.push(elem);
} else {
reports.push(
Report::build(ReportKind::Error, token.source(), token.range.start)
.with_message("Unable to Parse Blockquote Entry")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_message("Blockquotes may only contain paragraphs and other blockquotes")
.with_color(state.parser.colors().error),
)
.finish(),
report_err!(&mut reports, token.source(), "Unable to Parse Blockquote Entry".into(),
span(token.range.clone(), "Blockquotes may only contain paragraphs and other blockquotes".into())
);
return (end_cursor, reports);
}

View file

@ -9,9 +9,6 @@ use std::rc::Rc;
use std::sync::Arc;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
@ -29,6 +26,8 @@ use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::state::RuleState;
use crate::parser::state::Scope;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use super::paragraph::Paragraph;
@ -50,7 +49,7 @@ impl CustomStyle for LuaCustomStyle {
location: Token,
state: &ParserState,
document: &'a dyn Document<'a>,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let kernel: Ref<'_, Kernel> =
Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap());
//let kernel = RefMut::map(parser_state.shared.kernels.borrow(), |ker| ker.get("main").unwrap());
@ -64,19 +63,12 @@ impl CustomStyle for LuaCustomStyle {
kernel.run_with_context(ctx, |lua| {
let chunk = lua.load(self.start.as_str());
if let Err(err) = chunk.eval::<()>() {
reports.push(
Report::build(ReportKind::Error, location.source(), location.start())
.with_message("Lua execution failed")
.with_label(
Label::new((location.source(), location.range.clone()))
.with_message(err.to_string())
.with_color(state.parser.colors().error),
)
.with_note(format!(
report_err!(&mut reports, location.source(), "Lua execution failed".into(),
span(location.range.clone(), err.to_string()),
note(format!(
"When trying to start custom style {}",
self.name().fg(state.parser.colors().info)
))
.finish(),
);
}
});
@ -89,7 +81,7 @@ impl CustomStyle for LuaCustomStyle {
location: Token,
state: &ParserState,
document: &'a dyn Document<'a>,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let kernel: Ref<'_, Kernel> =
Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap());
let ctx = KernelContext {
@ -102,19 +94,12 @@ impl CustomStyle for LuaCustomStyle {
kernel.run_with_context(ctx, |lua| {
let chunk = lua.load(self.end.as_str());
if let Err(err) = chunk.eval::<()>() {
reports.push(
Report::build(ReportKind::Error, location.source(), location.start())
.with_message("Lua execution failed")
.with_label(
Label::new((location.source(), location.range.clone()))
.with_message(err.to_string())
.with_color(state.parser.colors().error),
)
.with_note(format!(
report_err!(&mut reports, location.source(), "Lua execution failed".into(),
span(location.range.clone(), err.to_string()),
note(format!(
"When trying to end custom style {}",
self.name().fg(state.parser.colors().info)
))
.finish(),
);
}
});
@ -130,11 +115,11 @@ struct CustomStyleState {
impl RuleState for CustomStyleState {
fn scope(&self) -> Scope { Scope::PARAGRAPH }
fn on_remove<'a>(
fn on_remove(
&self,
state: &ParserState,
document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
self.toggled.iter().for_each(|(style, token)| {
@ -150,26 +135,13 @@ impl RuleState for CustomStyleState {
})
.unwrap();
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Unterminated Custom Style")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_order(1)
.with_message(format!(
report_err!(&mut reports, token.source(), "Unterminated Custom Style".into(),
span(token.range.clone(), format!(
"Style {} starts here",
style.fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.with_label(
Label::new(paragraph_end)
.with_order(1)
.with_message("Paragraph ends here".to_string())
.with_color(state.parser.colors().error),
)
.with_note("Styles cannot span multiple documents (i.e @import)")
.finish(),
)),
span(paragraph_end.1, "Paragraph ends here".into()),
note("Styles cannot span multiple documents (i.e @import)".into())
);
});
@ -248,7 +220,7 @@ impl Rule for CustomStyleRule {
document: &'a dyn Document<'a>,
cursor: Cursor,
match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
let (style, end) = match_data
.downcast_ref::<(Rc<dyn CustomStyle>, bool)>()
.unwrap();
@ -299,22 +271,16 @@ impl Rule for CustomStyleRule {
let token =
Token::new(cursor.pos..cursor.pos + s_end.len(), cursor.source.clone());
if style_state.toggled.get(style.name()).is_none() {
return (
cursor.at(cursor.pos + s_end.len()),
vec![
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid End of Style")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_order(1)
.with_message(format!(
"Cannot end style {} here, is it not started anywhere",
let mut reports = vec![];
report_err!(&mut reports, token.source(), "Invalid End of Style".into(),
span(token.range.clone(), format!(
"Cannot end style {} here, it does not started anywhere",
style.name().fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish(),
],
);
return (
cursor.at(cursor.pos + s_end.len()),
reports
);
}
@ -327,33 +293,20 @@ impl Rule for CustomStyleRule {
cursor.source.clone(),
);
if let Some(start_token) = style_state.toggled.get(style.name()) {
let mut reports = vec![];
report_err!(&mut reports, token.source(), "Invalid Start of Style".into(),
span(token.range.clone(), format!(
"When trying to start custom style {}",
self.name().fg(state.parser.colors().info)
)),
span(start_token.range.clone(), format!(
"Style {} previously starts here",
self.name().fg(state.parser.colors().info)
)),
);
return (
cursor.at(cursor.pos + s_end.len()),
vec![Report::build(
ReportKind::Error,
start_token.source(),
start_token.start(),
)
.with_message("Invalid Start of Style")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_order(1)
.with_message(format!(
"Style cannot {} starts here",
style.name().fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.with_label(
Label::new((start_token.source(), start_token.range.clone()))
.with_order(2)
.with_message(format!(
"Style {} starts previously here",
style.name().fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish()],
reports
);
}

View file

@ -6,9 +6,6 @@ use std::rc::Rc;
use std::sync::Arc;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
@ -18,9 +15,10 @@ use regex::Regex;
use crate::document::document::Document;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParserState;
use crate::parser::reports::macros::*;
use crate::parser::reports::*;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
use crate::parser::source::Source;
#[auto_registry::auto_registry(registry = "rules", path = "crate::elements::elemstyle")]
pub struct ElemStyleRule {
@ -80,7 +78,7 @@ impl Rule for ElemStyleRule {
_document: &'a (dyn Document<'a> + 'a),
cursor: Cursor,
_match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
let mut reports = vec![];
let matches = self
.start_re
@ -93,33 +91,28 @@ impl Rule for ElemStyleRule {
// Check if empty
if trimmed.is_empty() {
reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), key.start())
.with_message("Empty Style Key")
.with_label(
Label::new((cursor.source.clone(), key.range()))
.with_message("Expected a non-empty style key".to_string())
.with_color(state.parser.colors().error),
)
.finish(),
report_err!(
&mut reports,
cursor.source.clone(),
"Empty Style Key".into(),
span(key.range(), "Expected a non-empty style key".into()),
);
return (cursor, reports);
}
// Check if key exists
if !state.shared.styles.borrow().is_registered(trimmed) {
reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), key.start())
.with_message("Unknown Style Key")
.with_label(
Label::new((cursor.source.clone(), key.range()))
.with_message(format!(
report_err!(
&mut reports,
cursor.source.clone(),
"Unknown Style Key".into(),
span(
key.range(),
format!(
"Could not find a style with key: {}",
trimmed.fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish(),
),
);
return (cursor, reports);
@ -135,17 +128,14 @@ impl Rule for ElemStyleRule {
&cursor.source.clone().content().as_str()[cursor.pos..],
) {
None => {
reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), cursor.pos)
.with_message("Invalid Style Value")
.with_label(
Label::new((cursor.source.clone(), matches.get(0).unwrap().range()))
.with_message(
"Unable to parse json string after style key".to_string(),
report_err!(
&mut reports,
cursor.source.clone(),
"Invalid Style Value".into(),
span(
matches.get(0).unwrap().range(),
"Unable to parse json string after style key".into()
)
.with_color(state.parser.colors().error),
)
.finish(),
);
return (cursor, reports);
}
@ -155,22 +145,18 @@ impl Rule for ElemStyleRule {
// Attempt to deserialize
match style.from_json(json) {
Err(err) => {
reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), cursor.pos)
.with_message("Invalid Style Value")
.with_label(
Label::new((
report_err!(
&mut reports,
cursor.source.clone(),
"Invalid Style Value".into(),
span(
cursor.pos..cursor.pos + json.len(),
))
.with_message(format!(
format!(
"Failed to serialize `{}` into style with key `{}`: {err}",
json.fg(state.parser.colors().highlight),
style.key().fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return (cursor, reports);
}

View file

@ -17,9 +17,6 @@ use crate::parser::state::RuleState;
use crate::parser::state::Scope;
use crate::parser::util::escape_text;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
@ -34,6 +31,8 @@ use std::ops::Range;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::Arc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum LayoutToken {
@ -253,11 +252,11 @@ struct LayoutState {
impl RuleState for LayoutState {
fn scope(&self) -> Scope { Scope::DOCUMENT }
fn on_remove<'a>(
fn on_remove(
&self,
state: &ParserState,
document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let doc_borrow = document.content().borrow();
@ -265,25 +264,23 @@ impl RuleState for LayoutState {
for (tokens, layout_type) in &self.stack {
let start = tokens.first().unwrap();
reports.push(
Report::build(ReportKind::Error, start.source(), start.start())
.with_message("Unterminated Layout")
.with_label(
Label::new((start.source(), start.range.start + 1..start.range.end))
.with_order(1)
.with_message(format!(
report_err!(
&mut reports,
start.source(),
"Unterminated Layout".into(),
span(
start.source(),
start.range.start+1..start.range.end,
format!(
"Layout {} stars here",
layout_type.name().fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.with_label(
Label::new((at.source(), at.range.clone()))
.with_order(2)
.with_message("Document ends here".to_string())
.with_color(state.parser.colors().error),
),
span(
at.source(),
at.range.clone(),
"Document ends here".into()
)
.finish(),
);
}
@ -340,24 +337,26 @@ impl LayoutRule {
}
pub fn parse_properties<'a>(
colors: &ReportColors,
mut reports: &mut Vec<Report>,
token: &Token,
layout_type: Rc<dyn LayoutType>,
properties: Option<Match>,
) -> Result<Option<Box<dyn Any>>, Report<'a, (Rc<dyn Source>, Range<usize>)>> {
) -> Option<Box<dyn Any>> {
match properties {
None => match layout_type.parse_properties("") {
Ok(props) => Ok(props),
Err(err) => Err(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Unable to parse layout properties")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_message(err)
.with_color(colors.error),
Ok(props) => props,
Err(err) => {
report_err!(
&mut reports,
token.source(),
"Invalid Layout Properties".into(),
span(
token.range.clone(),
format!("Layout is missing required property: {eee}")
)
.finish(),
),
);
None
}
},
Some(props) => {
let trimmed = props.as_str().trim_start().trim_end();

View file

@ -14,9 +14,6 @@ use crate::parser::source::Token;
use crate::parser::source::VirtualSource;
use crate::parser::util;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
@ -25,6 +22,8 @@ use regex::Regex;
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug)]
pub struct Link {
@ -109,39 +108,37 @@ impl RegexRule for LinkRule {
document: &'a (dyn Document<'a> + 'a),
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let link_display = match matches.get(1) {
Some(display) => {
if display.as_str().is_empty() {
reports.push(
Report::build(ReportKind::Error, token.source(), display.start())
.with_message("Empty link name")
.with_label(
Label::new((token.source().clone(), display.range()))
.with_message("Link name is empty")
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Empty Link Display".into(),
span(
display.range(),
"Link display is empty".into()
)
.finish(),
);
return reports;
}
let display_source = util::escape_source(token.source(), display.range(), "Link Display".into(), '\\', "](");
if display_source.content().is_empty() {
reports.push(
Report::build(ReportKind::Error, token.source(), display.start())
.with_message("Empty link name")
.with_label(
Label::new((token.source(), display.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Empty Link Display".into(),
span(
display.range(),
format!(
"Link name is empty. Once processed, `{}` yields `{}`",
display.as_str().fg(state.parser.colors().highlight),
display_source.fg(state.parser.colors().highlight),
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return reports;
}
@ -156,15 +153,14 @@ impl RegexRule for LinkRule {
}
match util::parse_paragraph(state, display_source, document) {
Err(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), display.start())
.with_message("Failed to parse link display")
.with_label(
Label::new((token.source(), display.range()))
.with_message(err.to_string())
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Link Display".into(),
span(
display.range(),
format!("Failed to parse link display:\n{err}")
)
.finish(),
);
return reports;
}
@ -177,34 +173,32 @@ impl RegexRule for LinkRule {
let link_url = match matches.get(2) {
Some(url) => {
if url.as_str().is_empty() {
reports.push(
Report::build(ReportKind::Error, token.source(), url.start())
.with_message("Empty link url")
.with_label(
Label::new((token.source(), url.range()))
.with_message("Link url is empty")
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Empty Link URL".into(),
span(
url.range(),
"Link url is empty".into()
)
.finish(),
);
return reports;
}
let text_content = util::process_text(document, url.as_str());
if text_content.is_empty() {
reports.push(
Report::build(ReportKind::Error, token.source(), url.start())
.with_message("Empty link url")
.with_label(
Label::new((token.source(), url.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Empty Link URL".into(),
span(
url.range(),
format!(
"Link url is empty. Once processed, `{}` yields `{}`",
url.as_str().fg(state.parser.colors().highlight),
text_content.as_str().fg(state.parser.colors().highlight),
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return reports;
}

View file

@ -14,9 +14,9 @@ use crate::document::element::Element;
use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::reports::Report;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::source::VirtualSource;
use crate::parser::util;
@ -24,9 +24,8 @@ use crate::parser::util::escape_text;
use crate::parser::util::Property;
use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use regex::Match;
use regex::Regex;
@ -293,7 +292,7 @@ impl Rule for ListRule {
document: &'a dyn Document<'a>,
cursor: Cursor,
_match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
let mut reports = vec![];
let content = cursor.source.content();
@ -312,19 +311,8 @@ impl Rule for ListRule {
if let Some(properties) = captures.get(2) {
match self.parse_properties(properties) {
Err(err) => {
reports.push(
Report::build(
ReportKind::Warning,
cursor.source.clone(),
properties.start(),
)
.with_message("Invalid List Entry Properties")
.with_label(
Label::new((cursor.source.clone(), properties.range()))
.with_message(err)
.with_color(state.parser.colors().warning),
)
.finish(),
report_err!(&mut reports, cursor.source.clone(), "Invalid List Entry Properties".into(),
span(properties.range(), err)
);
return (cursor.at(captures.get(0).unwrap().end()), reports);
}
@ -391,15 +379,8 @@ impl Rule for ListRule {
));
let parsed_content = match util::parse_paragraph(state, entry_src, document) {
Err(err) => {
reports.push(
Report::build(ReportKind::Warning, token.source(), token.range.start)
.with_message("Unable to Parse List Entry")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_message(err)
.with_color(state.parser.colors().warning),
)
.finish(),
report_warn!(&mut reports, token.source(), "Unable to parse List Entry".into(),
span(token.range.clone(), err.into())
);
// Return an empty paragraph
vec![]

View file

@ -4,9 +4,6 @@ use std::rc::Rc;
use std::str::FromStr;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use regex::Captures;
use regex::Match;
use regex::Regex;
@ -34,6 +31,8 @@ use crate::parser::util::Property;
use crate::parser::util::PropertyMap;
use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use super::paragraph::Paragraph;
use super::reference::InternalReference;
@ -286,39 +285,43 @@ impl MediaRule {
fn parse_properties(
&self,
colors: &ReportColors,
mut reports: &mut Vec<Report>,
token: &Token,
m: &Option<Match>,
) -> Result<PropertyMap, Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Option<PropertyMap> {
match m {
None => match self.properties.default() {
Ok(properties) => Ok(properties),
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Media Properties")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!("Media is missing required property: {e}"))
.with_color(colors.error),
Ok(properties) => Some(properties),
Err(e) => {
report_err!(
&mut reports,
token.source(),
"Invalid Media Properties".into(),
span(
token.range.clone(),
format!("Media is missing required property: {e}")
)
.finish(),
),
);
None
}
},
Some(props) => {
let processed =
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start())
.with_message("Invalid Media Properties")
.with_label(
Label::new((token.source().clone(), props.range()))
.with_message(e)
.with_color(colors.error),
Err(e) => {
report_err!(
&mut reports,
token.source(),
"Invalid Media Properties".into(),
span(
props.range(),
e
)
.finish(),
),
Ok(properties) => Ok(properties),
);
None
},
Ok(properties) => Some(properties),
}
}
}
@ -357,7 +360,7 @@ impl RegexRule for MediaRule {
document: &'a (dyn Document<'a> + 'a),
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let refname = match (
@ -366,13 +369,14 @@ impl RegexRule for MediaRule {
) {
(_, Ok(refname)) => refname.to_string(),
(m, Err(err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), m.start())
.with_message("Invalid Media Refname")
.with_label(
Label::new((token.source().clone(), m.range())).with_message(err),
report_err!(
&mut reports,
token.source(),
"Invalid Media Refname".into(),
span(
m.range(),
err
)
.finish(),
);
return reports;
}
@ -384,26 +388,24 @@ impl RegexRule for MediaRule {
) {
(_, Ok(uri)) => util::escape_text('\\', ")", uri),
(m, Err(err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), m.start())
.with_message("Invalid Media URI")
.with_label(
Label::new((token.source().clone(), m.range())).with_message(err),
report_err!(
&mut reports,
token.source(),
"Invalid Media URI".into(),
span(
m.range(),
err
)
.finish(),
);
return reports;
}
};
// Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(3))
let properties = match self.parse_properties(&mut reports, &token, &matches.get(3))
{
Ok(pm) => pm,
Err(report) => {
reports.push(report);
return reports;
}
Some(pm) => pm,
None => return reports,
};
let media_type =
@ -415,35 +417,30 @@ impl RegexRule for MediaRule {
Ok((_prop, kind)) => kind,
Err(e) => match e {
PropertyMapError::ParseError((prop, err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Media Property")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Media Property".into(),
span(
token.start()+1..token.end(),
format!(
"Property `type: {}` cannot be converted: {}",
prop.fg(state.parser.colors().info),
err.fg(state.parser.colors().error)
))
.with_color(state.parser.colors().warning),
)
.finish(),
)
);
return reports;
}
PropertyMapError::NotFoundError(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Media Property")
.with_label(
Label::new((
token.source().clone(),
token.start() + 1..token.end(),
))
.with_message(format!("{err}. Required because mediatype could not be detected"))
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Media Property".into(),
span(
token.start()+1..token.end(),
format!("{err}. Required because mediatype could not be detected")
)
.finish(),
);
return reports;
}
@ -478,17 +475,16 @@ impl RegexRule for MediaRule {
match parse_paragraph(state, source, document) {
Ok(paragraph) => Some(*paragraph),
Err(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), content.start())
.with_message("Invalid Media Description")
.with_label(
Label::new((token.source().clone(), content.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Media Description".into(),
span(
content.range(),
format!(
"Could not parse description: {err}"
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return reports;
}
@ -522,15 +518,15 @@ impl RegexRule for MediaRule {
caption,
description,
})) {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Media")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(err)
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Media".into(),
span(
token.range.clone(),
err
)
.finish(),
);
}

View file

@ -6,25 +6,21 @@ use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::util::Property;
use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use crate::parser::util::{self};
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
use regex::Captures;
use regex::Regex;
use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::Arc;
@ -94,25 +90,24 @@ impl RegexRule for RawRule {
document: &dyn Document,
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let raw_content = match matches.get(2) {
// Unterminated
None => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Unterminated Raw Code")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unterminated Raw Code".into(),
span(
token.range.clone(),
format!(
"Missing terminating `{}` after first `{}`",
"?}".fg(state.parser.colors().info),
"{?".fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return reports;
}
@ -121,15 +116,11 @@ impl RegexRule for RawRule {
util::escape_text('\\', "?}", content.as_str().trim_start().trim_end());
if processed.is_empty() {
reports.push(
Report::build(ReportKind::Warning, token.source(), content.start())
.with_message("Empty Raw Code")
.with_label(
Label::new((token.source().clone(), content.range()))
.with_message("Raw code is empty")
.with_color(state.parser.colors().warning),
)
.finish(),
report_warn!(
&mut reports,
token.source(),
"Empty Raw Code".into(),
span(content.range(), "Raw code is empty".into())
);
}
processed
@ -140,15 +131,14 @@ impl RegexRule for RawRule {
None => match self.properties.default() {
Ok(properties) => properties,
Err(e) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Raw Code")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!("Raw code is missing properties: {e}"))
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Raw Code".into(),
span(
token.range.clone(),
format!("Raw code is missing properties: {e}")
)
.finish(),
);
return reports;
}
@ -158,15 +148,11 @@ impl RegexRule for RawRule {
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => {
reports.push(
Report::build(ReportKind::Error, token.source(), props.start())
.with_message("Invalid Raw Code Properties")
.with_label(
Label::new((token.source().clone(), props.range()))
.with_message(e)
.with_color(state.parser.colors().error),
)
.finish(),
report_err!(
&mut reports,
token.source(),
"Invalid Raw Code Properties".into(),
span(props.range(), e)
);
return reports;
}
@ -181,38 +167,33 @@ impl RegexRule for RawRule {
Ok((_prop, kind)) => kind,
Err(e) => match e {
PropertyMapError::ParseError((prop, err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Raw Code Property")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Raw Code Properties".into(),
span(
token.range.clone(),
format!(
"Property `kind: {}` cannot be converted: {}",
prop.fg(state.parser.colors().info),
err.fg(state.parser.colors().error)
))
.with_color(state.parser.colors().warning),
)
.finish(),
)
);
return reports;
}
PropertyMapError::NotFoundError(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Code Property")
.with_label(
Label::new((
token.source().clone(),
token.start() + 1..token.end(),
))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Raw Code Properties".into(),
span(
token.range.clone(),
format!(
"Property `{}` is missing",
err.fg(state.parser.colors().info)
))
.with_color(state.parser.colors().warning),
)
.finish(),
)
);
return reports;
}
@ -232,15 +213,14 @@ impl RegexRule for RawRule {
Semantics::from_source(token.source(), &state.shared.semantics)
{
let range = matches.get(0).unwrap().range();
sems.add(range.start..range.start+2, tokens.raw_sep);
if let Some(props) = matches.get(1).map(|m| m.range())
{
sems.add(range.start..range.start + 2, tokens.raw_sep);
if let Some(props) = matches.get(1).map(|m| m.range()) {
sems.add(props.start - 1..props.start, tokens.raw_props_sep);
sems.add(props.clone(), tokens.raw_props);
sems.add(props.end..props.end + 1, tokens.raw_props_sep);
}
sems.add(matches.get(2).unwrap().range(), tokens.raw_content);
sems.add(range.end-2..range.end, tokens.raw_sep);
sems.add(range.end - 2..range.end, tokens.raw_sep);
}
reports
@ -297,7 +277,8 @@ mod tests {
use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::{validate_document, validate_semantics};
use crate::validate_document;
use crate::validate_semantics;
#[test]
fn parser() {

View file

@ -2,9 +2,6 @@ use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use reference_style::ExternalReferenceStyle;
use regex::Captures;
use regex::Match;
@ -32,6 +29,8 @@ use crate::parser::util;
use crate::parser::util::Property;
use crate::parser::util::PropertyMap;
use crate::parser::util::PropertyParser;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug)]
pub struct InternalReference {
@ -186,39 +185,43 @@ impl ReferenceRule {
fn parse_properties(
&self,
colors: &ReportColors,
mut reports: &mut Vec<Report>,
token: &Token,
m: &Option<Match>,
) -> Result<PropertyMap, Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Option<PropertyMap> {
match m {
None => match self.properties.default() {
Ok(properties) => Ok(properties),
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Media Properties")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!("Media is missing required property: {e}"))
.with_color(colors.error),
Ok(properties) => Some(properties),
Err(e) => {
report_err!(
&mut reports,
token.source(),
"Invalid Reference Properties".into(),
span(
token.range.clone(),
format!("Reference is missing required property: {e}")
)
.finish(),
),
);
None
}
},
Some(props) => {
let processed =
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start())
.with_message("Invalid Media Properties")
.with_label(
Label::new((token.source().clone(), props.range()))
.with_message(e)
.with_color(colors.error),
Err(e) => {
report_err!(
&mut reports,
token.source(),
"Invalid Reference Properties".into(),
span(
props.range(),
e
)
.finish(),
),
Ok(properties) => Ok(properties),
);
None
},
Ok(properties) => Some(properties),
}
}
}
@ -241,7 +244,7 @@ impl RegexRule for ReferenceRule {
document: &'a (dyn Document<'a> + 'a),
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let (refdoc, refname) = if let Some(refname_match) = matches.get(1) {
@ -252,14 +255,14 @@ impl RegexRule for ReferenceRule {
match validate_refname(document, refname_match.as_str().split_at(sep + 1).1, false)
{
Err(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), refname_match.start())
.with_message("Invalid Reference Refname")
.with_label(
Label::new((token.source().clone(), refname_match.range()))
.with_message(err),
report_err!(
&mut reports,
token.source(),
"Invalid Reference Refname".into(),
span(
refname_match.range(),
err
)
.finish(),
);
return reports;
}
@ -270,14 +273,14 @@ impl RegexRule for ReferenceRule {
{
match validate_refname(document, refname_match.as_str(), false) {
Err(err) => {
reports.push(
Report::build(ReportKind::Error, token.source(), refname_match.start())
.with_message("Invalid Reference Refname")
.with_label(
Label::new((token.source().clone(), refname_match.range()))
.with_message(err),
report_err!(
&mut reports,
token.source(),
"Invalid Reference Refname".into(),
span(
refname_match.range(),
err
)
.finish(),
);
return reports;
}
@ -289,13 +292,10 @@ impl RegexRule for ReferenceRule {
};
// Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(2))
let properties = match self.parse_properties(&mut reports, &token, &matches.get(2))
{
Ok(pm) => pm,
Err(report) => {
reports.push(report);
return reports;
}
Some(pm) => pm,
None => return reports,
};
let caption = properties

View file

@ -12,14 +12,13 @@ use crate::parser::source::VirtualSource;
use crate::parser::util;
use crate::parser::util::escape_source;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Lua;
use regex::Captures;
use regex::Regex;
use std::ops::Range;
use std::rc::Rc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use super::text::Text;
@ -95,7 +94,7 @@ impl RegexRule for ScriptRule {
document: &'a dyn Document<'a>,
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let kernel_name = match matches.get(1) {
@ -104,15 +103,14 @@ impl RegexRule for ScriptRule {
match ScriptRule::validate_kernel_name(state.parser.colors(), name.as_str()) {
Ok(name) => name,
Err(e) => {
reports.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Invalid kernel name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(e)
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Kernel Name".into(),
span(
name.range(),
e
)
.finish(),
);
return reports;
}
@ -136,15 +134,14 @@ impl RegexRule for ScriptRule {
), '\\', ">@");
if source.content().is_empty()
{
reports.push(
Report::build(ReportKind::Warning, token.source(), token.start())
.with_message("Invalid kernel code")
.with_label(
Label::new((token.source(), script_range))
.with_message("Kernel code is empty")
.with_color(state.parser.colors().warning),
report_warn!(
&mut reports,
token.source(),
"Invalid Kernel Code".into(),
span(
script_range,
"Kernel code is empty".into(),
)
.finish(),
);
return reports;
}
@ -157,15 +154,14 @@ impl RegexRule for ScriptRule {
// Exec
{
if let Err(e) = chunk.exec() {
reports.push(
Report::build(ReportKind::Error, source.clone(), 0)
.with_message("Invalid kernel code")
.with_label(
Label::new((source.clone(), 0..source.content().len()))
.with_message(format!("Kernel execution failed:\n{}", e))
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
source.clone(),
"Invalid Kernel Code".into(),
span(
0..source.content().len(),
format!("Kernel execution failed:\n{}", e)
)
.finish(),
);
return reports;
}
@ -178,15 +174,14 @@ impl RegexRule for ScriptRule {
Some(kind) => match self.validate_kind(state.parser.colors(), kind.as_str()) {
Ok(kind) => kind,
Err(msg) => {
reports.push(
Report::build(ReportKind::Error, token.source(), kind.start())
.with_message("Invalid kernel code kind")
.with_label(
Label::new((token.source(), kind.range()))
.with_message(msg)
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Kernel Code Kind".into(),
span(
kind.range(),
msg
)
.finish(),
);
return reports;
}
@ -197,15 +192,14 @@ impl RegexRule for ScriptRule {
// Eval
{
if let Err(e) = chunk.eval::<()>() {
reports.push(
Report::build(ReportKind::Error, source.clone(), 0)
.with_message("Invalid kernel code")
.with_label(
Label::new((source.clone(), 0..source.content().len()))
.with_message(format!("Kernel evaluation failed:\n{}", e))
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
source.clone(),
"Invalid Kernel Code".into(),
span(
0..source.content().len(),
format!("Kernel evaluation failed:\n{}", e)
)
.finish(),
);
}
} else
@ -245,18 +239,14 @@ impl RegexRule for ScriptRule {
}
}
Err(e) => {
reports.push(
Report::build(ReportKind::Error, source.clone(), 0)
.with_message("Invalid kernel code")
.with_label(
Label::new((source.clone(), 0..source.content().len()))
.with_message(format!(
"Kernel evaluation failed:\n{}",
e
))
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
source.clone(),
"Invalid Kernel Code".into(),
span(
0..source.content().len(),
format!("Kernel evaluation failed:\n{}", e)
)
.finish(),
);
}
}

View file

@ -13,9 +13,6 @@ use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::style::StyleHolder;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Error::BadArgument;
use mlua::Function;
use mlua::Lua;
@ -25,6 +22,8 @@ use section_style::SectionStyle;
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use super::reference::InternalReference;
@ -183,22 +182,22 @@ impl RegexRule for SectionRule {
document: &dyn Document,
token: Token,
matches: regex::Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
let mut result = vec![];
) -> Vec<Report> {
let mut reports = vec![];
let section_depth = match matches.get(1) {
Some(depth) => {
if depth.len() > 6 {
result.push(
Report::build(ReportKind::Error, token.source(), depth.start())
.with_message("Invalid section depth")
.with_label(
Label::new((token.source(), depth.range()))
.with_message(format!("Section is of depth {}, which is greather than {} (maximum depth allowed)",
report_err!(
&mut reports,
token.source(),
"Invalid Section Depth".into(),
span(
depth.range(),
format!("Section is of depth {}, which is greather than {} (maximum depth allowed)",
depth.len().fg(state.parser.colors().info),
6.fg(state.parser.colors().info)))
.with_color(state.parser.colors().error))
.finish());
return result;
6.fg(state.parser.colors().info))
)
);
}
depth.len()
@ -215,25 +214,27 @@ impl RegexRule for SectionRule {
if let Some(elem_reference) = document.get_reference(refname.as_str()) {
let elem = document.get_from_reference(&elem_reference).unwrap();
result.push(
Report::build(ReportKind::Warning, token.source(), refname.start())
.with_message("Duplicate reference name")
.with_label(
Label::new((token.source(), refname.range()))
.with_message(format!("Reference with name `{}` is already defined in `{}`",
report_warn!(
&mut reports,
token.source(),
"Duplicate Reference Name".into(),
span(
refname.range(),
format!("Reference with name `{}` is already defined in `{}`. `{}` conflicts with previously defined reference to {}",
refname.as_str().fg(state.parser.colors().highlight),
elem.location().source().name().as_str().fg(state.parser.colors().highlight)))
.with_message(format!("`{}` conflicts with previously defined reference to {}",
elem.location().source().name().as_str().fg(state.parser.colors().highlight),
refname.as_str().fg(state.parser.colors().highlight),
elem.element_name().fg(state.parser.colors().highlight)))
.with_color(state.parser.colors().warning))
.with_label(
Label::new((elem.location().source(), elem.location().start()..elem.location().end() ))
.with_message(format!("`{}` previously defined here",
refname.as_str().fg(state.parser.colors().highlight)))
.with_color(state.parser.colors().warning))
.with_note("Previous reference was overwritten".to_string())
.finish());
elem.element_name().fg(state.parser.colors().highlight))
),
span(
elem.location().source(),
elem.location().start()..elem.location().end(),
format!("`{}` previously defined here",
refname.as_str().fg(state.parser.colors().highlight))
),
note("Previous reference was overwritten".into())
);
}
Some(refname.as_str().to_string())
},
@ -247,19 +248,20 @@ impl RegexRule for SectionRule {
"+" => section_kind::NO_TOC,
"" => section_kind::NONE,
_ => {
result.push(
Report::build(ReportKind::Error, token.source(), kind.start())
.with_message("Invalid section numbering kind")
.with_label(
Label::new((token.source(), kind.range()))
.with_message(format!("Section numbering kind must be a combination of `{}` for unnumbered, and `{}` for non-listing; got `{}`",
report_err!(
&mut reports,
token.source(),
"Invalid Section Numbering Kind".into(),
span(
kind.range(),
format!("Section numbering kind must be a combination of `{}` for unnumbered, and `{}` for non-listing; got `{}`",
"*".fg(state.parser.colors().info),
"+".fg(state.parser.colors().info),
kind.as_str().fg(state.parser.colors().highlight)))
.with_color(state.parser.colors().error))
.with_help("Leave empty for a numbered listed section".to_string())
.finish());
return result;
kind.as_str().fg(state.parser.colors().highlight))
),
help("Leave empty for a numbered listed section".into())
);
return reports;
}
},
_ => section_kind::NONE,
@ -278,31 +280,31 @@ impl RegexRule for SectionRule {
if section_name.is_empty()
// No name
{
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Missing section name")
.with_label(
Label::new((token.source(), name.range()))
.with_message("Sections require a name before line end")
.with_color(state.parser.colors().error),
)
.finish(),
report_err!(
&mut reports,
token.source(),
"Missing Section Name".into(),
span(
name.range(),
"Section name must be specified before line end".into()
),
);
return result;
return reports;
}
// No spacing
if split == 0 {
result.push(
Report::build(ReportKind::Warning, token.source(), name.start())
.with_message("Missing section spacing")
.with_label(
Label::new((token.source(), name.range()))
.with_message("Sections require at least one whitespace before the section's name")
.with_color(state.parser.colors().warning))
.with_help(format!("Add a space before `{}`", section_name.fg(state.parser.colors().highlight)))
.finish());
return result;
report_err!(
&mut reports,
token.source(),
"Missing Section Spacing".into(),
span(
name.range(),
"Sections require at least one whitespace before the section's name".into()
),
help(format!("Add a space before `{}`", section_name.fg(state.parser.colors().highlight)))
);
return reports;
}
section_name.to_string()
@ -347,7 +349,7 @@ impl RegexRule for SectionRule {
sems.add(matches.get(5).unwrap().range(), tokens.section_name);
}
result
reports
}
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {

View file

@ -14,9 +14,6 @@ use crate::parser::source::Token;
use crate::parser::state::RuleState;
use crate::parser::state::Scope;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Function;
use regex::Captures;
use regex::Regex;
@ -24,6 +21,8 @@ use std::cell::RefCell;
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
use super::paragraph::Paragraph;
@ -87,11 +86,11 @@ impl StyleState {
impl RuleState for StyleState {
fn scope(&self) -> Scope { Scope::PARAGRAPH }
fn on_remove<'a>(
fn on_remove(
&self,
state: &ParserState,
document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
self.toggled
@ -114,27 +113,22 @@ impl RuleState for StyleState {
)
})
.unwrap();
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Unterminated Style")
.with_label(
Label::new((token.source(), token.range.clone()))
.with_order(1)
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unterminated Style".into(),
span(
token.range.clone(),
format!(
"Style {} starts here",
name.fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.with_label(
Label::new(paragraph_end)
.with_order(1)
.with_message("Paragraph ends here".to_string())
.with_color(state.parser.colors().error),
)
.with_note("Styles cannot span multiple documents (i.e @import)")
.finish(),
),
span(
paragraph_end.1,
"Paragraph ends here".into()
),
note("Styles cannot span multiple documents (i.e @import)".into())
);
});
@ -182,7 +176,7 @@ impl RegexRule for StyleRule {
document: &dyn Document,
token: Token,
_matches: Captures,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let query = state.shared.rule_state.borrow().get(STATE_NAME);
let style_state = match query {
Some(state) => state,

View file

@ -10,9 +10,6 @@ use std::sync::Arc;
use std::sync::Once;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use crypto::digest::Digest;
use crypto::sha2::Sha512;
use mlua::Function;
@ -41,6 +38,8 @@ use crate::parser::util::Property;
use crate::parser::util::PropertyMap;
use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug, PartialEq, Eq)]
enum TexKind {
@ -266,39 +265,45 @@ impl TexRule {
fn parse_properties(
&self,
mut reports: &mut Vec<Report>,
colors: &ReportColors,
token: &Token,
m: &Option<Match>,
) -> Result<PropertyMap, Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Option<PropertyMap> {
match m {
None => match self.properties.default() {
Ok(properties) => Ok(properties),
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Tex Properties")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!("Tex is missing required property: {e}"))
.with_color(colors.error),
Ok(properties) => Some(properties),
Err(e) =>
{
report_err!(
&mut reports,
token.source(),
"Invalid Tex Properties".into(),
span(
token.range.clone(),
format!("Tex is missing required property: {e}")
)
.finish(),
),
);
None
}
},
Some(props) => {
let processed =
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start())
.with_message("Invalid Tex Properties")
.with_label(
Label::new((token.source().clone(), props.range()))
.with_message(e)
.with_color(colors.error),
Err(e) => {
report_err!(
&mut reports,
token.source(),
"Invalid Tex Properties".into(),
span(
props.range(),
e
)
.finish(),
),
Ok(properties) => Ok(properties),
);
None
},
Ok(properties) => Some(properties),
}
}
}
@ -321,25 +326,24 @@ impl RegexRule for TexRule {
document: &dyn Document,
token: Token,
matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
let tex_content = match matches.get(2) {
// Unterminated `$`
None => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Unterminated Tex Code")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unterminated Tex Code".into(),
span(
token.range.clone(),
format!(
"Missing terminating `{}` after first `{}`",
["|$", "$"][index].fg(state.parser.colors().info),
["$|", "$"][index].fg(state.parser.colors().info)
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return reports;
}
@ -351,15 +355,14 @@ impl RegexRule for TexRule {
);
if processed.is_empty() {
reports.push(
Report::build(ReportKind::Warning, token.source(), content.start())
.with_message("Empty Tex Code")
.with_label(
Label::new((token.source().clone(), content.range()))
.with_message("Tex code is empty")
.with_color(state.parser.colors().warning),
report_err!(
&mut reports,
token.source(),
"Empty Tex Code".into(),
span(
content.range(),
"Tex code is empty".into()
)
.finish(),
);
}
processed
@ -367,13 +370,10 @@ impl RegexRule for TexRule {
};
// Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(1))
let properties = match self.parse_properties(&mut reports, state.parser.colors(), &token, &matches.get(1))
{
Ok(pm) => pm,
Err(report) => {
reports.push(report);
return reports;
}
Some(pm) => pm,
None => return reports,
};
// Tex kind
@ -383,19 +383,19 @@ impl RegexRule for TexRule {
Ok((_prop, kind)) => kind,
Err(e) => match e {
PropertyMapError::ParseError((prop, err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), token.start())
.with_message("Invalid Tex Property")
.with_label(
Label::new((token.source().clone(), token.range.clone()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Tex Property".into(),
span(
token.range.clone(),
format!(
"Property `kind: {}` cannot be converted: {}",
prop.fg(state.parser.colors().info),
err.fg(state.parser.colors().error)
))
.with_color(state.parser.colors().warning),
)
.finish(),
)
);
return reports;
}

View file

@ -2,7 +2,6 @@ use std::any::Any;
use std::ops::Range;
use std::rc::Rc;
use ariadne::Report;
use mlua::Function;
use mlua::Lua;
@ -17,6 +16,7 @@ use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::reports::*;
#[derive(Debug)]
pub struct Text {
@ -70,7 +70,7 @@ impl Rule for TextRule {
_document: &dyn Document,
_cursor: Cursor,
_match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
panic!("Text cannot match");
}

View file

@ -11,15 +11,14 @@ use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
use crate::parser::source::Token;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
use ariadne::ReportKind;
use mlua::Function;
use mlua::Lua;
use regex::Regex;
use std::ops::Range;
use std::rc::Rc;
use std::str::FromStr;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum VariableKind {
@ -134,8 +133,8 @@ impl RegexRule for VariableRule {
document: &dyn Document,
token: Token,
matches: regex::Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
let mut result = vec![];
) -> Vec<Report> {
let mut reports = vec![];
// [Optional] variable kind
let var_kind = match matches.get(1) {
Some(kind) => {
@ -148,18 +147,18 @@ impl RegexRule for VariableRule {
// Unknown kind specified
if r.is_none() {
result.push(
Report::build(ReportKind::Error, token.source(), kind.start())
.with_message("Unknown variable kind")
.with_label(
Label::new((token.source(), kind.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unknowm Variable Kind".into(),
span(
kind.range(),
format!(
"Variable kind `{}` is unknown",
kind.as_str().fg(state.parser.colors().highlight)
))
.with_color(state.parser.colors().error),
)
.with_help(format!(
),
help(format!(
"Leave empty for regular variables. Available variable kinds:{}",
self.kinds.iter().skip(1).fold(
"".to_string(),
@ -173,10 +172,8 @@ impl RegexRule for VariableRule {
}
)
))
.finish(),
);
return result;
return reports;
}
r.unwrap().0
@ -188,21 +185,20 @@ impl RegexRule for VariableRule {
Some(name) => match VariableRule::validate_name(state.parser.colors(), name.as_str()) {
Ok(var_name) => var_name,
Err(msg) => {
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Invalid variable name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Variable Name".into(),
span(
name.range(),
format!(
"Variable name `{}` is not allowed. {msg}",
name.as_str().fg(state.parser.colors().highlight)
))
.with_color(state.parser.colors().error),
)
.finish(),
),
);
return result;
return reports;
}
},
_ => panic!("Unknown variable name"),
@ -212,21 +208,20 @@ impl RegexRule for VariableRule {
Some(value) => match VariableRule::validate_value(value.as_str()) {
Ok(var_value) => var_value,
Err(msg) => {
result.push(
Report::build(ReportKind::Error, token.source(), value.start())
.with_message("Invalid variable value")
.with_label(
Label::new((token.source(), value.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Invalid Variable Value".into(),
span(
value.range(),
format!(
"Variable value `{}` is not allowed. {msg}",
value.as_str().fg(state.parser.colors().highlight)
))
.with_color(state.parser.colors().error),
)
.finish(),
),
);
return result;
return reports;
}
},
_ => panic!("Invalid variable value"),
@ -242,22 +237,21 @@ impl RegexRule for VariableRule {
Ok(variable) => document.add_variable(variable),
Err(msg) => {
let m = matches.get(0).unwrap();
result.push(
Report::build(ReportKind::Error, token.source(), m.start())
.with_message("Unable to create variable")
.with_label(
Label::new((token.source(), m.start() + 1..m.end()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unable to Create Variable".into(),
span(
m.start() + 1..m.end(),
format!(
"Unable to create variable `{}`. {}",
var_name.fg(state.parser.colors().highlight),
msg
))
.with_color(state.parser.colors().error),
)
.finish(),
),
);
return result;
return reports;
}
}
@ -277,7 +271,7 @@ impl RegexRule for VariableRule {
sems.add(value.clone(), tokens.variable_value);
}
result
reports
}
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
@ -346,98 +340,87 @@ impl RegexRule for VariableSubstitutionRule {
document: &'a dyn Document<'a>,
token: Token,
matches: regex::Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
let mut result = vec![];
) -> Vec<Report> {
let mut reports = vec![];
let variable = match matches.get(1) {
Some(name) => {
// Empty name
if name.as_str().is_empty() {
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Empty variable name")
.with_label(
Label::new((token.source(), matches.get(0).unwrap().range()))
.with_message(
"Missing variable name for substitution".to_string(),
report_err!(
&mut reports,
token.source(),
"Empty Variable Name".into(),
span(
name.range(),
"Missing variable name for substitution".into(),
)
.with_color(state.parser.colors().error),
)
.finish(),
);
return result;
return reports;
}
// Leading spaces
else if name.as_str().trim_start() != name.as_str() {
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Invalid variable name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(
"Variable names contains leading spaces".to_string(),
)
.with_color(state.parser.colors().error),
)
.with_help("Remove leading spaces")
.finish(),
report_err!(
&mut reports,
token.source(),
"Invalid Variable Name".into(),
span(
name.range(),
"Variable names contains leading spaces".into(),
),
help("Remove leading spaces".into())
);
return result;
return reports;
}
// Trailing spaces
else if name.as_str().trim_end() != name.as_str() {
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Invalid variable name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(
"Variable names contains trailing spaces".to_string(),
)
.with_color(state.parser.colors().error),
)
.with_help("Remove trailing spaces")
.finish(),
report_err!(
&mut reports,
token.source(),
"Invalid Variable Name".into(),
span(
name.range(),
"Variable names contains trailing spaces".into(),
),
help("Remove trailing spaces".into())
);
return result;
return reports;
}
// Invalid name
if let Err(msg) = VariableRule::validate_name(state.parser.colors(), name.as_str())
{
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Invalid variable name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(msg)
.with_color(state.parser.colors().error),
report_err!(
&mut reports,
token.source(),
"Invalid Variable Name".into(),
span(
name.range(),
msg
)
.finish(),
);
return result;
return reports;
}
// Get variable
match document.get_variable(name.as_str()) {
None => {
result.push(
Report::build(ReportKind::Error, token.source(), name.start())
.with_message("Unknown variable name")
.with_label(
Label::new((token.source(), name.range()))
.with_message(format!(
report_err!(
&mut reports,
token.source(),
"Unknown Variable Name".into(),
span(
name.range(),
format!(
"Unable to find variable with name: `{}`",
name.as_str().fg(state.parser.colors().highlight)
))
.with_color(state.parser.colors().error),
)
.finish(),
)
);
return result;
return reports;
}
Some(var) => var,
}
@ -456,6 +439,6 @@ impl RegexRule for VariableSubstitutionRule {
sems.add(name.end..name.end + 1, tokens.variable_sub_sep);
}
result
reports
}
}

View file

@ -1,14 +1,13 @@
use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
use std::ops::Deref;
use ariadne::Report;
use crate::document::document::Document;
use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::reports::*;
use super::parser::ParserState;
#[derive(Debug, PartialEq, Eq)]
@ -28,13 +27,13 @@ pub trait CustomStyle: core::fmt::Debug {
location: Token,
state: &ParserState,
document: &'a (dyn Document<'a> + 'a),
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>;
) -> Vec<Report>;
fn on_end<'a>(
&self,
location: Token,
state: &ParserState,
document: &'a (dyn Document<'a> + 'a),
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>;
) -> Vec<Report>;
}
#[derive(Default)]

View file

@ -1,5 +1,3 @@
use ariadne::Label;
use ariadne::Report;
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashSet;
@ -9,6 +7,7 @@ use unicode_segmentation::UnicodeSegmentation;
use super::customstyle::CustomStyleHolder;
use super::layout::LayoutHolder;
use super::reports::Report;
use super::rule::Rule;
use super::source::Cursor;
use super::source::Source;
@ -434,7 +433,9 @@ pub trait Parser {
/// Handles the reports produced by parsing. The default is to output them
/// to stderr, but you are free to modify it.
fn handle_reports(&self, reports: Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
fn handle_reports(&self, reports: Vec<Report>) {
todo!(); // TODO
/*
for mut report in reports {
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
fn recurse_source(sources: &mut HashSet<Rc<dyn Source>>, source: Rc<dyn Source>) {
@ -483,5 +484,6 @@ pub trait Parser {
});
report.eprint(ariadne::sources(cache)).unwrap()
}
*/
}
}

View file

@ -3,7 +3,7 @@ use std::{ops::Range, rc::Rc};
use super::{parser::Parser, source::{Source, SourcePosition, Token}};
#[derive(Debug)]
enum ReportKind
pub enum ReportKind
{
Error,
Warning,
@ -21,18 +21,20 @@ impl Into<ariadne::ReportKind<'static>> for &ReportKind
}
#[derive(Debug)]
struct ReportSpan
pub struct ReportSpan
{
pub token: Token,
pub message: String
}
#[derive(Debug)]
struct Report
pub struct Report
{
pub kind: ReportKind,
pub source: Rc<dyn Source>,
pub message: String,
pub note: Option<String>,
pub help: Option<String>,
pub spans: Vec<ReportSpan>,
}
@ -86,36 +88,69 @@ impl Report
}
}
macro_rules! report_label {
($spans:expr, $psource:expr,) => {{ }};
($spans:expr, $psource:expr, span($source:expr, $range:expr, $message:expr), $(, $($tail:tt)*)?) => {{
$spans.push(ReportSpan {
token: Token::new($range, $source),
message: $message,
});
report_label!($spans, $psource, $($($tail)*)?);
}};
($spans:expr, $psource:expr, span($range:expr, $message:expr) $(, $($tail:tt)*)?) => {{
$spans.push(ReportSpan {
token: Token::new($range, $psource),
message: $message,
});
report_label!($spans, $psource, $($($tail)*)?);
}}
}
pub mod macros
{
pub use super::*;
#[macro_export]
macro_rules! report_err {
macro_rules! report_label {
($r:expr,) => {{ }};
($r:expr, span($source:expr, $range:expr, $message:expr), $(, $($tail:tt)*)?) => {{
$r.spans.push(ReportSpan {
token: crate::parser::source::Token::Token::new($range, $source),
message: $message,
});
report_label!($r, $($($tail)*)?);
}};
($r:expr, span($range:expr, $message:expr) $(, $($tail:tt)*)?) => {{
$r.spans.push(ReportSpan {
token: crate::parser::source::Token::new($range, $r.source.clone()),
message: $message,
});
report_label!($r, $($($tail)*)?);
}};
($r:expr, note($message:expr) $(, $($tail:tt)*)?) => {{
$r.note = Some($message);
report_label!($r, $($($tail)*)?);
}};
($r:expr, help($message:expr) $(, $($tail:tt)*)?) => {{
$r.help = Some($message);
report_label!($r, $($($tail)*)?);
}}
}
#[macro_export]
macro_rules! report_err {
($reports:expr, $source:expr, $message:expr, $($tail:tt)*) => {{
let mut spans = Vec::new();
report_label!(spans, $source.clone(), $($tail)*);
$reports.push(Report {
let mut r = Report {
kind: ReportKind::Error,
source: $source,
message: $message,
spans,
});
note: None,
help: None,
spans: vec![],
};
report_label!(r, $($tail)*);
$reports.push(r);
}}
}
#[macro_export]
macro_rules! report_warn {
($reports:expr, $source:expr, $message:expr, $($tail:tt)*) => {{
let mut r = Report {
kind: ReportKind::Warning,
source: $source,
message: $message,
note: None,
help: None,
spans: vec![],
};
report_label!(r, $($tail)*);
$reports.push(r);
}}
}
pub use crate::*;
}
#[cfg(test)]
@ -140,7 +175,6 @@ Dolor
));
let mut reports = vec![];
//let la = report_label!(source.clone(), 5..9, "Msg".into());
report_err!(&mut reports, source.clone(), "Some message".into(),
span(5..9, "Msg".into()),

View file

@ -1,12 +1,12 @@
use super::layout::LayoutHolder;
use super::parser::ParseMode;
use super::parser::ParserState;
use super::reports::Report;
use super::source::Cursor;
use super::source::Source;
use super::source::Token;
use super::style::StyleHolder;
use crate::document::document::Document;
use ariadne::Report;
use downcast_rs::impl_downcast;
use downcast_rs::Downcast;
use mlua::Function;
@ -88,7 +88,7 @@ pub trait Rule: Downcast {
document: &'a (dyn Document<'a> + 'a),
cursor: Cursor,
match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
) -> (Cursor, Vec<Report>);
/// Registers lua bindings
fn register_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
@ -128,7 +128,7 @@ pub trait RegexRule {
document: &'a (dyn Document<'a> + 'a),
token: Token,
matches: regex::Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
) -> Vec<Report>;
fn register_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
fn register_styles(&self, _holder: &mut StyleHolder) {}
@ -175,7 +175,7 @@ impl<T: RegexRule + 'static> Rule for T {
document: &'a (dyn Document<'a> + 'a),
cursor: Cursor,
match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
) -> (Cursor, Vec<Report>) {
let content = cursor.source.content();
let index = match_data.downcast::<usize>().unwrap();
let re = &self.regexes()[*index];

View file

@ -1,16 +1,14 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
use ariadne::Report;
use downcast_rs::impl_downcast;
use downcast_rs::Downcast;
use crate::document::document::Document;
use super::parser::ParserState;
use super::source::Source;
use super::reports::Report;
/// Scope for state objects
#[derive(PartialEq, PartialOrd, Debug)]
@ -30,11 +28,11 @@ pub trait RuleState: Downcast {
fn scope(&self) -> Scope;
/// Callback called when state goes out of scope
fn on_remove<'a>(
fn on_remove(
&self,
state: &ParserState,
document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>>;
) -> Vec<Report>;
}
impl_downcast!(RuleState);
@ -72,7 +70,7 @@ impl RuleStateHolder {
state: &ParserState,
document: &dyn Document,
scope: Scope,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
) -> Vec<Report> {
let mut reports = vec![];
self.states.retain(|_name, rule_state| {