diff --git a/src/elements/script.rs b/src/elements/script.rs index 6bdbd98..7c24178 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -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; diff --git a/src/elements/style.rs b/src/elements/style.rs index 9ed3a71..6bf7ebd 100644 --- a/src/elements/style.rs +++ b/src/elements/style.rs @@ -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; diff --git a/src/lsp/semantic.rs b/src/lsp/semantic.rs index fdeea28..3b25fec 100644 --- a/src/lsp/semantic.rs +++ b/src/lsp/semantic.rs @@ -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::().ok() { return Ref::filter_map( @@ -316,7 +315,7 @@ impl<'a> Semantics<'a> { } pub fn add(&self, range: Range, 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(); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 433cbec..b4137da 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7,3 +7,4 @@ pub mod util; pub mod style; pub mod layout; pub mod customstyle; +pub mod reports; diff --git a/src/parser/reports.rs b/src/parser/reports.rs new file mode 100644 index 0000000..bea0f8e --- /dev/null +++ b/src/parser/reports.rs @@ -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> 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, + pub message: String, + pub spans: Vec, +} + +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, Range)> + { + 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:#?}"); + } +} diff --git a/src/parser/source.rs b/src/parser/source.rs index a5cb50f..baf479f 100644 --- a/src/parser/source.rs +++ b/src/parser/source.rs @@ -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, 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) -> (Rc, Range); +} + 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, mut pos: usize) -> (Rc, usize) +impl SourcePosition for Rc { - // Apply offsets - if let Some(offsets) = - source.downcast_ref::() - .and_then(|source| source.offsets.as_ref()) - { - pos = offsets.position(pos); - } + fn original_position(&self, mut pos: usize) -> (Rc, usize) { + // Stop recursion + if self.downcast_ref::().is_some() + { + return (self.clone(), pos); + } - // Recurse to parent - if let Some(parent) = source.location() - { - return original_position(parent.source.clone(), parent.range.start + pos); - } + // Apply offsets + if let Some(offsets) = + self.downcast_ref::() + .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 -/// -/// 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, mut range: Range) -> (Rc, Range) -{ - // Apply offsets - if let Some(offsets) = - source.downcast_ref::() - .and_then(|source| source.offsets.as_ref()) - { - range = offsets.position(range.start) .. offsets.position(range.end); - } + return (self.clone(), pos); + } - // Recurse to parent - if let Some(parent) = source.location() - { - return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end); - } + fn original_range(&self, mut range: Range) -> (Rc, Range) { + // Stop recursion + if self.downcast_ref::().is_some() + { + return (self.clone(), range); + } - return (source, range); + // Apply offsets + if let Some(offsets) = + self.downcast_ref::() + .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)] diff --git a/src/parser/util.rs b/src/parser/util.rs index 32df163..36b1425 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -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;