use super::functions::*;
use crate::tokens::Span;
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct FileRegistry {
entries: Vec<(FileId, String, String)>,
next_id: u32,
}
impl FileRegistry {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self {
entries: Vec::new(),
next_id: 1,
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn register(&mut self, path: impl Into<String>, source: impl Into<String>) -> FileId {
let id = FileId(self.next_id);
self.next_id += 1;
self.entries.push((id, path.into(), source.into()));
id
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn source(&self, id: FileId) -> Option<&str> {
self.entries
.iter()
.find(|(fid, _, _)| *fid == id)
.map(|(_, _, src)| src.as_str())
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn path(&self, id: FileId) -> Option<&str> {
self.entries
.iter()
.find(|(fid, _, _)| *fid == id)
.map(|(_, p, _)| p.as_str())
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.entries.len()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn extract(&self, fspan: &FileSpan) -> &str {
self.source(fspan.file)
.and_then(|src| src.get(fspan.span.start..fspan.span.end))
.unwrap_or("")
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct DiagnosticSpan {
pub span: Span,
pub severity: SpanSeverity,
#[allow(missing_docs)]
pub message: String,
}
impl DiagnosticSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(span: Span, severity: SpanSeverity, message: impl Into<String>) -> Self {
Self {
span,
severity,
message: message.into(),
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn error(span: Span, message: impl Into<String>) -> Self {
Self::new(span, SpanSeverity::Error, message)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn warning(span: Span, message: impl Into<String>) -> Self {
Self::new(span, SpanSeverity::Warning, message)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn info(span: Span, message: impl Into<String>) -> Self {
Self::new(span, SpanSeverity::Info, message)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn format_short(&self) -> String {
format!(
"[{}] {}: {}",
self.severity.label(),
span_short(&self.span),
self.message
)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct ProvenanceSpan {
pub span: Span,
pub origin: SpanOrigin,
}
impl ProvenanceSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(span: Span, origin: SpanOrigin) -> Self {
Self { span, origin }
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn user(span: Span) -> Self {
Self::new(span, SpanOrigin::UserSource)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn synthetic() -> Self {
Self::new(dummy_span(), SpanOrigin::Synthetic)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn macro_expanded(span: Span, macro_name: impl Into<String>) -> Self {
Self::new(
span,
SpanOrigin::MacroExpanded {
macro_name: macro_name.into(),
},
)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct SpanAnnotations {
items: Vec<AnnotatedSpan>,
}
impl SpanAnnotations {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn add(&mut self, a: AnnotatedSpan) {
self.items.push(a);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn annotate(&mut self, span: Span, text: impl Into<String>) {
self.items.push(AnnotatedSpan::new(span, text));
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn at_offset(&self, offset: usize) -> Vec<&AnnotatedSpan> {
self.items
.iter()
.filter(|a| span_contains(&a.span, offset))
.collect()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn with_tag<'a>(&'a self, tag: &str) -> Vec<&'a AnnotatedSpan> {
self.items
.iter()
.filter(|a| a.tag.as_deref() == Some(tag))
.collect()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.items.len()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn sort_by_start(&mut self) {
self.items.sort_by_key(|a| a.span.start);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn iter(&self) -> impl Iterator<Item = &AnnotatedSpan> {
self.items.iter()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn clear(&mut self) {
self.items.clear();
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn merge(&mut self, other: SpanAnnotations) {
self.items.extend(other.items);
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct SpanBuilder {
start: usize,
line: usize,
column: usize,
}
impl SpanBuilder {
#[allow(missing_docs)]
pub fn new(start: usize, line: usize, column: usize) -> Self {
Self {
start,
line,
column,
}
}
#[allow(missing_docs)]
pub fn finish(&self, end: usize) -> Span {
Span::new(self.start, end, self.line, self.column)
}
#[allow(missing_docs)]
pub fn start(&self) -> usize {
self.start
}
#[allow(missing_docs)]
pub fn pos(&self) -> SourcePos {
SourcePos::new(self.line, self.column)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct Utf16Span {
pub start_utf16: usize,
pub end_utf16: usize,
#[allow(missing_docs)]
pub line: usize,
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct SpanStats {
pub count: usize,
pub total_len: usize,
pub min_len: usize,
pub max_len: usize,
}
impl SpanStats {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn compute(spans: &[Span]) -> Self {
if spans.is_empty() {
return Self::default();
}
let count = spans.len();
let lengths: Vec<usize> = spans.iter().map(span_len).collect();
let total_len: usize = lengths.iter().sum();
let min_len = *lengths.iter().min().unwrap_or(&0);
let max_len = *lengths.iter().max().unwrap_or(&0);
Self {
count,
total_len,
min_len,
max_len,
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn avg_len(&self) -> usize {
self.total_len.checked_div(self.count).unwrap_or(0)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FileId(pub u32);
impl FileId {
#[allow(dead_code)]
#[allow(missing_docs)]
pub const UNKNOWN: FileId = FileId(0);
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(id: u32) -> Self {
FileId(id)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn raw(self) -> u32 {
self.0
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct SpanChain {
spans: Vec<Span>,
}
impl SpanChain {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn push(&mut self, span: Span) {
self.spans.push(span);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn total_span(&self) -> Option<Span> {
merge_spans(&self.spans)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.spans.len()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.spans.is_empty()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn iter(&self) -> impl Iterator<Item = &Span> {
self.spans.iter()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn first(&self) -> Option<&Span> {
self.spans.first()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn last(&self) -> Option<&Span> {
self.spans.last()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn clear(&mut self) {
self.spans.clear();
}
}
#[derive(Clone, Debug, Default)]
#[allow(missing_docs)]
pub struct SpanRegistry {
entries: std::collections::HashMap<String, Span>,
}
impl SpanRegistry {
#[allow(missing_docs)]
pub fn new() -> Self {
Self {
entries: std::collections::HashMap::new(),
}
}
#[allow(missing_docs)]
pub fn register(&mut self, key: impl Into<String>, span: Span) {
self.entries.insert(key.into(), span);
}
#[allow(missing_docs)]
pub fn get(&self, key: &str) -> Option<&Span> {
self.entries.get(key)
}
#[allow(missing_docs)]
pub fn contains(&self, key: &str) -> bool {
self.entries.contains_key(key)
}
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.entries.len()
}
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[allow(missing_docs)]
pub fn iter(&self) -> impl Iterator<Item = (&String, &Span)> {
self.entries.iter()
}
#[allow(missing_docs)]
pub fn remove(&mut self, key: &str) -> Option<Span> {
self.entries.remove(key)
}
#[allow(missing_docs)]
pub fn merge(&mut self, other: SpanRegistry) {
for (k, v) in other.entries {
self.entries.insert(k, v);
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct PrioritizedSpan {
pub span: Span,
pub priority: u32,
}
impl PrioritizedSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(span: Span, priority: u32) -> Self {
Self { span, priority }
}
}
#[derive(Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub struct LabeledSpan {
pub label: String,
pub span: Span,
}
impl LabeledSpan {
#[allow(missing_docs)]
pub fn new(label: impl Into<String>, span: Span) -> Self {
Self {
label: label.into(),
span,
}
}
#[allow(missing_docs)]
pub fn len(&self) -> usize {
span_len(&self.span)
}
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct SourceCursor<'a> {
source: &'a str,
pos: usize,
line: usize,
col: usize,
}
impl<'a> SourceCursor<'a> {
#[allow(missing_docs)]
pub fn new(source: &'a str) -> Self {
Self {
source,
pos: 0,
line: 1,
col: 1,
}
}
#[allow(missing_docs)]
pub fn pos(&self) -> usize {
self.pos
}
#[allow(missing_docs)]
pub fn source_pos(&self) -> SourcePos {
SourcePos::new(self.line, self.col)
}
#[allow(missing_docs)]
pub fn current_span(&self) -> Span {
Span::new(self.pos, self.pos, self.line, self.col)
}
#[allow(missing_docs)]
pub fn is_eof(&self) -> bool {
self.pos >= self.source.len()
}
#[allow(missing_docs)]
pub fn peek(&self) -> Option<char> {
self.source[self.pos..].chars().next()
}
#[allow(missing_docs)]
pub fn peek_ahead(&self, n: usize) -> Option<char> {
self.source[self.pos..].chars().nth(n)
}
#[allow(missing_docs)]
pub fn advance(&mut self) -> Option<char> {
let ch = self.source[self.pos..].chars().next()?;
self.pos += ch.len_utf8();
if ch == '\n' {
self.line += 1;
self.col = 1;
} else {
self.col += 1;
}
Some(ch)
}
#[allow(missing_docs)]
pub fn advance_while<F: Fn(char) -> bool>(&mut self, pred: F) -> &'a str {
let start = self.pos;
while let Some(ch) = self.peek() {
if pred(ch) {
self.advance();
} else {
break;
}
}
&self.source[start..self.pos]
}
#[allow(missing_docs)]
pub fn advance_bytes(&mut self, n: usize) {
for _ in 0..n {
self.advance();
}
}
#[allow(missing_docs)]
pub fn span_from(&self, start: usize, start_line: usize, start_col: usize) -> Span {
Span::new(start, self.pos, start_line, start_col)
}
#[allow(missing_docs)]
pub fn rest(&self) -> &'a str {
&self.source[self.pos..]
}
#[allow(missing_docs)]
pub fn consumed(&self) -> &'a str {
&self.source[..self.pos]
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct DiagnosticSet {
diagnostics: Vec<DiagnosticSpan>,
}
impl DiagnosticSet {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn add(&mut self, d: DiagnosticSpan) {
self.diagnostics.push(d);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn add_error(&mut self, span: Span, msg: impl Into<String>) {
self.add(DiagnosticSpan::error(span, msg));
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn add_warning(&mut self, span: Span, msg: impl Into<String>) {
self.add(DiagnosticSpan::warning(span, msg));
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn add_info(&mut self, span: Span, msg: impl Into<String>) {
self.add(DiagnosticSpan::info(span, msg));
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn count_severity(&self, sev: &SpanSeverity) -> usize {
self.diagnostics
.iter()
.filter(|d| &d.severity == sev)
.count()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.diagnostics.len()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.diagnostics.is_empty()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn has_errors(&self) -> bool {
self.diagnostics.iter().any(|d| d.severity.is_error())
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn errors(&self) -> Vec<&DiagnosticSpan> {
self.diagnostics
.iter()
.filter(|d| d.severity.is_error())
.collect()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn warnings(&self) -> Vec<&DiagnosticSpan> {
self.diagnostics
.iter()
.filter(|d| matches!(d.severity, SpanSeverity::Warning))
.collect()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn sort_by_position(&mut self) {
self.diagnostics.sort_by_key(|d| d.span.start);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn iter(&self) -> impl Iterator<Item = &DiagnosticSpan> {
self.diagnostics.iter()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn clear(&mut self) {
self.diagnostics.clear();
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn merge(&mut self, other: DiagnosticSet) {
self.diagnostics.extend(other.diagnostics);
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct SpanDiff {
pub old: Span,
pub new: Span,
#[allow(missing_docs)]
pub byte_delta: i64,
}
impl SpanDiff {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn compute(old: Span, new: Span) -> Self {
let byte_delta = new.end as i64 - old.end as i64;
Self {
old,
new,
byte_delta,
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn grew(&self) -> bool {
self.byte_delta > 0
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn shrank(&self) -> bool {
self.byte_delta < 0
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn unchanged(&self) -> bool {
self.byte_delta == 0
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct IncrementalSpanTracker {
spans: Vec<Span>,
edit_count: usize,
}
impl IncrementalSpanTracker {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn track(&mut self, span: Span) {
self.spans.push(span);
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn apply_edit(&mut self, edit_start: usize, delta: i64) {
shift_spans(&mut self.spans, edit_start, delta);
self.edit_count += 1;
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn spans(&self) -> &[Span] {
&self.spans
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn edit_count(&self) -> usize {
self.edit_count
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn reset(&mut self) {
self.spans.clear();
self.edit_count = 0;
}
}
#[derive(Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub struct Spanned<T> {
pub value: T,
pub span: Span,
}
impl<T> Spanned<T> {
#[allow(missing_docs)]
pub fn new(value: T, span: Span) -> Self {
Self { value, span }
}
#[allow(missing_docs)]
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Spanned<U> {
Spanned {
value: f(self.value),
span: self.span,
}
}
#[allow(clippy::should_implement_trait)]
#[allow(missing_docs)]
pub fn as_ref(&self) -> &T {
&self.value
}
#[allow(missing_docs)]
pub fn into_value(self) -> T {
self.value
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum SpanOrigin {
UserSource,
MacroExpanded { macro_name: String },
Elaborated,
Synthetic,
}
impl SpanOrigin {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_user_source(&self) -> bool {
matches!(self, SpanOrigin::UserSource)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_synthetic(&self) -> bool {
matches!(self, SpanOrigin::Synthetic)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn kind_str(&self) -> &'static str {
match self {
SpanOrigin::UserSource => "user",
SpanOrigin::MacroExpanded { .. } => "macro",
SpanOrigin::Elaborated => "elab",
SpanOrigin::Synthetic => "synthetic",
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub enum SpanSeverity {
Info,
Warning,
Error,
}
impl SpanSeverity {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_error(&self) -> bool {
matches!(self, SpanSeverity::Error)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn label(&self) -> &'static str {
match self {
SpanSeverity::Info => "info",
SpanSeverity::Warning => "warning",
SpanSeverity::Error => "error",
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub struct AnnotatedSpan {
pub span: Span,
pub annotation: String,
pub tag: Option<String>,
}
impl AnnotatedSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(span: Span, annotation: impl Into<String>) -> Self {
Self {
span,
annotation: annotation.into(),
tag: None,
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn with_tag(span: Span, annotation: impl Into<String>, tag: impl Into<String>) -> Self {
Self {
span,
annotation: annotation.into(),
tag: Some(tag.into()),
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
span_len(&self.span)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SpanRange {
pub start_idx: usize,
pub end_idx: usize,
}
impl SpanRange {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(start_idx: usize, end_idx: usize) -> Self {
Self { start_idx, end_idx }
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.end_idx.saturating_sub(self.start_idx)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.start_idx >= self.end_idx
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn contains(&self, idx: usize) -> bool {
idx >= self.start_idx && idx < self.end_idx
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct PaddedSpan {
pub inner: Span,
pub left_pad: usize,
pub right_pad: usize,
}
impl PaddedSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(inner: Span, left_pad: usize, right_pad: usize) -> Self {
Self {
inner,
left_pad,
right_pad,
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn expanded(&self, source_len: usize) -> Span {
let start = self.inner.start.saturating_sub(self.left_pad);
let end = (self.inner.end + self.right_pad).min(source_len);
Span::new(start, end, self.inner.line, self.inner.column)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, Default)]
pub struct SpanMap<V> {
entries: Vec<(usize, V)>,
}
impl<V> SpanMap<V> {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn insert(&mut self, offset: usize, value: V) {
self.entries.push((offset, value));
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn get(&self, offset: usize) -> Option<&V> {
self.entries
.iter()
.find(|(o, _)| *o == offset)
.map(|(_, v)| v)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
self.entries.len()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn iter(&self) -> impl Iterator<Item = &(usize, V)> {
self.entries.iter()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq)]
pub struct FileSpan {
pub file: FileId,
pub span: Span,
}
impl FileSpan {
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn new(file: FileId, span: Span) -> Self {
Self { file, span }
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn len(&self) -> usize {
span_len(&self.span)
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub fn merge_with(&self, other: &FileSpan) -> FileSpan {
assert_eq!(
self.file, other.file,
"cannot merge spans from different files"
);
FileSpan {
file: self.file,
span: self.span.merge(&other.span),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub struct SourcePos {
pub line: usize,
pub col: usize,
}
impl SourcePos {
#[allow(missing_docs)]
pub fn new(line: usize, col: usize) -> Self {
Self { line, col }
}
#[allow(missing_docs)]
pub fn start() -> Self {
Self { line: 1, col: 1 }
}
#[allow(missing_docs)]
pub fn advance_col(&self) -> Self {
Self {
line: self.line,
col: self.col + 1,
}
}
#[allow(missing_docs)]
pub fn advance_line(&self) -> Self {
Self {
line: self.line + 1,
col: 1,
}
}
#[allow(missing_docs)]
pub fn same_line(&self, other: &SourcePos) -> bool {
self.line == other.line
}
}