Update comments / docs for Spanned (#1549)

Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
Andrew Lamb 2024-11-30 08:08:55 -05:00 committed by GitHub
parent f4f112d7d6
commit 4ab3ab9147
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 306 additions and 91 deletions

View file

@ -422,13 +422,35 @@ impl fmt::Display for Whitespace {
}
/// Location in input string
///
/// # Create an "empty" (unknown) `Location`
/// ```
/// # use sqlparser::tokenizer::Location;
/// let location = Location::empty();
/// ```
///
/// # Create a `Location` from a line and column
/// ```
/// # use sqlparser::tokenizer::Location;
/// let location = Location::new(1, 1);
/// ```
///
/// # Create a `Location` from a pair
/// ```
/// # use sqlparser::tokenizer::Location;
/// let location = Location::from((1, 1));
/// ```
#[derive(Eq, PartialEq, Hash, Clone, Copy, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Location {
/// Line number, starting from 1
/// Line number, starting from 1.
///
/// Note: Line 0 is used for empty spans
pub line: u64,
/// Line column, starting from 1
/// Line column, starting from 1.
///
/// Note: Column 0 is used for empty spans
pub column: u64,
}
@ -448,10 +470,25 @@ impl fmt::Debug for Location {
}
impl Location {
pub fn of(line: u64, column: u64) -> Self {
/// Return an "empty" / unknown location
pub fn empty() -> Self {
Self { line: 0, column: 0 }
}
/// Create a new `Location` for a given line and column
pub fn new(line: u64, column: u64) -> Self {
Self { line, column }
}
/// Create a new location for a given line and column
///
/// Alias for [`Self::new`]
// TODO: remove / deprecate in favor of` `new` for consistency?
pub fn of(line: u64, column: u64) -> Self {
Self::new(line, column)
}
/// Combine self and `end` into a new `Span`
pub fn span_to(self, end: Self) -> Span {
Span { start: self, end }
}
@ -463,7 +500,9 @@ impl From<(u64, u64)> for Location {
}
}
/// A span of source code locations (start, end)
/// A span represents a linear portion of the input string (start, end)
///
/// See [Spanned](crate::ast::Spanned) for more information.
#[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@ -483,12 +522,15 @@ impl Span {
// We need a const instance for pattern matching
const EMPTY: Span = Self::empty();
/// Create a new span from a start and end [`Location`]
pub fn new(start: Location, end: Location) -> Span {
Span { start, end }
}
/// Returns an empty span (0, 0) -> (0, 0)
/// Returns an empty span `(0, 0) -> (0, 0)`
///
/// Empty spans represent no knowledge of source location
/// See [Spanned](crate::ast::Spanned) for more information.
pub const fn empty() -> Span {
Span {
start: Location { line: 0, column: 0 },
@ -498,6 +540,19 @@ impl Span {
/// Returns the smallest Span that contains both `self` and `other`
/// If either span is [Span::empty], the other span is returned
///
/// # Examples
/// ```
/// # use sqlparser::tokenizer::{Span, Location};
/// // line 1, column1 -> line 2, column 5
/// let span1 = Span::new(Location::new(1, 1), Location::new(2, 5));
/// // line 2, column 3 -> line 3, column 7
/// let span2 = Span::new(Location::new(2, 3), Location::new(3, 7));
/// // Union of the two is the min/max of the two spans
/// // line 1, column 1 -> line 3, column 7
/// let union = span1.union(&span2);
/// assert_eq!(union, Span::new(Location::new(1, 1), Location::new(3, 7)));
/// ```
pub fn union(&self, other: &Span) -> Span {
// If either span is empty, return the other
// this prevents propagating (0, 0) through the tree
@ -512,6 +567,7 @@ impl Span {
}
/// Same as [Span::union] for `Option<Span>`
///
/// If `other` is `None`, `self` is returned
pub fn union_opt(&self, other: &Option<Span>) -> Span {
match other {
@ -519,13 +575,57 @@ impl Span {
None => *self,
}
}
/// Return the [Span::union] of all spans in the iterator
///
/// If the iterator is empty, an empty span is returned
///
/// # Example
/// ```
/// # use sqlparser::tokenizer::{Span, Location};
/// let spans = vec![
/// Span::new(Location::new(1, 1), Location::new(2, 5)),
/// Span::new(Location::new(2, 3), Location::new(3, 7)),
/// Span::new(Location::new(3, 1), Location::new(4, 2)),
/// ];
/// // line 1, column 1 -> line 4, column 2
/// assert_eq!(
/// Span::union_iter(spans),
/// Span::new(Location::new(1, 1), Location::new(4, 2))
/// );
pub fn union_iter<I: IntoIterator<Item = Span>>(iter: I) -> Span {
iter.into_iter()
.reduce(|acc, item| acc.union(&item))
.unwrap_or(Span::empty())
}
}
/// Backwards compatibility struct for [`TokenWithSpan`]
#[deprecated(since = "0.53.0", note = "please use `TokenWithSpan` instead")]
pub type TokenWithLocation = TokenWithSpan;
/// A [Token] with [Location] attached to it
/// A [Token] with [Span] attached to it
///
/// This is used to track the location of a token in the input string
///
/// # Examples
/// ```
/// # use sqlparser::tokenizer::{Location, Span, Token, TokenWithSpan};
/// // commas @ line 1, column 10
/// let tok1 = TokenWithSpan::new(
/// Token::Comma,
/// Span::new(Location::new(1, 10), Location::new(1, 11)),
/// );
/// assert_eq!(tok1, Token::Comma); // can compare the token
///
/// // commas @ line 2, column 20
/// let tok2 = TokenWithSpan::new(
/// Token::Comma,
/// Span::new(Location::new(2, 20), Location::new(2, 21)),
/// );
/// // same token but different locations are not equal
/// assert_ne!(tok1, tok2);
/// ```
#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@ -535,16 +635,24 @@ pub struct TokenWithSpan {
}
impl TokenWithSpan {
pub fn new(token: Token, span: Span) -> TokenWithSpan {
TokenWithSpan { token, span }
/// Create a new [`TokenWithSpan`] from a [`Token`] and a [`Span`]
pub fn new(token: Token, span: Span) -> Self {
Self { token, span }
}
pub fn wrap(token: Token) -> TokenWithSpan {
TokenWithSpan::new(token, Span::empty())
/// Wrap a token with an empty span
pub fn wrap(token: Token) -> Self {
Self::new(token, Span::empty())
}
pub fn at(token: Token, start: Location, end: Location) -> TokenWithSpan {
TokenWithSpan::new(token, Span::new(start, end))
/// Wrap a token with a location from `start` to `end`
pub fn at(token: Token, start: Location, end: Location) -> Self {
Self::new(token, Span::new(start, end))
}
/// Return an EOF token with no location
pub fn new_eof() -> Self {
Self::wrap(Token::EOF)
}
}