Experimental new report system
This commit is contained in:
parent
352b395929
commit
f57173b9be
7 changed files with 209 additions and 42 deletions
|
@ -230,7 +230,7 @@ impl RegexRule for ScriptRule {
|
|||
{
|
||||
let parse_source = Rc::new(VirtualSource::new(
|
||||
Token::new(0..source.content().len(), source.clone()),
|
||||
format!("parse({})", source.name()),
|
||||
format!(":LUA:parse({})", source.name()),
|
||||
result,
|
||||
)) as Rc<dyn Source>;
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::lua::kernel::CTX;
|
|||
use crate::parser::parser::ParseMode;
|
||||
use crate::parser::parser::ParserState;
|
||||
use crate::parser::rule::RegexRule;
|
||||
use crate::parser::source::original_range;
|
||||
use crate::parser::source::Source;
|
||||
use crate::parser::source::Token;
|
||||
use crate::parser::state::RuleState;
|
||||
|
|
|
@ -8,10 +8,10 @@ use tower_lsp::lsp_types::SemanticToken;
|
|||
use tower_lsp::lsp_types::SemanticTokenModifier;
|
||||
use tower_lsp::lsp_types::SemanticTokenType;
|
||||
|
||||
use crate::parser::source::original_range;
|
||||
use crate::parser::source::LineCursor;
|
||||
use crate::parser::source::Source;
|
||||
use crate::parser::source::SourceFile;
|
||||
use crate::parser::source::SourcePosition;
|
||||
use crate::parser::source::VirtualSource;
|
||||
|
||||
pub const TOKEN_TYPE: &[SemanticTokenType] = &[
|
||||
|
@ -278,7 +278,6 @@ impl<'a> Semantics<'a> {
|
|||
.map(|parent| parent.location())
|
||||
.unwrap_or(None)
|
||||
{
|
||||
//let range = location.range.start+range.start..location.range.start+range.end;
|
||||
return Self::from_source_impl(location.source(), semantics, original_source);
|
||||
} else if let Some(source) = source.clone().downcast_rc::<SourceFile>().ok() {
|
||||
return Ref::filter_map(
|
||||
|
@ -316,7 +315,7 @@ impl<'a> Semantics<'a> {
|
|||
}
|
||||
|
||||
pub fn add(&self, range: Range<usize>, token: (u32, u32)) {
|
||||
let range = original_range(self.original_source.clone(), range).1;
|
||||
let range = self.original_source.original_range(range).1;
|
||||
let mut tokens = self.sems.tokens.borrow_mut();
|
||||
let mut cursor = self.sems.cursor.borrow_mut();
|
||||
let mut current = cursor.clone();
|
||||
|
|
|
@ -7,3 +7,4 @@ pub mod util;
|
|||
pub mod style;
|
||||
pub mod layout;
|
||||
pub mod customstyle;
|
||||
pub mod reports;
|
||||
|
|
151
src/parser/reports.rs
Normal file
151
src/parser/reports.rs
Normal file
|
@ -0,0 +1,151 @@
|
|||
use std::{ops::Range, rc::Rc};
|
||||
|
||||
use super::{parser::Parser, source::{Source, SourcePosition, Token}};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ReportKind
|
||||
{
|
||||
Error,
|
||||
Warning,
|
||||
}
|
||||
|
||||
impl Into<ariadne::ReportKind<'static>> for &ReportKind
|
||||
{
|
||||
fn into(self) -> ariadne::ReportKind<'static> {
|
||||
match self
|
||||
{
|
||||
ReportKind::Error => ariadne::ReportKind::Error,
|
||||
ReportKind::Warning => ariadne::ReportKind::Warning,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ReportSpan
|
||||
{
|
||||
pub token: Token,
|
||||
pub message: String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Report
|
||||
{
|
||||
pub kind: ReportKind,
|
||||
pub source: Rc<dyn Source>,
|
||||
pub message: String,
|
||||
pub spans: Vec<ReportSpan>,
|
||||
}
|
||||
|
||||
impl Report
|
||||
{
|
||||
fn ariadne_format(fmt: &str, parser: &dyn Parser) -> String
|
||||
{
|
||||
// TODO: Colors
|
||||
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>)>
|
||||
{
|
||||
let source = self.source.original_position(0).0;
|
||||
let mut start = usize::MAX;
|
||||
for span in &self.spans
|
||||
{
|
||||
let (osource, opos) = span.token.source().original_position(span.token.start());
|
||||
|
||||
if &osource == &source && opos < start
|
||||
{
|
||||
start = opos;
|
||||
}
|
||||
}
|
||||
if start == usize::MAX
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
let mut builder = ariadne::Report::build((&self.kind).into(), self.source, start)
|
||||
.with_message(Self::ariadne_format(self.message.as_str(), parser));
|
||||
|
||||
for span in self.spans
|
||||
{
|
||||
builder = builder.with_label(
|
||||
ariadne::Label::new((span.token.source(), span.token.range))
|
||||
.with_message(Self::ariadne_format(span.message.as_str(), parser))
|
||||
.with_color(Self::ariadne_color(&self.kind, parser))
|
||||
)
|
||||
}
|
||||
|
||||
builder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
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)*)?);
|
||||
}}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
kind: ReportKind::Error,
|
||||
source: $source,
|
||||
message: $message,
|
||||
spans,
|
||||
});
|
||||
}}
|
||||
}
|
||||
|
||||
#[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:#?}");
|
||||
}
|
||||
}
|
|
@ -17,6 +17,17 @@ pub trait Source: Downcast + Debug {
|
|||
}
|
||||
impl_downcast!(Source);
|
||||
|
||||
pub trait SourcePosition
|
||||
{
|
||||
/// Transforms a position to it's position in the oldest parent source
|
||||
fn original_position(&self, pos: usize) -> (Rc<dyn Source>, usize);
|
||||
|
||||
/// Transforms a range to the oldest parent source
|
||||
///
|
||||
/// This function takes a range from a source and attempts to get the range's position in the oldest parent
|
||||
fn original_range(&self, range: Range<usize>) -> (Rc<dyn Source>, Range<usize>);
|
||||
}
|
||||
|
||||
impl core::fmt::Display for dyn Source {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.name())
|
||||
|
@ -140,46 +151,55 @@ impl Source for VirtualSource {
|
|||
fn content(&self) -> &String { &self.content }
|
||||
}
|
||||
|
||||
/// Transforms a position to it's position in the oldest parent source
|
||||
pub fn original_position(source: Rc<dyn Source>, mut pos: usize) -> (Rc<dyn Source>, usize)
|
||||
impl SourcePosition for Rc<dyn Source>
|
||||
{
|
||||
fn original_position(&self, mut pos: usize) -> (Rc<dyn Source>, usize) {
|
||||
// Stop recursion
|
||||
if self.downcast_ref::<SourceFile>().is_some()
|
||||
{
|
||||
return (self.clone(), pos);
|
||||
}
|
||||
|
||||
// Apply offsets
|
||||
if let Some(offsets) =
|
||||
source.downcast_ref::<VirtualSource>()
|
||||
self.downcast_ref::<VirtualSource>()
|
||||
.and_then(|source| source.offsets.as_ref())
|
||||
{
|
||||
pos = offsets.position(pos);
|
||||
}
|
||||
|
||||
// Recurse to parent
|
||||
if let Some(parent) = source.location()
|
||||
if let Some(parent) = self.location()
|
||||
{
|
||||
return original_position(parent.source.clone(), parent.range.start + pos);
|
||||
return parent.source().original_position(parent.range.start + pos);
|
||||
}
|
||||
|
||||
return (source, pos);
|
||||
return (self.clone(), pos);
|
||||
}
|
||||
|
||||
/// Transforms a range to the oldest parent source
|
||||
///
|
||||
/// This function takes a range from a source and attempts to get the range's position in the oldest parent
|
||||
pub fn original_range(source: Rc<dyn Source>, mut range: Range<usize>) -> (Rc<dyn Source>, Range<usize>)
|
||||
fn original_range(&self, mut range: Range<usize>) -> (Rc<dyn Source>, Range<usize>) {
|
||||
// Stop recursion
|
||||
if self.downcast_ref::<SourceFile>().is_some()
|
||||
{
|
||||
return (self.clone(), range);
|
||||
}
|
||||
|
||||
// Apply offsets
|
||||
if let Some(offsets) =
|
||||
source.downcast_ref::<VirtualSource>()
|
||||
self.downcast_ref::<VirtualSource>()
|
||||
.and_then(|source| source.offsets.as_ref())
|
||||
{
|
||||
range = offsets.position(range.start) .. offsets.position(range.end);
|
||||
}
|
||||
|
||||
// Recurse to parent
|
||||
if let Some(parent) = source.location()
|
||||
if let Some(parent) = self.location()
|
||||
{
|
||||
return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
|
||||
return parent.source.original_range(parent.range.start + range.start..parent.range.start + range.end);
|
||||
}
|
||||
|
||||
return (source, range);
|
||||
return (self.clone(), range);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::iter::Peekable;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -9,12 +8,10 @@ use crate::document::document::Document;
|
|||
use crate::document::document::DocumentAccessors;
|
||||
use crate::document::element::ElemKind;
|
||||
use crate::elements::paragraph::Paragraph;
|
||||
use crate::parser::source::original_range;
|
||||
|
||||
use super::parser::ParseMode;
|
||||
use super::parser::ParserState;
|
||||
use super::source::Source;
|
||||
use super::source::SourceFile;
|
||||
use super::source::Token;
|
||||
use super::source::VirtualSource;
|
||||
|
||||
|
|
Loading…
Reference in a new issue