Skip to content

Commit

Permalink
Merge pull request #47 from jaredh159/diagnostic-source-file
Browse files Browse the repository at this point in the history
fix diagnostics from included files
  • Loading branch information
jaredh159 authored Feb 12, 2025
2 parents 551d37e + b4fef3c commit a4af777
Show file tree
Hide file tree
Showing 30 changed files with 224 additions and 162 deletions.
18 changes: 13 additions & 5 deletions ast/src/chunk_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,32 @@ use crate::internal::*;
pub struct ChunkMeta<'arena> {
pub attrs: MultiAttrList<'arena>,
pub title: Option<InlineNodes<'arena>>,
pub start: u32, // rename
pub start_loc: SourceLocation,
}

impl<'arena> ChunkMeta<'arena> {
pub fn empty(start: u32, bump: &'arena Bump) -> Self {
pub fn empty(start_loc: SourceLocation, bump: &'arena Bump) -> Self {
Self {
title: None,
attrs: MultiAttrList::new_in(bump),
start,
start_loc,
}
}

pub fn new(
attrs: impl Into<MultiAttrList<'arena>>,
title: Option<InlineNodes<'arena>>,
start: u32,
start_loc: impl Into<SourceLocation>,
) -> Self {
Self { title, attrs: attrs.into(), start }
let mut cm = Self {
title,
attrs: attrs.into(),
start_loc: start_loc.into(),
};
if cm.is_empty() {
cm.start_loc = cm.start_loc.clamp_start();
}
cm
}

pub fn is_empty(&self) -> bool {
Expand Down
4 changes: 4 additions & 0 deletions ast/src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl ListItem<'_> {
self.marker_src.loc.start
}

pub const fn loc(&self) -> SourceLocation {
self.marker_src.loc
}

pub fn last_loc(&self) -> Option<SourceLocation> {
self
.blocks
Expand Down
19 changes: 19 additions & 0 deletions ast/src/source_location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,30 @@ impl SourceLocation {
Self { start, end, include_depth }
}

pub fn spanning(start: Self, end: Self) -> Self {
debug_assert!(start.start <= end.start);
debug_assert!(start.end <= end.end);
debug_assert!(start.include_depth == end.include_depth);
Self {
start: start.start,
end: end.end,
include_depth: start.include_depth,
}
}

pub fn extend(&mut self, other: SourceLocation) {
self.start = self.start.min(other.start);
self.end = self.end.max(other.end);
}

pub fn adding_to_end(&self, adding: u32) -> SourceLocation {
Self::new_depth(self.start, self.end + adding, self.include_depth)
}

pub fn setting_end(&self, end: u32) -> SourceLocation {
Self::new_depth(self.start, end, self.include_depth)
}

#[must_use]
pub fn clamp_start(&self) -> SourceLocation {
Self::new_depth(self.start, self.start, self.include_depth)
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,4 @@ impl DiagnosticColor for Colorizer {
}
}

// hack: force cli version publish - dec4b426
// hack: force cli version publish - bb8615fe
66 changes: 33 additions & 33 deletions parser/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,34 @@ pub struct Diagnostic {
}

impl Parser<'_> {
pub(crate) fn err_at(&self, message: impl Into<String>, start: u32, end: u32) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(start);
self.handle_err(Diagnostic {
line_num,
line: self.lexer.line_of(start).to_string(),
message: message.into(),
underline_start: offset,
underline_width: end - start,
source_file: self.lexer.source_file().clone(),
})
}

pub(crate) fn err_line(&self, message: impl Into<String>, line: &Line) -> Result<()> {
let start = line.loc().expect("non empty line for `err_line`").start;
let (line_num, offset) = self.lexer.line_number_with_offset(start);
let loc = line.loc().expect("non empty line for `err_line`");
let (line_num, offset) = self.lexer.line_number_with_offset(loc);
let line = line.reassemble_src().to_string();
self.handle_err(Diagnostic {
line_num,
message: message.into(),
underline_start: offset,
underline_width: line.len() as u32,
line,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(loc.include_depth).clone(),
})
}

pub(crate) fn err_line_starting(&self, message: impl Into<String>, start: u32) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(start);
let line = self.lexer.line_of(start);
pub(crate) fn err_line_starting(
&self,
message: impl Into<String>,
loc: SourceLocation,
) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(loc);
let line = self.lexer.line_of(loc);
self.handle_err(Diagnostic {
line_num,
message: message.into(),
underline_start: offset,
underline_width: line.len() as u32,
line: String::from(line.as_str()),
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(loc.include_depth).clone(),
})
}

Expand Down Expand Up @@ -83,7 +75,7 @@ impl Parser<'_> {
pub(crate) fn err_at_pattern(
&self,
message: impl Into<String>,
line_start: u32,
line_start: SourceLocation,
pattern: &str,
) -> Result<()> {
let (line_num, _) = self.lexer.line_number_with_offset(line_start);
Expand All @@ -95,7 +87,7 @@ impl Parser<'_> {
message: message.into(),
underline_start: idx as u32,
underline_width: pattern.len() as u32,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(line_start.include_depth).clone(),
});
}
self.handle_err(Diagnostic {
Expand All @@ -104,48 +96,56 @@ impl Parser<'_> {
message: message.into(),
underline_start: 0,
underline_width: line.len() as u32,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(line_start.include_depth).clone(),
})
}

pub(crate) fn err_at_loc(&self, message: impl Into<String>, loc: SourceLocation) -> Result<()> {
self.err_at(message, loc.start, loc.end)
pub(crate) fn err_at(&self, message: impl Into<String>, loc: SourceLocation) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(loc);
self.handle_err(Diagnostic {
line_num,
line: self.lexer.line_of(loc).to_string(),
message: message.into(),
underline_start: offset,
underline_width: loc.end - loc.start,
source_file: self.lexer.source_file_at(loc.include_depth).clone(),
})
}

pub(crate) fn err_token_full(&self, message: impl Into<String>, token: &Token) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(token.loc.start);
let (line_num, offset) = self.lexer.line_number_with_offset(token.loc);
self.handle_err(Diagnostic {
line_num,
line: self.lexer.line_of(token.loc.start).to_string(),
line: self.lexer.line_of(token.loc).to_string(),
message: message.into(),
underline_start: offset,
underline_width: token.lexeme.len() as u32,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(token.loc.include_depth).clone(),
})
}

pub(crate) fn err_token_start(&self, message: impl Into<String>, token: &Token) -> Result<()> {
let (line_num, offset) = self.lexer.line_number_with_offset(token.loc.start);
let (line_num, offset) = self.lexer.line_number_with_offset(token.loc);
self.handle_err(Diagnostic {
line_num,
line: self.lexer.line_of(token.loc.start).to_string(),
line: self.lexer.line_of(token.loc).to_string(),
message: message.into(),
underline_start: offset,
underline_width: 1,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(token.loc.include_depth).clone(),
})
}

pub(crate) fn err_token(&self, message: impl Into<String>, token: Option<&Token>) -> Result<()> {
let location = token.map_or_else(|| self.lexer.loc(), |t| t.loc);
let (line_num, offset) = self.lexer.line_number_with_offset(location.start);
let (line_num, offset) = self.lexer.line_number_with_offset(location);
self.handle_err(Diagnostic {
line_num,
line: self.lexer.line_of(location.start).to_string(),
line: self.lexer.line_of(location).to_string(),
message: message.into(),
underline_start: offset,
underline_width: 1,
source_file: self.lexer.source_file().clone(),
source_file: self.lexer.source_file_at(location.include_depth).clone(),
})
}

Expand Down
71 changes: 35 additions & 36 deletions parser/src/lexer/root_lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,17 +202,17 @@ impl<'arena> RootLexer<'arena> {
self.peek() == Some(c)
}

