tamer: Consistent span diagram representation
I'll document it more formally eventually, but this settles on a mix of the two: square brackets and dashes for intervals, `+` for intersecting lines, byte offsets below interval endpoints, and names below that. The docblock for `Span` itself iss still off; I'll probably just take one of the test cases and paste it there at some point. DEV-7145main
parent
bba181f573
commit
495c1438fd
|
@ -86,9 +86,11 @@ impl Diagnostic for StubError {
|
|||
|
||||
const FILE_FOO_BAR: &[u8] =
|
||||
b"foo/bar line 1\nfoo/bar line 2\nfoo/bar line 3\nfoo/bar line 4";
|
||||
// |-------+--+-| |-------+--+-| |-------+--+-| |-------+--+-|
|
||||
// [-------+--+-] [-------+--+-] [-------+--+-] [-------+--+-]
|
||||
// 0 | |13 15 | |28 30 | |43 45 | |58
|
||||
// [--] [--] [--] [--]
|
||||
// 8 11 23 26 38 41 53 56
|
||||
//
|
||||
// len: 14
|
||||
|
||||
const FILE_BAR_BAZ: &[u8] =
|
||||
|
@ -96,7 +98,7 @@ const FILE_BAR_BAZ: &[u8] =
|
|||
// Offsets for this are the same as `FILE_FOO_BAR`.
|
||||
|
||||
const FILE_INVALID_UTF8: &[u8] = b"bad \xC0!";
|
||||
// |---- |
|
||||
// [---- ]
|
||||
// 0 5
|
||||
|
||||
const FILE_MANY_LINES: &[u8] = b"\
|
||||
|
|
|
@ -651,11 +651,11 @@ impl Line {
|
|||
///
|
||||
/// # Will have its columns reported as:
|
||||
/// line 1
|
||||
/// |-| [4,6]
|
||||
/// [-] [4,6]
|
||||
/// line 2
|
||||
/// |----| [1,6]
|
||||
/// [----] [1,6]
|
||||
/// line 4
|
||||
/// |^^| [1,4]
|
||||
/// [--] [1,4]
|
||||
/// ```
|
||||
fn resolve_columns(&self, line: &str, span: Span) -> Column {
|
||||
// The max(1) here is intended to accommodate zero-length spans.
|
||||
|
|
|
@ -74,9 +74,9 @@ fn rejects_span_with_endpoint_past_eof() {
|
|||
fn first_byte_of_line() {
|
||||
let ctx = Context::from("foo");
|
||||
let buf = "line 1\nline 2\nline 3\nline 4";
|
||||
// |--| |
|
||||
// [--] |
|
||||
// 7 10 |
|
||||
// |----|
|
||||
// [----]
|
||||
// 12
|
||||
|
||||
let span = ctx.span(7, 4);
|
||||
|
@ -107,7 +107,7 @@ fn last_byte_of_line() {
|
|||
let buf = "line 1\nline 2\nline 3\nline 4";
|
||||
// | |
|
||||
// | 19
|
||||
// |----|
|
||||
// [----]
|
||||
// 14
|
||||
|
||||
let span = ctx.span(19, 1);
|
||||
|
@ -139,9 +139,9 @@ fn last_byte_of_line() {
|
|||
fn last_byte_of_file_no_trailing_nl() {
|
||||
let ctx = Context::from("foo");
|
||||
let buf = "line 1\nline 2\nline 3";
|
||||
// | |--|
|
||||
// | [--]
|
||||
// | 16 19
|
||||
// |----|
|
||||
// [----]
|
||||
// 14
|
||||
|
||||
let span = ctx.span(16, 4);
|
||||
|
@ -171,9 +171,9 @@ fn last_byte_of_file_no_trailing_nl() {
|
|||
fn multiple_lines_first_last() {
|
||||
let ctx = Context::from("foobar");
|
||||
let buf = "line 1\nline start 2\nend line 3";
|
||||
// | |-----+- +-| |
|
||||
// | [-----+- +-] |
|
||||
// | 12 | |22 |
|
||||
// |----------| |--------|
|
||||
// [----------] [--------]
|
||||
// 7 18 20 29
|
||||
|
||||
let span = ctx.span(12, 11);
|
||||
|
@ -217,9 +217,9 @@ fn multiple_lines_first_last() {
|
|||
fn multiple_lines_middle_line_endpoints() {
|
||||
let ctx = Context::from("foobar");
|
||||
let buf = "line start 1\nline 2\nend line 3";
|
||||
// | |-----+- +----+- +-| |
|
||||
// | [-----+- +----+- +-] |
|
||||
// | 5 | | | |22 |
|
||||
// |----------| |----| |--------|
|
||||
// [----------] [----] [--------]
|
||||
// 0 11 13 18 20 29
|
||||
|
||||
let span = ctx.span(5, 18);
|
||||
|
@ -276,7 +276,7 @@ fn multiple_lines_middle_line_endpoints() {
|
|||
fn first_line() {
|
||||
let ctx = Context::from("foobar");
|
||||
let buf = "line 1\n";
|
||||
// |----|
|
||||
// [----]
|
||||
// 0 5
|
||||
|
||||
let span = ctx.span(0, 6);
|
||||
|
@ -313,7 +313,7 @@ fn newline_between_lines() {
|
|||
let buf = "line 1\nline 2\nline 3";
|
||||
// | ||
|
||||
// | |13
|
||||
// |----|
|
||||
// [----]
|
||||
// 7 12
|
||||
|
||||
let span = ctx.span(13, 1);
|
||||
|
@ -351,7 +351,7 @@ fn zero_length_span() {
|
|||
let buf = "line 1\nline 2\nline 3";
|
||||
// | | |
|
||||
// | 10 |
|
||||
// |----|
|
||||
// [----]
|
||||
// 7 12
|
||||
|
||||
let span = ctx.span(10, 0);
|
||||
|
@ -384,7 +384,7 @@ fn zero_length_span_at_eol() {
|
|||
let buf = "line 1\nline 2\nline 3";
|
||||
// | ||
|
||||
// | |13
|
||||
// |----|
|
||||
// [----]
|
||||
// 7 12
|
||||
|
||||
let span = ctx.span(13, 0);
|
||||
|
@ -421,7 +421,7 @@ fn zero_length_span_at_bol() {
|
|||
let buf = "line 1\nline 2\nline 3";
|
||||
// | |
|
||||
// 7 |
|
||||
// |----|
|
||||
// [----]
|
||||
// 12
|
||||
|
||||
let span = ctx.span(7, 0);
|
||||
|
@ -449,7 +449,7 @@ fn zero_length_span_at_bol() {
|
|||
fn resolve_multiple_spans() {
|
||||
let ctx = Context::from("multi");
|
||||
let buf = "line 1\nline 2\nline 3";
|
||||
// |----| |----|
|
||||
// [----] [----]
|
||||
// 7 12 14 19
|
||||
// A B
|
||||
|
||||
|
@ -497,7 +497,7 @@ fn resolve_multiple_spans() {
|
|||
fn resolve_same_span_multiple_times() {
|
||||
let ctx = Context::from("multi");
|
||||
let buf = "line 1\nline 2\nline 3";
|
||||
// |----|
|
||||
// [----]
|
||||
// 7 12
|
||||
// A
|
||||
|
||||
|
@ -529,7 +529,7 @@ fn resolve_same_span_multiple_times() {
|
|||
fn resolve_earlier_span_after_later() {
|
||||
let ctx = Context::from("multi");
|
||||
let buf = "line 1\nline 2\nline 3";
|
||||
// |----| |----|
|
||||
// [----] [----]
|
||||
// 0 5 7 12
|
||||
// earlier later
|
||||
|
||||
|
@ -592,7 +592,7 @@ fn invalid_unicode_no_column() {
|
|||
let ctx = Context::from("invalid-unicode");
|
||||
|
||||
let mut buf = b"bad \xC0!\n".to_vec();
|
||||
// |---- |
|
||||
// [---- ]
|
||||
// 0 5
|
||||
|
||||
let span = ctx.span(0, 4);
|
||||
|
@ -628,7 +628,7 @@ fn unicode_width() {
|
|||
let ctx = Context::from("unicode-width");
|
||||
|
||||
let buf = "0:\0\n1:“\n2:😊";
|
||||
// |-| |-| |--|
|
||||
// [-] [-] [--]
|
||||
// bytes: 0 2 4 8 10 15
|
||||
// col: 1 2 1 3 1 4
|
||||
|
||||
|
@ -710,7 +710,7 @@ fn at_invalid_char_boundary() {
|
|||
|
||||
// Charcater is 4 bytes.
|
||||
let buf = "(😊)";
|
||||
// |--|
|
||||
// [--]
|
||||
// bytes: 0 5
|
||||
// col: 1 4
|
||||
|
||||
|
|
|
@ -86,13 +86,13 @@
|
|||
//! # let ctx: Context = "some/path/foo".intern().into();
|
||||
//! #
|
||||
//! // Visualization of spans:
|
||||
//! // [..... ..... ..... .....]
|
||||
//! // [A====] [B==] |
|
||||
//! // | | [C=] |
|
||||
//! // | | [D====]
|
||||
//! // | | [E] |
|
||||
//! // [F=====] |
|
||||
//! // [G=======] |
|
||||
//! // [....,....,....,....,]
|
||||
//! // [A-+-] [B-+]|
|
||||
//! // | [C-] |
|
||||
//! // | [D-+-]
|
||||
//! // | [E]
|
||||
//! // [F----] |
|
||||
//! // [G------]
|
||||
//!
|
||||
//! let A = Span::new(2, 6, ctx);
|
||||
//! let B = Span::new(10, 5, ctx);
|
||||
|
@ -342,9 +342,10 @@ impl Span {
|
|||
/// #
|
||||
/// # let ctx: Context = "some/path/foo".intern().into();
|
||||
/// #
|
||||
/// // [..... .....]
|
||||
/// // [A===]
|
||||
/// // 2 6
|
||||
/// // [0123456789]
|
||||
/// // [---]
|
||||
/// // 2 6
|
||||
/// // A
|
||||
/// let A = Span::new(2, 6, ctx);
|
||||
///
|
||||
/// assert_eq!(
|
||||
|
|
|
@ -44,19 +44,21 @@ pub struct Attr(pub QName, pub SymbolId, pub AttrSpan);
|
|||
/// The diagram below illustrates the behavior of `AttrSpan`.
|
||||
/// Note that the extra spaces surrounding the `=` are intentional to
|
||||
/// illustrate what the behavior ought to be.
|
||||
/// Spans are represented by `|---|` intervals,
|
||||
/// Spans are represented by `[---]` intervals,
|
||||
/// with the byte offset at each end,
|
||||
/// and the single-letter span name centered below the interval.
|
||||
/// `+` represents intersecting `-` and `|` lines.
|
||||
///
|
||||
/// ```text
|
||||
/// <foo bar = "baz" />
|
||||
/// |-| |+-+|
|
||||
/// [-] [+-+]
|
||||
/// 5 7 13| |17
|
||||
/// |K |Q|
|
||||
/// |K |Q||
|
||||
/// | | ||
|
||||
/// | [-]|
|
||||
/// | 14 16
|
||||
/// | V |
|
||||
/// |-----------|
|
||||
/// [-----------]
|
||||
/// A
|
||||
/// ```
|
||||
///
|
||||
|
|
|
@ -164,7 +164,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
|
||||
QuickXmlEvent::End(ele) => Some({
|
||||
// </foo>
|
||||
// |----| name + '<' + '/' + '>'
|
||||
// [----] name + '<' + '/' + '>'
|
||||
let span = ctx.span_or_zz(prev_pos, ele.name().len() + 3);
|
||||
|
||||
ele.name()
|
||||
|
@ -187,7 +187,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
|
||||
QuickXmlEvent::Text(bytes) => Some({
|
||||
// <text>foo bar</text>
|
||||
// |-----|
|
||||
// [-----]
|
||||
let span = ctx.span_or_zz(prev_pos, bytes.len());
|
||||
|
||||
bytes
|
||||
|
@ -201,7 +201,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
// Comments are _not_ returned escaped.
|
||||
QuickXmlEvent::Comment(bytes) => Some({
|
||||
// <!-- foo -->
|
||||
// |----------| " foo " + "<!--" + "-->"
|
||||
// [----------] " foo " + "<!--" + "-->"
|
||||
let span = ctx.span_or_zz(prev_pos, bytes.len() + 7);
|
||||
|
||||
bytes
|
||||
|
@ -255,7 +255,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
// but it does not.
|
||||
if ver != b"1.0" {
|
||||
// <?xml version="X.Y"?>
|
||||
// |-|
|
||||
// [-]
|
||||
let ver_pos = (ver.as_ptr() as usize) - decl_ptr;
|
||||
let span = ctx.span_or_zz(ver_pos, ver.len());
|
||||
|
||||
|
@ -319,7 +319,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
Some(b'"' | b'\'') => {
|
||||
return Err({
|
||||
// <foo="bar" ...>
|
||||
// |-------|
|
||||
// [-------]
|
||||
let span = ctx.span_or_zz(pos + 1, len);
|
||||
|
||||
Error::InvalidQName(
|
||||
|
@ -343,10 +343,10 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
let noattr_add: usize = (!has_attrs).into();
|
||||
|
||||
// <tag ... />
|
||||
// |--| name + '<'
|
||||
// [--] name + '<'
|
||||
//
|
||||
// <tag>..</tag>
|
||||
// |---| name + '<' + '>'
|
||||
// [---] name + '<' + '>'
|
||||
let span = ctx.span_or_zz(pos, len + 1 + noattr_add);
|
||||
|
||||
if has_attrs {
|
||||
|
@ -361,7 +361,7 @@ impl<'s, B: BufRead, S: Escaper> XmlXirReader<'s, B, S> {
|
|||
|
||||
// Given this input, quick-xml ignores the bytes entirely:
|
||||
// <foo bar>
|
||||
// |--| missing `="value"`
|
||||
// [--] missing `="value"`
|
||||
//
|
||||
// The whitespace check is to handle input like this:
|
||||
// <foo />
|
||||
|
|
|
@ -96,7 +96,7 @@ macro_rules! new_sut {
|
|||
#[test]
|
||||
fn empty_node_without_prefix_or_attributes() {
|
||||
new_sut!(sut = "<empty-node />");
|
||||
// |---------| ||
|
||||
// [---------] []
|
||||
// 0 10
|
||||
// A B
|
||||
|
||||
|
@ -116,7 +116,7 @@ fn empty_node_without_prefix_or_attributes() {
|
|||
#[test]
|
||||
fn does_not_resolve_xmlns() {
|
||||
new_sut!(sut = r#"<no-ns xmlns="noresolve" />"#);
|
||||
// |----| |---| |-------| ||
|
||||
// [----] [---] [-------] []
|
||||
// 0 5 7 11 14 22 25
|
||||
// A B C D
|
||||
|
||||
|
@ -141,7 +141,7 @@ fn does_not_resolve_xmlns() {
|
|||
#[test]
|
||||
fn empty_node_with_prefix_without_attributes_unresolved() {
|
||||
new_sut!(sut = r#"<x:empty-node xmlns:x="noresolve" />"#);
|
||||
// |-----------| |-----| |-------| ||
|
||||
// [-----------] [-----] [-------] []
|
||||
// 0 12 14 20 23 31 34
|
||||
// A B C D
|
||||
|
||||
|
@ -167,7 +167,7 @@ fn empty_node_with_prefix_without_attributes_unresolved() {
|
|||
fn prefix_with_empty_local_name_invalid_qname() {
|
||||
// No local name (trailing colon).
|
||||
new_sut!(sut = r#"<x: xmlns:x="testns" />"#);
|
||||
// ||
|
||||
// []
|
||||
// 1
|
||||
// A
|
||||
|
||||
|
@ -187,7 +187,7 @@ fn prefix_with_empty_local_name_invalid_qname() {
|
|||
#[test]
|
||||
fn multiple_attrs_ordered() {
|
||||
new_sut!(sut = r#"<ele foo="a" bar="b" b:baz="c" />"#);
|
||||
// |--| |-| | |-| | |---| | ||
|
||||
// [--] [-] | [-] | [---] | []
|
||||
// 0 3 5 7 10 13 18 21 25 28 31
|
||||
// A B C D E F G H
|
||||
|
||||
|
@ -218,7 +218,7 @@ fn multiple_attrs_ordered() {
|
|||
#[test]
|
||||
fn empty_attr_value() {
|
||||
new_sut!(sut = r#"<ele empty="" />"#);
|
||||
// |--| |---| | ||
|
||||
// [--] [---] | []
|
||||
// 0 3 5 9 12 14
|
||||
// A B C D
|
||||
// /
|
||||
|
@ -247,7 +247,7 @@ fn empty_attr_value() {
|
|||
#[test]
|
||||
fn permits_duplicate_attrs() {
|
||||
new_sut!(sut = r#"<dup attr="a" attr="b" />"#);
|
||||
// |--| |--| | |--| | ||
|
||||
// [--] [--] | [--] | []
|
||||
// 0 3 5 8 11 14 17 20 23
|
||||
// A B C D E F
|
||||
|
||||
|
@ -274,7 +274,7 @@ fn permits_duplicate_attrs() {
|
|||
#[test]
|
||||
fn child_node_self_closing() {
|
||||
new_sut!(sut = r#"<root><child /></root>"#);
|
||||
// |----||----| |||-----|
|
||||
// [----][----] [][-----]
|
||||
// 0 5`6 11 13`15 21
|
||||
// A B C D
|
||||
// /
|
||||
|
@ -300,7 +300,7 @@ fn child_node_self_closing() {
|
|||
#[test]
|
||||
fn sibling_nodes() {
|
||||
new_sut!(sut = r#"<root><child /><child /></root>"#);
|
||||
// |----||----| |||----| |||-----|
|
||||
// [----][----] [][----] [][-----]
|
||||
// 0 5`6 11 13`15 20 22`24 30
|
||||
// A B C D E F
|
||||
|
||||
|
@ -327,7 +327,7 @@ fn sibling_nodes() {
|
|||
#[test]
|
||||
fn child_node_with_attrs() {
|
||||
new_sut!(sut = r#"<root><child foo="bar" /></root>"#);
|
||||
// |----||----| |-| |-| |||-----|
|
||||
// [----][----] [-] [-] [][-----]
|
||||
// 0 5`6 11 13 18 20 23`25 31
|
||||
// A B C D E F
|
||||
|
||||
|
@ -354,7 +354,7 @@ fn child_node_with_attrs() {
|
|||
#[test]
|
||||
fn child_text() {
|
||||
new_sut!(sut = r#"<text>foo bar</text>"#);
|
||||
// |----||-----||-----|
|
||||
// [----][-----][-----]
|
||||
// 0 5`6 12`13 19
|
||||
// A B C
|
||||
|
||||
|
@ -375,7 +375,7 @@ fn child_text() {
|
|||
#[test]
|
||||
fn mixed_child_content() {
|
||||
new_sut!(sut = r#"<text>foo<em>bar</em></text>"#);
|
||||
// |----||-||--||-||---||-----|
|
||||
// [----][-][--][-][---][-----]
|
||||
// 0 5`6 9 12`13`16 21 27
|
||||
// A B C D E F
|
||||
|
||||
|
@ -412,7 +412,7 @@ fn mixed_child_content_with_newlines() {
|
|||
"#
|
||||
);
|
||||
// \n<root>\n <child />\n</root>\n
|
||||
// |||----|| -||----| |||||-----|||
|
||||
// [][----][ -][----] [][][-----][]
|
||||
// 0 1 6`7 9`10 15 17| `20 26`27
|
||||
// 19
|
||||
// A B C D E F G H
|
||||
|
@ -444,7 +444,7 @@ fn mixed_child_content_with_newlines() {
|
|||
#[test]
|
||||
fn comment() {
|
||||
new_sut!(sut = r#"<!--root--><root><!--<child>--></root>"#);
|
||||
// |---------||----||------------||-----|
|
||||
// [---------][----][------------][-----]
|
||||
// 0 10`11 16`17 30`31 37
|
||||
// A B C D
|
||||
|
||||
|
@ -473,7 +473,7 @@ lines-->
|
|||
</mult>"#
|
||||
);
|
||||
// <mult><!--comment\non multiple\nlines-->\n</mult>
|
||||
// |----||----------- ------------ -------||||-----|
|
||||
// [----][----------- ------------ -------][][-----]
|
||||
// 0 5`6 37'38`39 45
|
||||
// A B C D
|
||||
|
||||
|
@ -497,7 +497,7 @@ lines-->
|
|||
#[test]
|
||||
fn permits_mismatched_tags() {
|
||||
new_sut!(sut = r#"<root><child /></mismatch>"#);
|
||||
// |----||----| |||---------|
|
||||
// [----][----] [][---------]
|
||||
// 0 5`6 11 13`15 25
|
||||
// A B C D
|
||||
|
||||
|
@ -585,7 +585,7 @@ fn attr_value_invalid_utf8() {
|
|||
#[test]
|
||||
fn valid_xml_decl_no_encoding() {
|
||||
new_sut!(sut = r#"<?xml version="1.0"?><root />"#);
|
||||
// |---| ||
|
||||
// [---] []
|
||||
// 21 25 27
|
||||
// A B
|
||||
// We do not yet emit a token for
|
||||
|
@ -621,7 +621,7 @@ fn valid_xml_decl_with_encoding_upper() {
|
|||
#[test]
|
||||
fn invalid_xml_decl_version() {
|
||||
new_sut!(sut = r#"<?xml version="1.1"?>"#);
|
||||
// |-|
|
||||
// [-]
|
||||
// 15 17
|
||||
|
||||
// Unlike above, we do actually calculate a span here.
|
||||
|
@ -637,7 +637,7 @@ fn invalid_xml_decl_version() {
|
|||
#[test]
|
||||
fn invalid_xml_encoding() {
|
||||
new_sut!(sut = r#"<?xml version="1.0" encoding="latin-1"?>"#);
|
||||
// |-----|
|
||||
// [-----]
|
||||
// 30 37
|
||||
|
||||
let span = DC.span(30, 7);
|
||||
|
@ -783,7 +783,7 @@ fn empty_element_qname_with_space_no_attrs() {
|
|||
#[test]
|
||||
fn empty_element_qname_with_attr() {
|
||||
new_sut!(sut = r#"<foo="bar">"#);
|
||||
// |-------|
|
||||
// [-------]
|
||||
// 1 10
|
||||
|
||||
let span = DC.span(1, 9);
|
||||
|
|
Loading…
Reference in New Issue