Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions rusty_lr_buildscript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,17 @@ impl Builder {
let diag =
match e {
ParseArgError::MacroLineParse { span, message } => {
let range = span.byte_range();

Diagnostic::error()
.with_message("Parse Failed")
.with_labels(vec![
Label::primary(file_id, range).with_message("Error here")
Label::primary(file_id, span).with_message("Error here")
])
.with_notes(vec![message])
}

_ => {
let message = e.short_message();
let span = e.span().byte_range();
let span = e.span();
Diagnostic::error().with_message(message).with_labels(vec![
Label::primary(file_id, span).with_message("occured here"),
])
Expand All @@ -321,13 +319,7 @@ impl Builder {
};

for error in &grammar_args.error_recovered {
let range = if let Some((first, last)) = error.span.pair {
let first_range = first.byte_range();
let last_range = last.byte_range();
first_range.start..last_range.end
} else {
0..1 // default range if span is not defined
};
let range = error.span.to_range();
let diag = Diagnostic::error()
.with_message("Syntax error in grammar")
.with_labels(vec![
Expand Down
2 changes: 1 addition & 1 deletion rusty_lr_parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords = ["parser", "bison", "lr", "glr", "compiler"]
categories = ["parsing"]

[dependencies]
proc-macro2 = "1.0.86"
proc-macro2 = { version = "1.0.86", features = ["span-locations"] }
quote = "1.0"
rusty_lr_core = { version = "3.40.0", path = "../rusty_lr_core", features = [
"builder",
Expand Down
15 changes: 10 additions & 5 deletions rusty_lr_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ use proc_macro2::TokenStream;
use quote::quote_spanned;

use crate::parser::args::IdentOrLiteral;
use crate::parser::span_pair::byte_range_to_span;

/// failed to feed() the token
#[non_exhaustive]
#[derive(Debug)]
pub enum ParseArgError {
/// feed() failed
MacroLineParse { span: Span, message: String },
/// feed() failed; `span` is the byte range `[start, end)` in the source
MacroLineParse {
span: std::ops::Range<usize>,
message: String,
},
}

#[non_exhaustive]
Expand Down Expand Up @@ -195,17 +199,18 @@ impl ArgError {
#[allow(unused)]
impl ParseArgError {
pub fn to_compile_error(&self) -> TokenStream {
let span = self.span();
let message = self.short_message();
let span = byte_range_to_span(self.span());
quote_spanned! {
span=>
compile_error!(#message);
}
}

pub fn span(&self) -> Span {
/// Returns the byte range `[start, end)` of the error location in the source.
pub fn span(&self) -> std::ops::Range<usize> {
match self {
ParseArgError::MacroLineParse { span, message } => *span,
ParseArgError::MacroLineParse { span, message } => span.clone(),
}
}

Expand Down
5 changes: 2 additions & 3 deletions rusty_lr_parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,15 @@ impl Grammar {
Ok(_) => {}
Err(err) => {
let message = err.to_string();
let span = err.location().unwrap().pair.unwrap().0;
let span = err.location().map(|loc| loc.to_range()).unwrap_or(0..0);
return Err(ParseArgError::MacroLineParse { span, message });
}
}
match context.accept(&parser, &mut grammar_args) {
Ok(_) => {}
Err(err) => {
let message = err.to_string();
let span = Span::call_site();
return Err(ParseArgError::MacroLineParse { span, message });
return Err(ParseArgError::MacroLineParse { span: 0..0, message });
}
}

Expand Down
9 changes: 6 additions & 3 deletions rusty_lr_parser/src/parser/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,8 @@ impl PatternArgs {
}
}
PatternArgs::Sep(_, _, _, span) => {
let (first, last) = span.pair.unwrap();
Err(ParseError::OnlyTerminalSet(first, last))
let s = span.span();
Err(ParseError::OnlyTerminalSet(s, s))
}
}
}
Expand Down Expand Up @@ -400,7 +400,10 @@ impl PatternArgs {
PatternArgs::Minus(base, terminal_set) => {
(base.span_pair().0, terminal_set.span_pair().1)
}
PatternArgs::Sep(_, _, _, span) => span.pair.unwrap(),
PatternArgs::Sep(_, _, _, span) => {
let s = span.span();
(s, s)
}
}
}

Expand Down
59 changes: 37 additions & 22 deletions rusty_lr_parser/src/parser/span_pair.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,63 @@
use proc_macro2::Span;

/// Converts a byte range `[start, end)` into a `proc_macro2::Span`.
/// Currently, byte offsets cannot be mapped back precisely, so this returns `Span::call_site()`.
pub fn byte_range_to_span(_range: std::ops::Range<usize>) -> Span {
Span::call_site()
}

/// type for %location for each token
/// since `Span::join()` is only for nightly,
/// we collect the first and last span pair of the token in the parsing tree.
/// stores byte offset range [start, end) in the source file.
#[derive(Clone, Debug, Copy)]
pub struct SpanPair {
/// `None` if this is a zero-length span
pub pair: Option<(Span, Span)>,
/// byte range `[start, end)` of the token span.
/// zero-length spans are represented with equal values `(pos, pos)`.
pub pair: (usize, usize),
}
impl Default for SpanPair {
fn default() -> Self {
SpanPair { pair: None }
SpanPair { pair: (0, 0) }
}
}
impl SpanPair {
pub fn new_single(span: Span) -> Self {
let range = span.byte_range();
SpanPair {
pair: Some((span, span)),
pair: (range.start, range.end),
}
}
/// Returns the byte range `[start, end)` of this span.
pub fn to_range(&self) -> std::ops::Range<usize> {
let (s, e) = self.pair;
s..e
}
/// Returns a `proc_macro2::Span` for use in proc-macro error reporting.
/// Since byte offsets cannot be converted back to `Span`, this falls back to `byte_range_to_span`.
pub fn span(&self) -> Span {
self.pair
.as_ref()
.map_or(Span::call_site(), |(first, last)| {
if let Some(joined) = first.join(*last) {
joined
} else {
*first
}
})
byte_range_to_span(self.to_range())
}
}
impl rusty_lr_core::Location for SpanPair {
fn new<'a>(stack: impl Iterator<Item = &'a Self> + Clone, len: usize) -> Self
fn new<'a>(mut stack: impl Iterator<Item = &'a Self> + Clone, len: usize) -> Self
where
Self: 'a,
{
let mut take = stack.take(len).filter_map(|x| x.pair);
let pair = if let Some(last) = take.next() {
let first = take.last().unwrap_or(last);

Some((first.0, last.1))
if len == 0 {
// zero-length: point to position after the most recent token
if let Some(after_pos) = stack.next() {
let (_, e) = after_pos.pair;
return SpanPair { pair: (e, e) };
}
return SpanPair::default();
}
// The iterator yields items most-recent-first, so the first item is the end span
// and the last item taken is the start span.
let mut take = stack.take(len).map(|x| x.pair);
let pair = if let Some(end_span) = take.next() {
let start_span = take.last().unwrap_or(end_span);
(start_span.0, end_span.1)
} else {
None
(0, 0)
};
SpanPair { pair }
}
Expand Down