pub fn line_of(&self, location: u32) -> BumpString<'arena> {
self.sources[self.idx as usize].line_of(location)
pub fn line_of(&self, loc: SourceLocation) -> BumpString<'arena> {
self.sources[loc.include_depth as usize].line_of(loc.start)
}

pub fn line_number(&self, location: u32) -> u32 {
let (line_number, _) = self.line_number_with_offset(location);
pub fn line_number(&self, loc: SourceLocation) -> u32 {
let (line_number, _) = self.line_number_with_offset(loc);
line_number
}

pub fn line_number_with_offset(&self, location: u32) -> (u32, u32) {
self.sources[self.idx as usize].line_number_with_offset(location)
pub fn line_number_with_offset(&self, loc: SourceLocation) -> (u32, u32) {
self.sources[loc.include_depth as usize].line_number_with_offset(loc.start)
}

pub fn next_token(&mut self) -> Token<'arena> {
Expand Down Expand Up @@ -792,32 +792,31 @@ mod tests {
#[test]
fn test_line_of() {
let lexer = test_lexer!("foo\nbar\n\nbaz\n");
assert_eq!(lexer.line_of(1), "foo");
assert_eq!(lexer.line_of(2), "foo");
assert_eq!(lexer.line_of(3), "foo"); // newline

assert_eq!(lexer.line_of(4), "bar");
assert_eq!(lexer.line_of(7), "bar");
assert_eq!(lexer.line_of(8), ""); // empty line
assert_eq!(lexer.line_of(9), "baz");
assert_eq!(lexer.line_of(1.into()), "foo");
assert_eq!(lexer.line_of(2.into()), "foo");
assert_eq!(lexer.line_of(3.into()), "foo"); // newline
assert_eq!(lexer.line_of(4.into()), "bar");
assert_eq!(lexer.line_of(7.into()), "bar");
assert_eq!(lexer.line_of(8.into()), ""); // empty line
assert_eq!(lexer.line_of(9.into()), "baz");
}

#[test]
fn test_line_of_win_crlf() {
let lexer = test_lexer!("foo\r\nbar\r\n\r\nbaz\r\n");
assert_eq!(lexer.line_of(0), "foo");
assert_eq!(lexer.line_of(1), "foo");
assert_eq!(lexer.line_of(2), "foo");
assert_eq!(lexer.line_of(3), "foo"); // newline '\r'
assert_eq!(lexer.line_of(4), "foo"); // newline '\n'
assert_eq!(lexer.line_of(5), "bar");
assert_eq!(lexer.line_of(6), "bar");
assert_eq!(lexer.line_of(7), "bar");
assert_eq!(lexer.line_of(8), "bar"); // newline '\r'
assert_eq!(lexer.line_of(9), "bar"); // newline '\n'
assert_eq!(lexer.line_of(10), ""); // empty line
assert_eq!(lexer.line_of(11), ""); // empty line
assert_eq!(lexer.line_of(12), "baz");
assert_eq!(lexer.line_of(0.into()), "foo");
assert_eq!(lexer.line_of(1.into()), "foo");
assert_eq!(lexer.line_of(2.into()), "foo");
assert_eq!(lexer.line_of(3.into()), "foo"); // newline '\r'
assert_eq!(lexer.line_of(4.into()), "foo"); // newline '\n'
assert_eq!(lexer.line_of(5.into()), "bar");
assert_eq!(lexer.line_of(6.into()), "bar");
assert_eq!(lexer.line_of(7.into()), "bar");
assert_eq!(lexer.line_of(8.into()), "bar"); // newline '\r'
assert_eq!(lexer.line_of(9.into()), "bar"); // newline '\n'
assert_eq!(lexer.line_of(10.into()), ""); // empty line
assert_eq!(lexer.line_of(11.into()), ""); // empty line
assert_eq!(lexer.line_of(12.into()), "baz");
}

#[test]
Expand All @@ -842,20 +841,20 @@ mod tests {
fn test_line_num_win_crlf() {
let input = "foo\r\nbar\r\n\r\nbaz\r\n";
let lexer = test_lexer!(input);
assert_eq!(lexer.line_number(0), 1);
assert_eq!(lexer.line_number(3), 1); // newline '\r'
assert_eq!(lexer.line_number(4), 1); // newline '\n'
assert_eq!(lexer.line_number(5), 2); // 'b' of 'bar'
assert_eq!(lexer.line_number(9), 2); // '\n' of 'bar\r\n'
assert_eq!(lexer.line_number(10), 3); // empty line '\r'
assert_eq!(lexer.line_number(11), 3); // empty line '\n'
assert_eq!(lexer.line_number(12), 4); // 'b' of 'baz'
assert_eq!(lexer.line_number(0.into()), 1);
assert_eq!(lexer.line_number(3.into()), 1); // newline '\r'
assert_eq!(lexer.line_number(4.into()), 1); // newline '\n'
assert_eq!(lexer.line_number(5.into()), 2); // 'b' of 'bar'
assert_eq!(lexer.line_number(9.into()), 2); // '\n' of 'bar\r\n'
assert_eq!(lexer.line_number(10.into()), 3); // empty line '\r'
assert_eq!(lexer.line_number(11.into()), 3); // empty line '\n'
assert_eq!(lexer.line_number(12.into()), 4); // 'b' of 'baz'
}

fn assert_next_token_line(lexer: &mut RootLexer, line: u32, expected_kind: TokenKind) {
let token = lexer.next_token();
assert_eq!(token.kind, expected_kind);
assert_eq!(lexer.line_number(token.loc.start), line);
assert_eq!(lexer.line_number(token.loc), line);
}

#[test]
Expand Down
6 changes: 3 additions & 3 deletions parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@ impl<'arena> Parser<'arena> {
return Ok(meta);
}
assert!(!lines.is_empty());
let start = lines.current_token().unwrap().loc.start;
let start_loc = lines.current_token().unwrap().loc;
let mut attrs = MultiAttrList::new_in(self.bump);
let mut title = None;
if !lines.current().unwrap().is_fully_unconsumed() {
return Ok(ChunkMeta { attrs, title, start });
return Ok(ChunkMeta::new(attrs, title, start_loc));
}
loop {
match lines.current() {
Expand Down Expand Up @@ -278,7 +278,7 @@ impl<'arena> Parser<'arena> {
_ => break,
}
}
Ok(ChunkMeta { attrs, title, start })
Ok(ChunkMeta::new(attrs, title, start_loc))
}

pub(crate) fn string(&self, s: &str) -> BumpString<'arena> {
Expand Down
3 changes: 1 addition & 2 deletions parser/src/tasks/anchors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ impl<'arena> Parser<'arena> {
} else {
"Duplicate anchor id"
},
id.loc.start,
id.loc.end,
id.loc,
)?;
} else {
anchors.insert(id.src.clone(), anchor);
Expand Down
2 changes: 1 addition & 1 deletion parser/src/tasks/diagnose_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Parser<'_> {
}

fn invalid_xref(&self, target: &str, loc: SourceLocation) -> Result<()> {
self.err_at_loc(
self.err_at(
format!("Invalid cross reference, no anchor found for `{target}`"),
loc,
)
Expand Down
4 changes: 2 additions & 2 deletions parser/src/tasks/directives/ifeval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<'arena> Parser<'arena> {
}
self.err_at_pattern(
"Invalid ifeval directive expression",
line.loc().unwrap().start,
line.loc().unwrap(),
pattern,
)?;
}
Expand All @@ -24,7 +24,7 @@ impl<'arena> Parser<'arena> {
if !&captures[1].is_empty() {
self.err_at_pattern(
"ifeval directive may not include a target",
line.loc().unwrap().start,
line.loc().unwrap(),
&captures[1],
)?;
return Ok(DirectiveAction::Passthrough);
Expand Down
Loading

0 comments on commit a4af777

Please sign in to comment.