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(
|
let parse_source = Rc::new(VirtualSource::new(
|
||||||
Token::new(0..source.content().len(), source.clone()),
|
Token::new(0..source.content().len(), source.clone()),
|
||||||
format!("parse({})", source.name()),
|
format!(":LUA:parse({})", source.name()),
|
||||||
result,
|
result,
|
||||||
)) as Rc<dyn Source>;
|
)) as Rc<dyn Source>;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ use crate::lua::kernel::CTX;
|
||||||
use crate::parser::parser::ParseMode;
|
use crate::parser::parser::ParseMode;
|
||||||
use crate::parser::parser::ParserState;
|
use crate::parser::parser::ParserState;
|
||||||
use crate::parser::rule::RegexRule;
|
use crate::parser::rule::RegexRule;
|
||||||
use crate::parser::source::original_range;
|
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::state::RuleState;
|
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::SemanticTokenModifier;
|
||||||
use tower_lsp::lsp_types::SemanticTokenType;
|
use tower_lsp::lsp_types::SemanticTokenType;
|
||||||
|
|
||||||
use crate::parser::source::original_range;
|
|
||||||
use crate::parser::source::LineCursor;
|
use crate::parser::source::LineCursor;
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
|
use crate::parser::source::SourcePosition;
|
||||||
use crate::parser::source::VirtualSource;
|
use crate::parser::source::VirtualSource;
|
||||||
|
|
||||||
pub const TOKEN_TYPE: &[SemanticTokenType] = &[
|
pub const TOKEN_TYPE: &[SemanticTokenType] = &[
|
||||||
|
@ -278,7 +278,6 @@ impl<'a> Semantics<'a> {
|
||||||
.map(|parent| parent.location())
|
.map(|parent| parent.location())
|
||||||
.unwrap_or(None)
|
.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);
|
return Self::from_source_impl(location.source(), semantics, original_source);
|
||||||
} else if let Some(source) = source.clone().downcast_rc::<SourceFile>().ok() {
|
} else if let Some(source) = source.clone().downcast_rc::<SourceFile>().ok() {
|
||||||
return Ref::filter_map(
|
return Ref::filter_map(
|
||||||
|
@ -316,7 +315,7 @@ impl<'a> Semantics<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&self, range: Range<usize>, token: (u32, u32)) {
|
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 tokens = self.sems.tokens.borrow_mut();
|
||||||
let mut cursor = self.sems.cursor.borrow_mut();
|
let mut cursor = self.sems.cursor.borrow_mut();
|
||||||
let mut current = cursor.clone();
|
let mut current = cursor.clone();
|
||||||
|
|
|
@ -7,3 +7,4 @@ pub mod util;
|
||||||
pub mod style;
|
pub mod style;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod customstyle;
|
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);
|
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 {
|
impl core::fmt::Display for dyn Source {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.name())
|
write!(f, "{}", self.name())
|
||||||
|
@ -140,46 +151,55 @@ impl Source for VirtualSource {
|
||||||
fn content(&self) -> &String { &self.content }
|
fn content(&self) -> &String { &self.content }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms a position to it's position in the oldest parent source
|
impl SourcePosition for Rc<dyn Source>
|
||||||
pub fn original_position(source: Rc<dyn Source>, mut pos: usize) -> (Rc<dyn Source>, usize)
|
|
||||||
{
|
{
|
||||||
// Apply offsets
|
fn original_position(&self, mut pos: usize) -> (Rc<dyn Source>, usize) {
|
||||||
if let Some(offsets) =
|
// Stop recursion
|
||||||
source.downcast_ref::<VirtualSource>()
|
if self.downcast_ref::<SourceFile>().is_some()
|
||||||
.and_then(|source| source.offsets.as_ref())
|
{
|
||||||
{
|
return (self.clone(), pos);
|
||||||
pos = offsets.position(pos);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse to parent
|
// Apply offsets
|
||||||
if let Some(parent) = source.location()
|
if let Some(offsets) =
|
||||||
{
|
self.downcast_ref::<VirtualSource>()
|
||||||
return original_position(parent.source.clone(), parent.range.start + pos);
|
.and_then(|source| source.offsets.as_ref())
|
||||||
}
|
{
|
||||||
|
pos = offsets.position(pos);
|
||||||
|
}
|
||||||
|
|
||||||
return (source, pos);
|
// Recurse to parent
|
||||||
}
|
if let Some(parent) = self.location()
|
||||||
|
{
|
||||||
|
return parent.source().original_position(parent.range.start + pos);
|
||||||
|
}
|
||||||
|
|
||||||
/// Transforms a range to the oldest parent source
|
return (self.clone(), pos);
|
||||||
///
|
}
|
||||||
/// 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>)
|
|
||||||
{
|
|
||||||
// Apply offsets
|
|
||||||
if let Some(offsets) =
|
|
||||||
source.downcast_ref::<VirtualSource>()
|
|
||||||
.and_then(|source| source.offsets.as_ref())
|
|
||||||
{
|
|
||||||
range = offsets.position(range.start) .. offsets.position(range.end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse to parent
|
fn original_range(&self, mut range: Range<usize>) -> (Rc<dyn Source>, Range<usize>) {
|
||||||
if let Some(parent) = source.location()
|
// Stop recursion
|
||||||
{
|
if self.downcast_ref::<SourceFile>().is_some()
|
||||||
return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
|
{
|
||||||
}
|
return (self.clone(), range);
|
||||||
|
}
|
||||||
|
|
||||||
return (source, range);
|
// Apply offsets
|
||||||
|
if let Some(offsets) =
|
||||||
|
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) = self.location()
|
||||||
|
{
|
||||||
|
return parent.source.original_range(parent.range.start + range.start..parent.range.start + range.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (self.clone(), range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::Peekable;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -9,12 +8,10 @@ use crate::document::document::Document;
|
||||||
use crate::document::document::DocumentAccessors;
|
use crate::document::document::DocumentAccessors;
|
||||||
use crate::document::element::ElemKind;
|
use crate::document::element::ElemKind;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
use crate::parser::source::original_range;
|
|
||||||
|
|
||||||
use super::parser::ParseMode;
|
use super::parser::ParseMode;
|
||||||
use super::parser::ParserState;
|
use super::parser::ParserState;
|
||||||
use super::source::Source;
|
use super::source::Source;
|
||||||
use super::source::SourceFile;
|
|
||||||
use super::source::Token;
|
use super::source::Token;
|
||||||
use super::source::VirtualSource;
|
use super::source::VirtualSource;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue