Reports refactor [2/2]
This commit is contained in:
parent
72954cdad8
commit
ea29c4bb53
15 changed files with 379 additions and 451 deletions
|
@ -1,7 +1,6 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Range;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use blockquote_style::AuthorPos::After;
|
use blockquote_style::AuthorPos::After;
|
||||||
|
|
|
@ -4,9 +4,6 @@ use std::rc::Rc;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
|
||||||
use ariadne::Report;
|
|
||||||
use ariadne::ReportKind;
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::sha2::Sha512;
|
use crypto::sha2::Sha512;
|
||||||
use mlua::Function;
|
use mlua::Function;
|
||||||
|
@ -36,6 +33,8 @@ use crate::parser::util::PropertyMapError;
|
||||||
use crate::parser::util::PropertyParser;
|
use crate::parser::util::PropertyParser;
|
||||||
use crate::parser::util::{self};
|
use crate::parser::util::{self};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use crate::parser::reports::*;
|
||||||
|
use crate::parser::reports::macros::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum CodeKind {
|
enum CodeKind {
|
||||||
|
@ -335,22 +334,21 @@ impl RegexRule for CodeRule {
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
token: Token,
|
token: Token,
|
||||||
matches: Captures,
|
matches: Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report> {
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
let properties = match matches.get(1) {
|
let properties = match matches.get(1) {
|
||||||
None => match self.properties.default() {
|
None => match self.properties.default() {
|
||||||
Ok(properties) => properties,
|
Ok(properties) => properties,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid code")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Code Properties".into(),
|
||||||
Label::new((token.source().clone(), token.range.clone()))
|
span(
|
||||||
.with_message(format!("Code is missing properties: {e}"))
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
format!("Code is missing properties: {e}")
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -360,15 +358,14 @@ impl RegexRule for CodeRule {
|
||||||
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
&mut reports,
|
||||||
.with_message("Invalid Code Properties")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Code Properties".into(),
|
||||||
Label::new((token.source().clone(), props.range()))
|
span(
|
||||||
.with_message(e)
|
props.range(),
|
||||||
.with_color(state.parser.colors().error),
|
e
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -382,15 +379,14 @@ impl RegexRule for CodeRule {
|
||||||
Some(lang) => {
|
Some(lang) => {
|
||||||
let code_lang = lang.as_str().trim_start().trim_end().to_string();
|
let code_lang = lang.as_str().trim_start().trim_end().to_string();
|
||||||
if code_lang.is_empty() {
|
if code_lang.is_empty() {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), lang.start())
|
&mut reports,
|
||||||
.with_message("Missing Code Language")
|
token.source(),
|
||||||
.with_label(
|
"Missing Code Language".into(),
|
||||||
Label::new((token.source().clone(), lang.range()))
|
span(
|
||||||
.with_message("No language specified")
|
lang.range(),
|
||||||
.with_color(state.parser.colors().error),
|
"No language specified".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return reports;
|
return reports;
|
||||||
|
@ -399,18 +395,17 @@ impl RegexRule for CodeRule {
|
||||||
.find_syntax_by_name(code_lang.as_str())
|
.find_syntax_by_name(code_lang.as_str())
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), lang.start())
|
&mut reports,
|
||||||
.with_message("Unknown Code Language")
|
token.source(),
|
||||||
.with_label(
|
"Unknown Code Language".into(),
|
||||||
Label::new((token.source().clone(), lang.range()))
|
span(
|
||||||
.with_message(format!(
|
lang.range(),
|
||||||
"Language `{}` cannot be found",
|
format!(
|
||||||
code_lang.fg(state.parser.colors().info)
|
"Language `{}` cannot be found",
|
||||||
))
|
code_lang.fg(state.parser.colors().info)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return reports;
|
return reports;
|
||||||
|
@ -432,15 +427,14 @@ impl RegexRule for CodeRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
if code_content.is_empty() {
|
if code_content.is_empty() {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Missing code content")
|
token.source(),
|
||||||
.with_label(
|
"Empty Code Content".into(),
|
||||||
Label::new((token.source().clone(), token.range.clone()))
|
span(
|
||||||
.with_message("Code content cannot be empty")
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
"Code content cannot be empty".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -464,34 +458,31 @@ impl RegexRule for CodeRule {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match e {
|
match e {
|
||||||
PropertyMapError::ParseError((prop, err)) => {
|
PropertyMapError::ParseError((prop, err)) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Code Property")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Code Property".into(),
|
||||||
Label::new((token.source().clone(), token.start()+1..token.end()))
|
span(
|
||||||
.with_message(format!("Property `line_offset: {}` cannot be converted: {}",
|
token.start()+1..token.end(),
|
||||||
prop.fg(state.parser.colors().info),
|
format!("Property `line_offset: {}` cannot be converted: {}",
|
||||||
err.fg(state.parser.colors().error)))
|
prop.fg(state.parser.colors().info),
|
||||||
.with_color(state.parser.colors().warning))
|
err.fg(state.parser.colors().error))
|
||||||
.finish());
|
)
|
||||||
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
PropertyMapError::NotFoundError(err) => {
|
PropertyMapError::NotFoundError(err) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Code Property")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Code Property".into(),
|
||||||
Label::new((
|
span(
|
||||||
token.source().clone(),
|
token.start()+1..token.end(),
|
||||||
token.start() + 1..token.end(),
|
format!(
|
||||||
))
|
"Property `{}` doesn't exist",
|
||||||
.with_message(format!(
|
err.fg(state.parser.colors().info)
|
||||||
"Property `{}` doesn't exist",
|
|
||||||
err.fg(state.parser.colors().info)
|
|
||||||
))
|
|
||||||
.with_color(state.parser.colors().warning),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,12 @@ use crate::parser::parser::ParserState;
|
||||||
use crate::parser::rule::RegexRule;
|
use crate::parser::rule::RegexRule;
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use ariadne::Label;
|
|
||||||
use ariadne::Report;
|
|
||||||
use ariadne::ReportKind;
|
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::parser::reports::*;
|
||||||
|
use crate::parser::reports::macros::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
|
@ -66,7 +65,7 @@ impl RegexRule for CommentRule {
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
token: Token,
|
token: Token,
|
||||||
matches: Captures,
|
matches: Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report> {
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
let content = match matches.get(1) {
|
let content = match matches.get(1) {
|
||||||
|
@ -74,15 +73,14 @@ impl RegexRule for CommentRule {
|
||||||
Some(comment) => {
|
Some(comment) => {
|
||||||
let trimmed = comment.as_str().trim_start().trim_end().to_string();
|
let trimmed = comment.as_str().trim_start().trim_end().to_string();
|
||||||
if trimmed.is_empty() {
|
if trimmed.is_empty() {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Warning, token.source(), comment.start())
|
&mut reports,
|
||||||
.with_message("Empty comment")
|
token.source(),
|
||||||
.with_label(
|
"Empty Comment".into(),
|
||||||
Label::new((token.source(), comment.range()))
|
span(
|
||||||
.with_message("Comment is empty")
|
comment.range(),
|
||||||
.with_color(state.parser.colors().warning),
|
"Comment is empty".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,6 @@ use crate::parser::util::Property;
|
||||||
use crate::parser::util::PropertyMapError;
|
use crate::parser::util::PropertyMapError;
|
||||||
use crate::parser::util::PropertyParser;
|
use crate::parser::util::PropertyParser;
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
|
||||||
use ariadne::Report;
|
|
||||||
use ariadne::ReportKind;
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::sha2::Sha512;
|
use crypto::sha2::Sha512;
|
||||||
use graphviz_rust::cmd::Format;
|
use graphviz_rust::cmd::Format;
|
||||||
|
@ -36,6 +33,8 @@ use crate::parser::rule::RegexRule;
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::util;
|
use crate::parser::util;
|
||||||
|
use crate::parser::reports::*;
|
||||||
|
use crate::parser::reports::macros::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Graphviz {
|
struct Graphviz {
|
||||||
|
@ -204,25 +203,24 @@ impl RegexRule for GraphRule {
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
token: Token,
|
token: Token,
|
||||||
matches: Captures,
|
matches: Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report> {
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
let graph_content = match matches.get(2) {
|
let graph_content = match matches.get(2) {
|
||||||
// Unterminated `[graph]`
|
// Unterminated `[graph]`
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Unterminated Graph Code")
|
token.source(),
|
||||||
.with_label(
|
"Unterminamted Graph Code".into(),
|
||||||
Label::new((token.source().clone(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
token.range.clone(),
|
||||||
"Missing terminating `{}` after first `{}`",
|
format!(
|
||||||
"[/graph]".fg(state.parser.colors().info),
|
"Missing terminating `{}` after first `{}`",
|
||||||
"[graph]".fg(state.parser.colors().info)
|
"[/graph]".fg(state.parser.colors().info),
|
||||||
))
|
"[graph]".fg(state.parser.colors().info)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -230,19 +228,18 @@ impl RegexRule for GraphRule {
|
||||||
let processed = util::escape_text(
|
let processed = util::escape_text(
|
||||||
'\\',
|
'\\',
|
||||||
"[/graph]",
|
"[/graph]",
|
||||||
content.as_str().trim_start().trim_end(),
|
content.as_str(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if processed.is_empty() {
|
if processed.is_empty() {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), content.start())
|
&mut reports,
|
||||||
.with_message("Empty Graph Code")
|
token.source(),
|
||||||
.with_label(
|
"Empty Graph Code".into(),
|
||||||
Label::new((token.source().clone(), content.range()))
|
span(
|
||||||
.with_message("Graph code is empty")
|
content.range(),
|
||||||
.with_color(state.parser.colors().error),
|
"Graph code is empty".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -255,15 +252,14 @@ impl RegexRule for GraphRule {
|
||||||
None => match self.properties.default() {
|
None => match self.properties.default() {
|
||||||
Ok(properties) => properties,
|
Ok(properties) => properties,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Graph")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Graph Properties".into(),
|
||||||
Label::new((token.source().clone(), token.range.clone()))
|
span(
|
||||||
.with_message(format!("Graph is missing property: {e}"))
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
format!("Graph is missing property: {e}")
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -273,15 +269,14 @@ impl RegexRule for GraphRule {
|
||||||
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
&mut reports,
|
||||||
.with_message("Invalid Graph Properties")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Graph Properties".into(),
|
||||||
Label::new((token.source().clone(), props.range()))
|
span(
|
||||||
.with_message(e)
|
props.range(),
|
||||||
.with_color(state.parser.colors().error),
|
e
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -297,35 +292,30 @@ impl RegexRule for GraphRule {
|
||||||
Ok((_prop, kind)) => kind,
|
Ok((_prop, kind)) => kind,
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
PropertyMapError::ParseError((prop, err)) => {
|
PropertyMapError::ParseError((prop, err)) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Graph Property")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Graph Property".into(),
|
||||||
Label::new((token.source().clone(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
token.range.clone(),
|
||||||
"Property `layout: {}` cannot be converted: {}",
|
format!(
|
||||||
|
"Property `{}` cannot be converted: {}",
|
||||||
prop.fg(state.parser.colors().info),
|
prop.fg(state.parser.colors().info),
|
||||||
err.fg(state.parser.colors().error)
|
err.fg(state.parser.colors().error)
|
||||||
))
|
)
|
||||||
.with_color(state.parser.colors().warning),
|
)
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
PropertyMapError::NotFoundError(err) => {
|
PropertyMapError::NotFoundError(err) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Graph Property")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Graph Property".into(),
|
||||||
Label::new((
|
span(
|
||||||
token.source().clone(),
|
token.start() + 1..token.end(),
|
||||||
token.start() + 1..token.end(),
|
err
|
||||||
))
|
)
|
||||||
.with_message(err)
|
|
||||||
.with_color(state.parser.colors().warning),
|
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -340,21 +330,17 @@ impl RegexRule for GraphRule {
|
||||||
Ok((_, kind)) => kind,
|
Ok((_, kind)) => kind,
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
PropertyMapError::NotFoundError(err) => {
|
PropertyMapError::NotFoundError(err) => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid Graph Property")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Graph Property".into(),
|
||||||
Label::new((
|
span(
|
||||||
token.source().clone(),
|
token.start() + 1..token.end(),
|
||||||
token.start() + 1..token.end(),
|
format!(
|
||||||
))
|
"Property `{}` is missing",
|
||||||
.with_message(format!(
|
err.fg(state.parser.colors().info)
|
||||||
"Property `{}` is missing",
|
|
||||||
err.fg(state.parser.colors().info)
|
|
||||||
))
|
|
||||||
.with_color(state.parser.colors().warning),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,12 @@ use crate::parser::source::Source;
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
|
||||||
use ariadne::Report;
|
|
||||||
use ariadne::ReportKind;
|
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::parser::reports::*;
|
||||||
|
use crate::parser::reports::macros::*;
|
||||||
|
|
||||||
use super::paragraph::Paragraph;
|
use super::paragraph::Paragraph;
|
||||||
|
|
||||||
|
@ -57,65 +56,62 @@ impl RegexRule for ImportRule {
|
||||||
document: &'a dyn Document<'a>,
|
document: &'a dyn Document<'a>,
|
||||||
token: Token,
|
token: Token,
|
||||||
matches: Captures,
|
matches: Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report> {
|
||||||
let mut result = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
let import_file = match matches.get(2) {
|
let import_file = match matches.get(2) {
|
||||||
Some(name) => match ImportRule::validate_name(state.parser.colors(), name.as_str()) {
|
Some(name) => match ImportRule::validate_name(state.parser.colors(), name.as_str()) {
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
result.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Invalid name for import")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Import Name".into(),
|
||||||
Label::new((token.source(), name.range()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Import name `{}` is invalid. {msg}",
|
format!(
|
||||||
name.as_str().fg(state.parser.colors().highlight)
|
"Import name `{}` is invalid. {msg}",
|
||||||
))
|
name.as_str().fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return reports;
|
||||||
}
|
}
|
||||||
Ok(filename) => {
|
Ok(filename) => {
|
||||||
let meta = match std::fs::metadata(filename.as_str()) {
|
let meta = match std::fs::metadata(filename.as_str()) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
result.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Invalid import path")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Import Path".into(),
|
||||||
Label::new((token.source(), name.range()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Unable to access file `{}`",
|
format!(
|
||||||
filename.fg(state.parser.colors().highlight)
|
"Unable to access file `{}`",
|
||||||
))
|
filename.fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return result;
|
return reports;
|
||||||
}
|
}
|
||||||
Ok(meta) => meta,
|
Ok(meta) => meta,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !meta.is_file() {
|
if !meta.is_file() {
|
||||||
result.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Invalid import path")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Import Path".into(),
|
||||||
Label::new((token.source(), name.range()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Path `{}` is not a file!",
|
format!(
|
||||||
filename.fg(state.parser.colors().highlight)
|
"Path `{}` is not a file!",
|
||||||
))
|
filename.fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return result;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename
|
filename
|
||||||
|
@ -130,21 +126,20 @@ impl RegexRule for ImportRule {
|
||||||
{
|
{
|
||||||
Ok(as_name) => as_name,
|
Ok(as_name) => as_name,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
result.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), as_name.start())
|
&mut reports,
|
||||||
.with_message("Invalid name for import as")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Import As".into(),
|
||||||
Label::new((token.source(), as_name.range()))
|
span(
|
||||||
.with_message(format!(
|
as_name.range(),
|
||||||
"Canot import `{import_file}` as `{}`. {msg}",
|
format!(
|
||||||
as_name.as_str().fg(state.parser.colors().highlight)
|
"Canot import `{import_file}` as `{}`. {msg}",
|
||||||
))
|
as_name.as_str().fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return reports;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => "".to_string(),
|
_ => "".to_string(),
|
||||||
|
@ -153,17 +148,16 @@ impl RegexRule for ImportRule {
|
||||||
let import = match SourceFile::new(import_file, Some(token.clone())) {
|
let import = match SourceFile::new(import_file, Some(token.clone())) {
|
||||||
Ok(import) => Rc::new(import),
|
Ok(import) => Rc::new(import),
|
||||||
Err(path) => {
|
Err(path) => {
|
||||||
result.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Unable to read file content")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Import File".into(),
|
||||||
Label::new((token.source(), token.range))
|
span(
|
||||||
.with_message(format!("Failed to read content from path `{path}`"))
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
format!("Failed to read content from path `{path}`")
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return result;
|
return reports;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,6 +206,6 @@ impl RegexRule for ImportRule {
|
||||||
sems.add(path, tokens.import_path);
|
sems.add(path, tokens.import_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
reports
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,10 +341,10 @@ impl LayoutRule {
|
||||||
token: &Token,
|
token: &Token,
|
||||||
layout_type: Rc<dyn LayoutType>,
|
layout_type: Rc<dyn LayoutType>,
|
||||||
properties: Option<Match>,
|
properties: Option<Match>,
|
||||||
) -> Option<Box<dyn Any>> {
|
) -> Result<Option<Box<dyn Any>>, ()> {
|
||||||
match properties {
|
match properties {
|
||||||
None => match layout_type.parse_properties("") {
|
None => match layout_type.parse_properties("") {
|
||||||
Ok(props) => props,
|
Ok(props) => Ok(props),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
report_err!(
|
report_err!(
|
||||||
&mut reports,
|
&mut reports,
|
||||||
|
@ -352,28 +352,28 @@ impl LayoutRule {
|
||||||
"Invalid Layout Properties".into(),
|
"Invalid Layout Properties".into(),
|
||||||
span(
|
span(
|
||||||
token.range.clone(),
|
token.range.clone(),
|
||||||
format!("Layout is missing required property: {eee}")
|
format!("Layout is missing required property: {err}")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
None
|
Err(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let trimmed = props.as_str().trim_start().trim_end();
|
let content = escape_text('\\', "]", props.as_str());
|
||||||
let content = escape_text('\\', "]", trimmed);
|
|
||||||
match layout_type.parse_properties(content.as_str()) {
|
match layout_type.parse_properties(content.as_str()) {
|
||||||
Ok(props) => Ok(props),
|
Ok(props) => Ok(props),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Err(
|
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
report_err!(
|
||||||
.with_message("Unable to parse layout properties")
|
&mut reports,
|
||||||
.with_label(
|
token.source(),
|
||||||
Label::new((token.source(), props.range()))
|
"Invalid Layout Properties".into(),
|
||||||
.with_message(err)
|
span(
|
||||||
.with_color(colors.error),
|
props.range(),
|
||||||
)
|
err
|
||||||
.finish(),
|
)
|
||||||
)
|
);
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,7 @@ impl RegexRule for LayoutRule {
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
token: Token,
|
token: Token,
|
||||||
matches: Captures,
|
matches: Captures,
|
||||||
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report> {
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
let rule_state = LayoutRule::initialize_state(state);
|
let rule_state = LayoutRule::initialize_state(state);
|
||||||
|
@ -409,18 +409,17 @@ impl RegexRule for LayoutRule {
|
||||||
{
|
{
|
||||||
match matches.get(2) {
|
match matches.get(2) {
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Missing Layout Name")
|
token.source(),
|
||||||
.with_label(
|
"Missing Layout Name".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
token.range.clone(),
|
||||||
"Missing layout name after `{}`",
|
format!(
|
||||||
"#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
|
"Missing layout name after `{}`",
|
||||||
))
|
"#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -429,35 +428,33 @@ impl RegexRule for LayoutRule {
|
||||||
if name.as_str().is_empty() || trimmed.is_empty()
|
if name.as_str().is_empty() || trimmed.is_empty()
|
||||||
// Empty name
|
// Empty name
|
||||||
{
|
{
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Empty Layout Name")
|
token.source(),
|
||||||
.with_label(
|
"Empty Layout Name".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Empty layout name after `{}`",
|
format!(
|
||||||
"#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
|
"Empty layout name after `{}`",
|
||||||
))
|
"#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
} else if !name.as_str().chars().next().unwrap().is_whitespace()
|
} else if !name.as_str().chars().next().unwrap().is_whitespace()
|
||||||
// Missing space
|
// Missing space
|
||||||
{
|
{
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Invalid Layout Name")
|
token.source(),
|
||||||
.with_label(
|
"Invalid Layout Name".into(),
|
||||||
Label::new((token.source(), name.range()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Missing a space before layout name `{}`",
|
format!(
|
||||||
name.as_str().fg(state.parser.colors().highlight)
|
"Missing a space before layout name `{}`",
|
||||||
))
|
name.as_str().fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -465,18 +462,18 @@ impl RegexRule for LayoutRule {
|
||||||
// Get layout
|
// Get layout
|
||||||
let layout_type = match state.shared.layouts.borrow().get(trimmed) {
|
let layout_type = match state.shared.layouts.borrow().get(trimmed) {
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
&mut reports,
|
||||||
.with_message("Unknown Layout")
|
token.source(),
|
||||||
.with_label(
|
"Unknown Layout".into(),
|
||||||
Label::new((token.source(), name.range()))
|
span(
|
||||||
.with_message(format!(
|
name.range(),
|
||||||
"Cannot find layout `{}`",
|
format!(
|
||||||
trimmed.fg(state.parser.colors().highlight)
|
"Cannot find layout `{}`",
|
||||||
))
|
trimmed.fg(state.parser.colors().highlight)
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -485,16 +482,13 @@ impl RegexRule for LayoutRule {
|
||||||
|
|
||||||
// Parse properties
|
// Parse properties
|
||||||
let properties = match LayoutRule::parse_properties(
|
let properties = match LayoutRule::parse_properties(
|
||||||
state.parser.colors(),
|
&mut reports,
|
||||||
&token,
|
&token,
|
||||||
layout_type.clone(),
|
layout_type.clone(),
|
||||||
matches.get(1),
|
matches.get(1),
|
||||||
) {
|
) {
|
||||||
Ok(props) => props,
|
Ok(props) => props,
|
||||||
Err(rep) => {
|
Err(()) => return reports,
|
||||||
reports.push(rep);
|
|
||||||
return reports;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state.push(
|
state.push(
|
||||||
|
@ -548,15 +542,14 @@ impl RegexRule for LayoutRule {
|
||||||
|
|
||||||
let (tokens, layout_type) = match layout_state.stack.last_mut() {
|
let (tokens, layout_type) = match layout_state.stack.last_mut() {
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid #+LAYOUT_NEXT")
|
token.source(),
|
||||||
.with_label(
|
"Invalid #+LAYOUT_NEXT".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message("No active layout found".to_string())
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
"No active layout found".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -566,35 +559,31 @@ impl RegexRule for LayoutRule {
|
||||||
if layout_type.expects().end < tokens.len()
|
if layout_type.expects().end < tokens.len()
|
||||||
// Too many blocks
|
// Too many blocks
|
||||||
{
|
{
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Unexpected #+LAYOUT_NEXT")
|
token.source(),
|
||||||
.with_label(
|
"Unexpected #+LAYOUT_NEXT".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
token.range.clone(),
|
||||||
"Layout expects a maximum of {} blocks, currently at {}",
|
format!(
|
||||||
layout_type.expects().end.fg(state.parser.colors().info),
|
"Layout expects a maximum of {} blocks, currently at {}",
|
||||||
tokens.len().fg(state.parser.colors().info),
|
layout_type.expects().end.fg(state.parser.colors().info),
|
||||||
))
|
tokens.len().fg(state.parser.colors().info),
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse properties
|
// Parse properties
|
||||||
let properties = match LayoutRule::parse_properties(
|
let properties = match LayoutRule::parse_properties(
|
||||||
state.parser.colors(),
|
&mut reports,
|
||||||
&token,
|
&token,
|
||||||
layout_type.clone(),
|
layout_type.clone(),
|
||||||
matches.get(1),
|
matches.get(1),
|
||||||
) {
|
) {
|
||||||
Ok(props) => props,
|
Ok(props) => props,
|
||||||
Err(rep) => {
|
Err(rep) => return reports,
|
||||||
reports.push(rep);
|
|
||||||
return reports;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((sems, tokens)) =
|
if let Some((sems, tokens)) =
|
||||||
|
@ -630,15 +619,14 @@ impl RegexRule for LayoutRule {
|
||||||
|
|
||||||
let (tokens, layout_type) = match layout_state.stack.last_mut() {
|
let (tokens, layout_type) = match layout_state.stack.last_mut() {
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Invalid #+LAYOUT_END")
|
token.source(),
|
||||||
.with_label(
|
"Invalid #+LAYOUT_NEXT".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message("No active layout found".to_string())
|
token.range.clone(),
|
||||||
.with_color(state.parser.colors().error),
|
"No active layout found".into()
|
||||||
)
|
)
|
||||||
.finish(),
|
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
@ -648,35 +636,31 @@ impl RegexRule for LayoutRule {
|
||||||
if layout_type.expects().start > tokens.len()
|
if layout_type.expects().start > tokens.len()
|
||||||
// Not enough blocks
|
// Not enough blocks
|
||||||
{
|
{
|
||||||
reports.push(
|
report_err!(
|
||||||
Report::build(ReportKind::Error, token.source(), token.start())
|
&mut reports,
|
||||||
.with_message("Unexpected #+LAYOUT_END")
|
token.source(),
|
||||||
.with_label(
|
"Unexpected #+LAYOUT_NEXT".into(),
|
||||||
Label::new((token.source(), token.range.clone()))
|
span(
|
||||||
.with_message(format!(
|
token.range.clone(),
|
||||||
"Layout expects a minimum of {} blocks, currently at {}",
|
format!(
|
||||||
layout_type.expects().start.fg(state.parser.colors().info),
|
"Layout expects a minimum of {} blocks, currently at {}",
|
||||||
tokens.len().fg(state.parser.colors().info),
|
layout_type.expects().start.fg(state.parser.colors().info),
|
||||||
))
|
tokens.len().fg(state.parser.colors().info),
|
||||||
.with_color(state.parser.colors().error),
|
|
||||||
)
|
)
|
||||||
.finish(),
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse properties
|
// Parse properties
|
||||||
let properties = match LayoutRule::parse_properties(
|
let properties = match LayoutRule::parse_properties(
|
||||||
state.parser.colors(),
|
&mut reports,
|
||||||
&token,
|
&token,
|
||||||
layout_type.clone(),
|
layout_type.clone(),
|
||||||
matches.get(1),
|
matches.get(1),
|
||||||
) {
|
) {
|
||||||
Ok(props) => props,
|
Ok(props) => props,
|
||||||
Err(rep) => {
|
Err(rep) => return reports,
|
||||||
reports.push(rep);
|
|
||||||
return reports;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let layout_type = layout_type.clone();
|
let layout_type = layout_type.clone();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Range;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::compiler::compiler::Compiler;
|
use crate::compiler::compiler::Compiler;
|
||||||
|
@ -429,6 +428,7 @@ impl Rule for ListRule {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::parser::source::Source;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
use crate::elements::text::Text;
|
use crate::elements::text::Text;
|
||||||
use crate::parser::langparser::LangParser;
|
use crate::parser::langparser::LangParser;
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::ops::Range;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use ariadne::Report;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::compiler::compiler::Compiler;
|
use crate::compiler::compiler::Compiler;
|
||||||
|
@ -17,6 +14,7 @@ use crate::parser::rule::Rule;
|
||||||
use crate::parser::source::Cursor;
|
use crate::parser::source::Cursor;
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
|
use crate::parser::reports::*;
|
||||||
|
|
||||||
// TODO: Full refactor
|
// TODO: Full refactor
|
||||||
// Problem is that document parsed from other sources i.e by variables
|
// Problem is that document parsed from other sources i.e by variables
|
||||||
|
@ -132,7 +130,7 @@ impl Rule for ParagraphRule {
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
_match_data: Box<dyn Any>,
|
_match_data: Box<dyn Any>,
|
||||||
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
|
) -> (Cursor, Vec<Report>) {
|
||||||
let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) {
|
let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) {
|
||||||
None => panic!("Unknown error"),
|
None => panic!("Unknown error"),
|
||||||
Some(capture) => cursor.at(capture.get(0).unwrap().end() - 1),
|
Some(capture) => cursor.at(capture.get(0).unwrap().end() - 1),
|
||||||
|
@ -152,6 +150,8 @@ impl Rule for ParagraphRule {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::rc::Rc;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
use crate::elements::text::Text;
|
use crate::elements::text::Text;
|
||||||
use crate::parser::langparser::LangParser;
|
use crate::parser::langparser::LangParser;
|
||||||
|
@ -159,7 +159,6 @@ mod tests {
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
use crate::validate_document;
|
use crate::validate_document;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse() {
|
fn parse() {
|
||||||
|
|
|
@ -272,6 +272,8 @@ impl RegexRule for RawRule {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::parser::source::Source;
|
||||||
|
use std::rc::Rc;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
use crate::elements::text::Text;
|
use crate::elements::text::Text;
|
||||||
use crate::parser::langparser::LangParser;
|
use crate::parser::langparser::LangParser;
|
||||||
|
|
|
@ -15,7 +15,6 @@ use ariadne::Fmt;
|
||||||
use mlua::Lua;
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::ops::Range;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use crate::parser::reports::*;
|
use crate::parser::reports::*;
|
||||||
use crate::parser::reports::macros::*;
|
use crate::parser::reports::macros::*;
|
||||||
|
@ -140,7 +139,7 @@ impl RegexRule for ScriptRule {
|
||||||
"Invalid Kernel Code".into(),
|
"Invalid Kernel Code".into(),
|
||||||
span(
|
span(
|
||||||
script_range,
|
script_range,
|
||||||
"Kernel code is empty".into(),
|
"Kernel code is empty".into()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return reports;
|
return reports;
|
||||||
|
|
|
@ -353,7 +353,7 @@ impl RegexRule for VariableSubstitutionRule {
|
||||||
"Empty Variable Name".into(),
|
"Empty Variable Name".into(),
|
||||||
span(
|
span(
|
||||||
name.range(),
|
name.range(),
|
||||||
"Missing variable name for substitution".into(),
|
"Missing variable name for substitution".into()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ impl RegexRule for VariableSubstitutionRule {
|
||||||
"Invalid Variable Name".into(),
|
"Invalid Variable Name".into(),
|
||||||
span(
|
span(
|
||||||
name.range(),
|
name.range(),
|
||||||
"Variable names contains leading spaces".into(),
|
"Variable names contains leading spaces".into()
|
||||||
),
|
),
|
||||||
help("Remove leading spaces".into())
|
help("Remove leading spaces".into())
|
||||||
);
|
);
|
||||||
|
@ -382,7 +382,7 @@ impl RegexRule for VariableSubstitutionRule {
|
||||||
"Invalid Variable Name".into(),
|
"Invalid Variable Name".into(),
|
||||||
span(
|
span(
|
||||||
name.range(),
|
name.range(),
|
||||||
"Variable names contains trailing spaces".into(),
|
"Variable names contains trailing spaces".into()
|
||||||
),
|
),
|
||||||
help("Remove trailing spaces".into())
|
help("Remove trailing spaces".into())
|
||||||
);
|
);
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn main() -> ExitCode {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let program = args[0].clone();
|
let program = args[0].clone();
|
||||||
|
|
||||||
slet mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optopt("i", "input", "Input path", "PATH");
|
opts.optopt("i", "input", "Input path", "PATH");
|
||||||
opts.optopt("o", "output", "Output path", "PATH");
|
opts.optopt("o", "output", "Output path", "PATH");
|
||||||
opts.optopt("d", "database", "Cache database location", "PATH");
|
opts.optopt("d", "database", "Cache database location", "PATH");
|
||||||
|
|
|
@ -434,7 +434,8 @@ pub trait Parser {
|
||||||
/// Handles the reports produced by parsing. The default is to output them
|
/// Handles the reports produced by parsing. The default is to output them
|
||||||
/// to stderr, but you are free to modify it.
|
/// to stderr, but you are free to modify it.
|
||||||
fn handle_reports(&self, reports: Vec<Report>) {
|
fn handle_reports(&self, reports: Vec<Report>) {
|
||||||
todo!(); // TODO
|
Report::reports_to_stdout(self.colors(), reports);
|
||||||
|
//todo!(); // TODO
|
||||||
/*
|
/*
|
||||||
for mut report in reports {
|
for mut report in reports {
|
||||||
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
|
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
use std::{ops::Range, rc::Rc};
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Range;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{parser::Parser, source::{Source, SourcePosition, Token}};
|
use super::parser::ReportColors;
|
||||||
|
use super::source::Source;
|
||||||
|
use super::source::SourcePosition;
|
||||||
|
use super::source::Token;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ReportKind
|
pub enum ReportKind {
|
||||||
{
|
|
||||||
Error,
|
Error,
|
||||||
Warning,
|
Warning,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<ariadne::ReportKind<'static>> for &ReportKind
|
impl Into<ariadne::ReportKind<'static>> for &ReportKind {
|
||||||
{
|
fn into(self) -> ariadne::ReportKind<'static> {
|
||||||
fn into(self) -> ariadne::ReportKind<'static> {
|
match self {
|
||||||
match self
|
|
||||||
{
|
|
||||||
ReportKind::Error => ariadne::ReportKind::Error,
|
ReportKind::Error => ariadne::ReportKind::Error,
|
||||||
ReportKind::Warning => ariadne::ReportKind::Warning,
|
ReportKind::Warning => ariadne::ReportKind::Warning,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReportSpan
|
pub struct ReportSpan {
|
||||||
{
|
|
||||||
pub token: Token,
|
pub token: Token,
|
||||||
pub message: String
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Report
|
pub struct Report {
|
||||||
{
|
|
||||||
pub kind: ReportKind,
|
pub kind: ReportKind,
|
||||||
pub source: Rc<dyn Source>,
|
pub source: Rc<dyn Source>,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
@ -38,65 +38,72 @@ pub struct Report
|
||||||
pub spans: Vec<ReportSpan>,
|
pub spans: Vec<ReportSpan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Report
|
impl Report {
|
||||||
{
|
fn ariadne_color(kind: &ReportKind, colors: &ReportColors) -> ariadne::Color {
|
||||||
fn ariadne_format(fmt: &str, parser: &dyn Parser) -> String
|
match kind {
|
||||||
{
|
ReportKind::Error => colors.error,
|
||||||
// TODO: Colors
|
ReportKind::Warning => colors.warning,
|
||||||
return fmt.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ariadne_color(kind: &ReportKind, parser: &dyn Parser) -> ariadne::Color
|
|
||||||
{
|
|
||||||
match kind
|
|
||||||
{
|
|
||||||
ReportKind::Error => parser.colors().error,
|
|
||||||
ReportKind::Warning => parser.colors().warning,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ariadne(self, parser: &dyn Parser) -> ariadne::Report<'static, (Rc<dyn Source>, Range<usize>)>
|
pub fn to_ariadne(
|
||||||
{
|
self,
|
||||||
|
colors: &ReportColors,
|
||||||
|
) -> (
|
||||||
|
ariadne::Report<'static, (Rc<dyn Source>, Range<usize>)>,
|
||||||
|
impl ariadne::Cache<Rc<dyn Source>>,
|
||||||
|
) {
|
||||||
|
let mut cache = HashMap::new();
|
||||||
let source = self.source.original_position(0).0;
|
let source = self.source.original_position(0).0;
|
||||||
let mut start = usize::MAX;
|
let mut start = usize::MAX;
|
||||||
for span in &self.spans
|
for span in &self.spans {
|
||||||
{
|
|
||||||
let (osource, opos) = span.token.source().original_position(span.token.start());
|
let (osource, opos) = span.token.source().original_position(span.token.start());
|
||||||
|
|
||||||
if &osource == &source && opos < start
|
if &osource == &source && opos < start {
|
||||||
{
|
|
||||||
start = opos;
|
start = opos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if start == usize::MAX
|
if start == usize::MAX {
|
||||||
{
|
|
||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
cache.insert(source.clone(), source.content().clone());
|
||||||
let mut builder = ariadne::Report::build((&self.kind).into(), self.source, start)
|
let mut builder = ariadne::Report::build((&self.kind).into(), self.source, start)
|
||||||
.with_message(Self::ariadne_format(self.message.as_str(), parser));
|
.with_message(self.message);
|
||||||
|
|
||||||
for span in self.spans
|
for span in self.spans {
|
||||||
{
|
cache.insert(span.token.source(), span.token.source().content().clone());
|
||||||
builder = builder.with_label(
|
builder = builder.with_label(
|
||||||
ariadne::Label::new((span.token.source(), span.token.range))
|
ariadne::Label::new(span.token.source().original_range(span.token.range))
|
||||||
.with_message(Self::ariadne_format(span.message.as_str(), parser))
|
.with_message(span.message)
|
||||||
.with_color(Self::ariadne_color(&self.kind, parser))
|
.with_color(Self::ariadne_color(&self.kind, colors)),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
if let Some(help) = &self.help {
|
||||||
|
builder.set_help(help);
|
||||||
|
}
|
||||||
|
if let Some(note) = &self.note {
|
||||||
|
builder.set_note(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.finish()
|
(builder.finish(), ariadne::sources(cache))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reports_to_stdout(colors: &ReportColors, mut reports: Vec<Report>) {
|
||||||
|
reports.drain(..).for_each(|report| {
|
||||||
|
let (report, cache) = report.to_ariadne(colors);
|
||||||
|
report.eprint(cache).unwrap();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod macros
|
pub mod macros {
|
||||||
{
|
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! report_label {
|
macro_rules! report_label {
|
||||||
($r:expr,) => {{ }};
|
($r:expr,) => {{ }};
|
||||||
($r:expr, span($source:expr, $range:expr, $message:expr), $(, $($tail:tt)*)?) => {{
|
($r:expr, span($source:expr, $range:expr, $message:expr) $(, $($tail:tt)*)?) => {{
|
||||||
$r.spans.push(ReportSpan {
|
$r.spans.push(ReportSpan {
|
||||||
token: crate::parser::source::Token::Token::new($range, $source),
|
token: crate::parser::source::Token::new($range, $source),
|
||||||
message: $message,
|
message: $message,
|
||||||
});
|
});
|
||||||
report_label!($r, $($($tail)*)?);
|
report_label!($r, $($($tail)*)?);
|
||||||
|
@ -152,34 +159,3 @@ pub mod macros
|
||||||
|
|
||||||
pub use crate::*;
|
pub use crate::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests
|
|
||||||
{
|
|
||||||
use crate::parser::source::SourceFile;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn te()
|
|
||||||
{
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
Sit
|
|
||||||
Lorem
|
|
||||||
Ipsum
|
|
||||||
Dolor
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
|
|
||||||
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()),
|
|
||||||
span(5..9, "Another".into()),
|
|
||||||
);
|
|
||||||
println!("Report = {reports:#?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use parser::parser::ParseMode;
|
||||||
use parser::parser::Parser;
|
use parser::parser::Parser;
|
||||||
use parser::parser::ParserState;
|
use parser::parser::ParserState;
|
||||||
use parser::source::SourceFile;
|
use parser::source::SourceFile;
|
||||||
use tower_lsp::jsonrpc::Result;
|
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use tower_lsp::Client;
|
use tower_lsp::Client;
|
||||||
use tower_lsp::LanguageServer;
|
use tower_lsp::LanguageServer;
|
||||||
|
@ -65,7 +64,7 @@ impl Backend {
|
||||||
|
|
||||||
#[tower_lsp::async_trait]
|
#[tower_lsp::async_trait]
|
||||||
impl LanguageServer for Backend {
|
impl LanguageServer for Backend {
|
||||||
async fn initialize(&self, _params: InitializeParams) -> Result<InitializeResult> {
|
async fn initialize(&self, _params: InitializeParams) -> tower_lsp::jsonrpc::Result<InitializeResult> {
|
||||||
Ok(InitializeResult {
|
Ok(InitializeResult {
|
||||||
capabilities: ServerCapabilities {
|
capabilities: ServerCapabilities {
|
||||||
text_document_sync: Some(TextDocumentSyncCapability::Kind(
|
text_document_sync: Some(TextDocumentSyncCapability::Kind(
|
||||||
|
@ -118,7 +117,7 @@ impl LanguageServer for Backend {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn shutdown(&self) -> Result<()> { Ok(()) }
|
async fn shutdown(&self) -> tower_lsp::jsonrpc::Result<()> { Ok(()) }
|
||||||
|
|
||||||
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
||||||
self.client
|
self.client
|
||||||
|
@ -139,7 +138,7 @@ impl LanguageServer for Backend {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn completion(&self, _params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
async fn completion(&self, _params: CompletionParams) -> tower_lsp::jsonrpc::Result<Option<CompletionResponse>> {
|
||||||
//let uri = params.text_document_position.text_document.uri;
|
//let uri = params.text_document_position.text_document.uri;
|
||||||
//let position = params.text_document_position.position;
|
//let position = params.text_document_position.position;
|
||||||
let completions = || -> Option<Vec<CompletionItem>> {
|
let completions = || -> Option<Vec<CompletionItem>> {
|
||||||
|
@ -153,7 +152,7 @@ impl LanguageServer for Backend {
|
||||||
async fn semantic_tokens_full(
|
async fn semantic_tokens_full(
|
||||||
&self,
|
&self,
|
||||||
params: SemanticTokensParams,
|
params: SemanticTokensParams,
|
||||||
) -> Result<Option<SemanticTokensResult>> {
|
) -> tower_lsp::jsonrpc::Result<Option<SemanticTokensResult>> {
|
||||||
let uri = params.text_document.uri.to_string();
|
let uri = params.text_document.uri.to_string();
|
||||||
self.client
|
self.client
|
||||||
.log_message(MessageType::LOG, "semantic_token_full")
|
.log_message(MessageType::LOG, "semantic_token_full")
|
||||||
|
|
Loading…
Reference in a new issue