use nom_locate::LocatedSpan;
use crate::ast::Span;
pub type Input<'a> = LocatedSpan<&'a str>;
pub fn input(source: &str) -> Input<'_> {
Input::new(source)
}
pub fn span_between(before: &Input<'_>, after: &Input<'_>) -> Span {
let start_byte = before.location_offset();
let end_byte = after.location_offset();
Span::new(
start_byte,
end_byte,
before.location_line(),
before.get_column() as u32,
after.location_line(),
after.get_column() as u32,
)
}
pub fn span_at(cursor: &Input<'_>) -> Span {
let byte = cursor.location_offset();
let line = cursor.location_line();
let col = cursor.get_column() as u32;
Span::new(byte, byte, line, col, line, col)
}
pub fn span_for_line(start: &Input<'_>, text: &Input<'_>) -> Span {
let start_byte = start.location_offset();
let end_byte = text.location_offset() + text.fragment().len();
let line = start.location_line();
let start_col = start.get_column() as u32;
let end_col = start_col + text.fragment().len() as u32;
Span::new(start_byte, end_byte, line, start_col, line, end_col)
}
#[cfg(test)]
mod tests {
use super::*;
use super::super::util::physical_line;
#[test]
fn span_for_line_ascii_byte_columns() {
let s = Input::new("hello world\nrest");
let (_rest, text) = physical_line(s).unwrap();
let span = span_for_line(&s, &text);
assert_eq!(span.start_byte, 0);
assert_eq!(span.end_byte, 11);
assert_eq!(span.start_line, 1);
assert_eq!(span.end_line, 1);
assert_eq!(span.start_column, 1);
assert_eq!(span.end_column, 12);
}
#[test]
fn span_for_line_utf8_uses_byte_columns() {
let s = Input::new("αβγ\nrest");
let (_rest, text) = physical_line(s).unwrap();
let span = span_for_line(&s, &text);
assert_eq!(span.end_byte - span.start_byte, 6);
assert_eq!(span.end_column - span.start_column, 6);
}
#[test]
fn span_for_line_stops_before_newline() {
let s = Input::new("first\nsecond\n");
let (_rest, text) = physical_line(s).unwrap();
let span = span_for_line(&s, &text);
assert_eq!(span.end_byte, 5);
assert_eq!(span.start_line, span.end_line);
}
}