mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-30 10:45:06 +00:00
Add a helper for getting the location of a span in some textual source.
This commit is contained in:
parent
62da3bf348
commit
f9dfc38c40
@ -16,6 +16,7 @@ use crate::{
|
||||
proc::{
|
||||
ensure_block_returns, Alignment, Layouter, ResolveContext, ResolveError, TypeResolution,
|
||||
},
|
||||
span::SourceLocation,
|
||||
span::Span as NagaSpan,
|
||||
Bytes, ConstantInner, FastHashMap, ScalarValue,
|
||||
};
|
||||
@ -29,7 +30,7 @@ use self::{
|
||||
};
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label},
|
||||
files::{Files, SimpleFile},
|
||||
files::SimpleFile,
|
||||
term::{
|
||||
self,
|
||||
termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor},
|
||||
@ -1367,17 +1368,10 @@ impl ParseError {
|
||||
|
||||
/// Returns the 1-based line number and column of the first label in the
|
||||
/// error message.
|
||||
pub fn location(&self, source: &str) -> (usize, usize) {
|
||||
let files = SimpleFile::new("wgsl", source);
|
||||
match self.labels.get(0) {
|
||||
Some(label) => {
|
||||
let location = files
|
||||
.location((), label.0.start)
|
||||
.expect("invalid span location");
|
||||
(location.line_number, location.column_number)
|
||||
}
|
||||
None => (1, 1),
|
||||
}
|
||||
pub fn location(&self, source: &str) -> Option<SourceLocation> {
|
||||
self.labels
|
||||
.get(0)
|
||||
.map(|label| NagaSpan::new(label.0.start as u32, label.0.end as u32).location(source))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ pub mod valid;
|
||||
|
||||
pub use crate::arena::{Arena, Handle, Range, UniqueArena};
|
||||
|
||||
pub use crate::span::{Span, SpanContext, WithSpan};
|
||||
pub use crate::span::{SourceLocation, Span, SpanContext, WithSpan};
|
||||
#[cfg(feature = "arbitrary")]
|
||||
use arbitrary::Arbitrary;
|
||||
#[cfg(feature = "deserialize")]
|
||||
|
150
src/span.rs
150
src/span.rs
@ -59,6 +59,22 @@ impl Span {
|
||||
pub fn is_defined(&self) -> bool {
|
||||
*self != Self::default()
|
||||
}
|
||||
|
||||
/// Returns the 1-based line number and column of the this span in
|
||||
/// the provided source.
|
||||
pub fn location(&self, source: &str) -> SourceLocation {
|
||||
let prefix = &source[..self.start as usize];
|
||||
let line_number = prefix.matches('\n').count() as u32 + 1;
|
||||
let line_start = prefix.rfind('\n').map(|pos| pos + 1).unwrap_or(0);
|
||||
let line_position = source[line_start..self.start as usize].chars().count() as u32 + 1;
|
||||
|
||||
SourceLocation {
|
||||
line_number,
|
||||
line_position,
|
||||
offset: self.start,
|
||||
length: self.end - self.start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Range<usize>> for Span {
|
||||
@ -70,6 +86,22 @@ impl From<Range<usize>> for Span {
|
||||
}
|
||||
}
|
||||
|
||||
/// A human-readable representation for span, tailored for text source.
|
||||
///
|
||||
/// Corresponds to the positional members of `GPUCompilationMessage` from the WebGPU specification,
|
||||
/// using utf8 instead of utf16 as reference encoding.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SourceLocation {
|
||||
/// 1-based line number.
|
||||
pub line_number: u32,
|
||||
/// 1-based column of the start of this span
|
||||
pub line_position: u32,
|
||||
/// 0-based Offset in code units (in bytes) of the start of the span.
|
||||
pub offset: u32,
|
||||
/// Length in code units (in bytes) of the span.
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
/// A source code span together with "context", a user-readable description of what part of the error it refers to.
|
||||
pub type SpanContext = (Span, String);
|
||||
|
||||
@ -186,6 +218,20 @@ impl<E> WithSpan<E> {
|
||||
res.spans.extend(self.spans);
|
||||
res
|
||||
}
|
||||
|
||||
#[cfg(feature = "span")]
|
||||
pub fn location(&self, source: &str) -> Option<SourceLocation> {
|
||||
if self.spans.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(self.spans[0].0.location(source))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "span"))]
|
||||
pub fn location(&self, _source: &str) -> Option<SourceLocation> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience trait for [`Error`] to be able to apply spans to anything.
|
||||
@ -273,3 +319,107 @@ impl<T, E, E2> MapErrWithSpan<E, E2> for Result<T, WithSpan<E>> {
|
||||
self.map_err(|e| e.and_then(func).into_other::<E2>())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_location() {
|
||||
let source = "12\n45\n\n89\n";
|
||||
assert_eq!(
|
||||
Span { start: 0, end: 1 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 1,
|
||||
line_position: 1,
|
||||
offset: 0,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 1, end: 2 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 1,
|
||||
line_position: 2,
|
||||
offset: 1,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 2, end: 3 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 1,
|
||||
line_position: 3,
|
||||
offset: 2,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 3, end: 5 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 2,
|
||||
line_position: 1,
|
||||
offset: 3,
|
||||
length: 2
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 4, end: 6 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 2,
|
||||
line_position: 2,
|
||||
offset: 4,
|
||||
length: 2
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 5, end: 6 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 2,
|
||||
line_position: 3,
|
||||
offset: 5,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 6, end: 7 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 3,
|
||||
line_position: 1,
|
||||
offset: 6,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 7, end: 8 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 4,
|
||||
line_position: 1,
|
||||
offset: 7,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 8, end: 9 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 4,
|
||||
line_position: 2,
|
||||
offset: 8,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 9, end: 10 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 4,
|
||||
line_position: 3,
|
||||
offset: 9,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Span { start: 10, end: 11 }.location(source),
|
||||
SourceLocation {
|
||||
line_number: 5,
|
||||
line_position: 1,
|
||||
offset: 10,
|
||||
length: 1
|
||||
}
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user