Skip to main content

oxilean_parse/sourcemap/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::tokens::Span;
6
7/// A cache for source map lookups.
8#[allow(dead_code)]
9#[allow(missing_docs)]
10pub struct SourceMapCache {
11    /// Cached lookups: (line, col) -> (orig_line, orig_col)
12    pub cache: std::collections::HashMap<(usize, usize), (usize, usize)>,
13}
14impl SourceMapCache {
15    /// Create a new empty cache.
16    #[allow(dead_code)]
17    pub fn new() -> Self {
18        SourceMapCache {
19            cache: std::collections::HashMap::new(),
20        }
21    }
22    /// Insert a cached mapping.
23    #[allow(dead_code)]
24    pub fn insert(&mut self, gen_line: usize, gen_col: usize, orig_line: usize, orig_col: usize) {
25        self.cache
26            .insert((gen_line, gen_col), (orig_line, orig_col));
27    }
28    /// Look up a cached mapping.
29    #[allow(dead_code)]
30    pub fn lookup(&self, gen_line: usize, gen_col: usize) -> Option<(usize, usize)> {
31        self.cache.get(&(gen_line, gen_col)).copied()
32    }
33    /// Returns the number of cached entries.
34    #[allow(dead_code)]
35    pub fn len(&self) -> usize {
36        self.cache.len()
37    }
38    /// Returns true if empty.
39    #[allow(dead_code)]
40    pub fn is_empty(&self) -> bool {
41        self.cache.is_empty()
42    }
43}
44/// A source position with both byte offset and line/column information.
45#[allow(dead_code)]
46#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
47pub struct SourcePosition {
48    /// Byte offset from the start of the file.
49    pub offset: usize,
50    /// 1-based line number.
51    pub line: usize,
52    /// 1-based column number.
53    pub column: usize,
54}
55#[allow(dead_code)]
56impl SourcePosition {
57    /// Create a source position.
58    pub fn new(offset: usize, line: usize, column: usize) -> Self {
59        Self {
60            offset,
61            line,
62            column,
63        }
64    }
65    /// The origin position (offset 0, line 1, col 1).
66    pub fn origin() -> Self {
67        Self {
68            offset: 0,
69            line: 1,
70            column: 1,
71        }
72    }
73    /// Advance by one character (non-newline).
74    pub fn advance_col(self, bytes: usize) -> Self {
75        Self {
76            offset: self.offset + bytes,
77            column: self.column + 1,
78            ..self
79        }
80    }
81    /// Advance to the next line.
82    pub fn advance_line(self, bytes: usize) -> Self {
83        Self {
84            offset: self.offset + bytes,
85            line: self.line + 1,
86            column: 1,
87        }
88    }
89    /// Check if this position is before another.
90    pub fn is_before(&self, other: &SourcePosition) -> bool {
91        self.offset < other.offset
92    }
93    /// Check if this position is after another.
94    pub fn is_after(&self, other: &SourcePosition) -> bool {
95        self.offset > other.offset
96    }
97}
98/// Severity of an IDE diagnostic.
99#[allow(dead_code)]
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
101pub enum DiagnosticSeverity {
102    /// A hint (informational).
103    Hint,
104    /// An informational message.
105    Information,
106    /// A warning.
107    Warning,
108    /// An error.
109    Error,
110}
111/// A semantic token for IDE highlighting.
112#[derive(Clone, Debug, PartialEq)]
113pub struct SemanticToken {
114    /// The source span of this token.
115    pub span: Span,
116    /// The token type.
117    pub token_type: SemanticTokenType,
118    /// Additional modifiers.
119    pub modifiers: Vec<SemanticModifier>,
120}
121impl SemanticToken {
122    /// Create a new semantic token without modifiers.
123    #[allow(dead_code)]
124    pub fn new(span: Span, token_type: SemanticTokenType) -> Self {
125        Self {
126            span,
127            token_type,
128            modifiers: Vec::new(),
129        }
130    }
131    /// Create a semantic token with modifiers.
132    #[allow(dead_code)]
133    pub fn with_modifiers(
134        span: Span,
135        token_type: SemanticTokenType,
136        modifiers: Vec<SemanticModifier>,
137    ) -> Self {
138        Self {
139            span,
140            token_type,
141            modifiers,
142        }
143    }
144}
145/// A batch of source map entries.
146#[allow(dead_code)]
147#[allow(missing_docs)]
148#[derive(Debug, Default)]
149pub struct SourceMapBatch {
150    /// All entries
151    pub entries: Vec<RangeTransform>,
152}
153impl SourceMapBatch {
154    /// Create a new batch.
155    #[allow(dead_code)]
156    pub fn new() -> Self {
157        SourceMapBatch {
158            entries: Vec::new(),
159        }
160    }
161    /// Add an entry.
162    #[allow(dead_code)]
163    pub fn add(&mut self, e: RangeTransform) {
164        self.entries.push(e);
165    }
166    /// Returns the total coverage (sum of original ranges).
167    #[allow(dead_code)]
168    pub fn total_coverage(&self) -> usize {
169        self.entries.iter().map(|e| e.orig_len()).sum()
170    }
171    /// Returns the number of length-preserving entries.
172    #[allow(dead_code)]
173    pub fn length_preserving_count(&self) -> usize {
174        self.entries
175            .iter()
176            .filter(|e| e.is_length_preserving())
177            .count()
178    }
179}
180/// A symbol in the document symbol outline (for IDE sidebar).
181#[allow(dead_code)]
182#[derive(Debug, Clone, PartialEq)]
183pub struct DocumentSymbol {
184    /// The name of the symbol.
185    pub name: String,
186    /// The kind of symbol.
187    pub kind: SymbolKind,
188    /// The span of the entire declaration.
189    pub full_span: Span,
190    /// The span of just the name.
191    pub name_span: Span,
192    /// Child symbols (e.g. structure fields, inductive constructors).
193    pub children: Vec<DocumentSymbol>,
194}
195#[allow(dead_code)]
196impl DocumentSymbol {
197    /// Create a new document symbol.
198    pub fn new(name: String, kind: SymbolKind, full_span: Span, name_span: Span) -> Self {
199        Self {
200            name,
201            kind,
202            full_span,
203            name_span,
204            children: Vec::new(),
205        }
206    }
207    /// Add a child symbol.
208    pub fn add_child(&mut self, child: DocumentSymbol) {
209        self.children.push(child);
210    }
211    /// Whether this symbol has children.
212    pub fn has_children(&self) -> bool {
213        !self.children.is_empty()
214    }
215    /// Recursively find a symbol by name.
216    pub fn find_by_name(&self, name: &str) -> Option<&DocumentSymbol> {
217        if self.name == name {
218            return Some(self);
219        }
220        for child in &self.children {
221            if let Some(found) = child.find_by_name(name) {
222                return Some(found);
223            }
224        }
225        None
226    }
227    /// Flatten into a list (self first, then children recursively).
228    pub fn flatten(&self) -> Vec<&DocumentSymbol> {
229        let mut result = vec![self];
230        for child in &self.children {
231            result.extend(child.flatten());
232        }
233        result
234    }
235}
236/// A labeled region of source text (e.g. a function body, an import block).
237#[allow(dead_code)]
238#[derive(Debug, Clone, PartialEq)]
239pub struct SourceRegion {
240    /// Label for the region.
241    pub label: String,
242    /// Span of the region.
243    pub span: Span,
244    /// Optional metadata string.
245    pub meta: Option<String>,
246}
247#[allow(dead_code)]
248impl SourceRegion {
249    /// Create a source region.
250    pub fn new(label: impl Into<String>, span: Span) -> Self {
251        Self {
252            label: label.into(),
253            span,
254            meta: None,
255        }
256    }
257    /// Create a source region with metadata.
258    pub fn with_meta(label: impl Into<String>, span: Span, meta: impl Into<String>) -> Self {
259        Self {
260            label: label.into(),
261            span,
262            meta: Some(meta.into()),
263        }
264    }
265    /// Whether this region contains a byte offset.
266    pub fn contains_offset(&self, offset: usize) -> bool {
267        offset >= self.span.start && offset < self.span.end
268    }
269    /// The byte length of the region.
270    pub fn byte_len(&self) -> usize {
271        self.span.end.saturating_sub(self.span.start)
272    }
273}
274/// Modifier flags for semantic tokens.
275#[derive(Clone, Debug, PartialEq, Eq)]
276pub enum SemanticModifier {
277    /// This token is a definition site.
278    Definition,
279    /// This token is a declaration.
280    Declaration,
281    /// This token is deprecated.
282    Deprecated,
283    /// This token is inside documentation.
284    Documentation,
285}
286/// Semantic token type for syntax highlighting.
287#[derive(Clone, Debug, PartialEq, Eq)]
288pub enum SemanticTokenType {
289    /// A keyword (e.g. `def`, `theorem`, `if`).
290    Keyword,
291    /// A variable reference.
292    Variable,
293    /// A function name.
294    Function,
295    /// A type name.
296    Type,
297    /// A constructor name.
298    Constructor,
299    /// An operator symbol.
300    Operator,
301    /// A number literal.
302    Number,
303    /// A string literal.
304    StringLit,
305    /// A comment.
306    Comment,
307    /// A tactic name.
308    Tactic,
309    /// A namespace name.
310    Namespace,
311}
312/// A single entry in the source map.
313#[derive(Clone, Debug, PartialEq)]
314pub struct SourceEntry {
315    /// Source span for this entry.
316    pub span: Span,
317    /// What kind of entry this is.
318    pub kind: EntryKind,
319    /// Optional name associated with this entry.
320    pub name: Option<String>,
321    /// Optional type information as a display string.
322    pub ty_info: Option<String>,
323}
324impl SourceEntry {
325    /// Create a new source entry.
326    #[allow(dead_code)]
327    pub fn new(span: Span, kind: EntryKind) -> Self {
328        Self {
329            span,
330            kind,
331            name: None,
332            ty_info: None,
333        }
334    }
335    /// Create a source entry with a name.
336    #[allow(dead_code)]
337    pub fn with_name(span: Span, kind: EntryKind, name: &str) -> Self {
338        Self {
339            span,
340            kind,
341            name: Some(name.to_string()),
342            ty_info: None,
343        }
344    }
345    /// Create a source entry with name and type info.
346    #[allow(dead_code)]
347    pub fn with_name_and_type(span: Span, kind: EntryKind, name: &str, ty: &str) -> Self {
348        Self {
349            span,
350            kind,
351            name: Some(name.to_string()),
352            ty_info: Some(ty.to_string()),
353        }
354    }
355    /// Check whether a byte offset falls within this entry's span.
356    #[allow(dead_code)]
357    pub fn contains_offset(&self, offset: usize) -> bool {
358        offset >= self.span.start && offset < self.span.end
359    }
360}
361/// The kind of source entry.
362#[derive(Clone, Debug, PartialEq, Eq)]
363pub enum EntryKind {
364    /// A definition site (def, theorem, axiom, etc.)
365    Definition,
366    /// A reference to a previously defined name.
367    Reference,
368    /// A type annotation expression.
369    TypeAnnotation,
370    /// A binder (lambda, forall, let parameter).
371    Binder,
372    /// A constructor of an inductive type.
373    Constructor,
374    /// A pattern in a match expression.
375    Pattern,
376    /// A tactic invocation.
377    Tactic,
378    /// A keyword token.
379    Keyword,
380    /// A literal value (number, string, char).
381    Literal,
382    /// A comment (line or block).
383    Comment,
384    /// A documentation comment.
385    DocComment,
386    /// An operator symbol.
387    Operator,
388}
389/// A diagnostic message with a source location.
390#[allow(dead_code)]
391#[derive(Debug, Clone, PartialEq)]
392pub struct SourceDiagnostic {
393    /// Span of the diagnostic.
394    pub span: Span,
395    /// Severity level.
396    pub severity: DiagnosticSeverity,
397    /// The diagnostic message.
398    pub message: String,
399    /// Optional code (e.g. "E001").
400    pub code: Option<String>,
401    /// Optional related spans (e.g. for "note" entries).
402    pub related: Vec<(Span, String)>,
403}
404#[allow(dead_code)]
405impl SourceDiagnostic {
406    /// Create a new diagnostic.
407    pub fn new(span: Span, severity: DiagnosticSeverity, message: impl Into<String>) -> Self {
408        Self {
409            span,
410            severity,
411            message: message.into(),
412            code: None,
413            related: Vec::new(),
414        }
415    }
416    /// Create an error diagnostic.
417    pub fn error(span: Span, message: impl Into<String>) -> Self {
418        Self::new(span, DiagnosticSeverity::Error, message)
419    }
420    /// Create a warning diagnostic.
421    pub fn warning(span: Span, message: impl Into<String>) -> Self {
422        Self::new(span, DiagnosticSeverity::Warning, message)
423    }
424    /// Create an informational diagnostic.
425    pub fn info(span: Span, message: impl Into<String>) -> Self {
426        Self::new(span, DiagnosticSeverity::Information, message)
427    }
428    /// Set the error code.
429    pub fn with_code(mut self, code: impl Into<String>) -> Self {
430        self.code = Some(code.into());
431        self
432    }
433    /// Add a related location.
434    pub fn with_related(mut self, span: Span, message: impl Into<String>) -> Self {
435        self.related.push((span, message.into()));
436        self
437    }
438    /// Whether this is an error.
439    pub fn is_error(&self) -> bool {
440        self.severity == DiagnosticSeverity::Error
441    }
442    /// Whether this is a warning.
443    pub fn is_warning(&self) -> bool {
444        self.severity == DiagnosticSeverity::Warning
445    }
446}
447/// The result of a go-to-definition lookup.
448#[allow(dead_code)]
449#[derive(Debug, Clone, PartialEq)]
450pub struct GoToDefinitionResult {
451    /// Name that was queried.
452    pub name: String,
453    /// The span(s) of the definition site.
454    pub definition_spans: Vec<Span>,
455    /// Whether the definition is in the same file.
456    pub is_local: bool,
457}
458#[allow(dead_code)]
459impl GoToDefinitionResult {
460    /// Create a result.
461    pub fn new(name: String, spans: Vec<Span>, is_local: bool) -> Self {
462        Self {
463            name,
464            definition_spans: spans,
465            is_local,
466        }
467    }
468    /// Whether the definition was found.
469    pub fn found(&self) -> bool {
470        !self.definition_spans.is_empty()
471    }
472    /// The primary (first) definition span.
473    pub fn primary_span(&self) -> Option<&Span> {
474        self.definition_spans.first()
475    }
476}
477/// Statistics about a source map.
478#[allow(dead_code)]
479#[derive(Debug, Clone, Default)]
480pub struct SourceMapStats {
481    /// Total number of entries.
482    pub total_entries: usize,
483    /// Number of definition entries.
484    pub definitions: usize,
485    /// Number of reference entries.
486    pub references: usize,
487    /// Number of tactic entries.
488    pub tactics: usize,
489    /// Number of comment entries.
490    pub comments: usize,
491    /// Number of operator entries.
492    pub operators: usize,
493}
494#[allow(dead_code)]
495impl SourceMapStats {
496    /// Compute stats from a list of source entries.
497    pub fn from_entries(entries: &[SourceEntry]) -> Self {
498        let mut definitions = 0usize;
499        let mut references = 0usize;
500        let mut tactics = 0usize;
501        let mut comments = 0usize;
502        let mut operators = 0usize;
503        for entry in entries {
504            match entry.kind {
505                EntryKind::Definition => definitions += 1,
506                EntryKind::Reference => references += 1,
507                EntryKind::Tactic => tactics += 1,
508                EntryKind::Comment | EntryKind::DocComment => comments += 1,
509                EntryKind::Operator => operators += 1,
510                _ => {}
511            }
512        }
513        Self {
514            total_entries: entries.len(),
515            definitions,
516            references,
517            tactics,
518            comments,
519            operators,
520        }
521    }
522}
523/// A combined source index with definitions, references, and symbols.
524#[allow(dead_code)]
525#[derive(Debug, Clone, Default)]
526pub struct SourceIndex {
527    /// Definition index.
528    pub definitions: DefinitionIndex,
529    /// Reference index.
530    pub references: ReferenceIndex,
531    /// Document symbols.
532    pub symbols: Vec<DocumentSymbol>,
533    /// Source regions.
534    pub regions: Vec<SourceRegion>,
535}
536#[allow(dead_code)]
537impl SourceIndex {
538    /// Create an empty source index.
539    pub fn new() -> Self {
540        Self::default()
541    }
542    /// Register a definition.
543    pub fn register_definition(&mut self, name: impl Into<String>, span: Span) {
544        self.definitions.register(name, span);
545    }
546    /// Record a reference.
547    pub fn record_reference(&mut self, name: impl Into<String>, span: Span) {
548        self.references.record(name, span);
549    }
550    /// Add a document symbol.
551    pub fn add_symbol(&mut self, symbol: DocumentSymbol) {
552        self.symbols.push(symbol);
553    }
554    /// Add a source region.
555    pub fn add_region(&mut self, region: SourceRegion) {
556        self.regions.push(region);
557    }
558    /// Find the symbol at a given byte offset.
559    pub fn symbol_at_offset(&self, offset: usize) -> Option<&DocumentSymbol> {
560        self.symbols
561            .iter()
562            .find(|&sym| sym.full_span.start <= offset && offset < sym.full_span.end)
563    }
564    /// Get all definition spans for a name.
565    pub fn definition_spans(&self, name: &str) -> &[Span] {
566        self.definitions.lookup(name)
567    }
568    /// Get all use-site spans for a name.
569    pub fn reference_spans(&self, name: &str) -> &[Span] {
570        self.references.uses_of(name)
571    }
572    /// Symbols that are top-level definitions (not inside a namespace).
573    pub fn top_level_symbols(&self) -> &[DocumentSymbol] {
574        &self.symbols
575    }
576}
577/// An index mapping definition names to their source spans.
578#[allow(dead_code)]
579#[derive(Debug, Clone, Default)]
580pub struct DefinitionIndex {
581    entries: std::collections::HashMap<String, Vec<Span>>,
582}
583#[allow(dead_code)]
584impl DefinitionIndex {
585    /// Create an empty definition index.
586    pub fn new() -> Self {
587        Self {
588            entries: std::collections::HashMap::new(),
589        }
590    }
591    /// Register a definition name with its span.
592    pub fn register(&mut self, name: impl Into<String>, span: Span) {
593        self.entries.entry(name.into()).or_default().push(span);
594    }
595    /// Look up all spans for a given name.
596    pub fn lookup(&self, name: &str) -> &[Span] {
597        self.entries.get(name).map(|v| v.as_slice()).unwrap_or(&[])
598    }
599    /// Check if a name is defined.
600    pub fn contains(&self, name: &str) -> bool {
601        self.entries.contains_key(name)
602    }
603    /// All defined names.
604    pub fn names(&self) -> Vec<&str> {
605        self.entries.keys().map(|s| s.as_str()).collect()
606    }
607    /// Number of unique definition names.
608    pub fn len(&self) -> usize {
609        self.entries.len()
610    }
611    /// Whether the index is empty.
612    pub fn is_empty(&self) -> bool {
613        self.entries.is_empty()
614    }
615    /// Remove all definitions for a name.
616    pub fn remove(&mut self, name: &str) -> Vec<Span> {
617        self.entries.remove(name).unwrap_or_default()
618    }
619    /// Merge another index into this one.
620    pub fn merge(&mut self, other: DefinitionIndex) {
621        for (name, spans) in other.entries {
622            self.entries.entry(name).or_default().extend(spans);
623        }
624    }
625}
626/// A bidirectional position mapper between two source representations.
627#[allow(dead_code)]
628#[allow(missing_docs)]
629pub struct BidiMapper {
630    /// Forward mappings (original offset -> generated offset)
631    pub forward: Vec<(usize, usize)>,
632    /// Backward mappings (generated offset -> original offset)
633    pub backward: Vec<(usize, usize)>,
634}
635impl BidiMapper {
636    /// Create a new empty mapper.
637    #[allow(dead_code)]
638    pub fn new() -> Self {
639        BidiMapper {
640            forward: Vec::new(),
641            backward: Vec::new(),
642        }
643    }
644    /// Add a mapping.
645    #[allow(dead_code)]
646    pub fn add(&mut self, orig: usize, gen: usize) {
647        self.forward.push((orig, gen));
648        self.backward.push((gen, orig));
649    }
650    /// Look up the generated offset for an original offset.
651    #[allow(dead_code)]
652    pub fn to_gen(&self, orig: usize) -> Option<usize> {
653        self.forward
654            .iter()
655            .rev()
656            .find(|(o, _)| *o <= orig)
657            .map(|(_, g)| *g)
658    }
659    /// Look up the original offset for a generated offset.
660    #[allow(dead_code)]
661    pub fn to_orig(&self, gen: usize) -> Option<usize> {
662        self.backward
663            .iter()
664            .rev()
665            .find(|(g, _)| *g <= gen)
666            .map(|(_, o)| *o)
667    }
668    /// Returns the number of mappings.
669    #[allow(dead_code)]
670    pub fn len(&self) -> usize {
671        self.forward.len()
672    }
673    /// Returns true if empty.
674    #[allow(dead_code)]
675    pub fn is_empty(&self) -> bool {
676        self.forward.is_empty()
677    }
678}
679/// A source range transformation record.
680#[allow(dead_code)]
681#[allow(missing_docs)]
682#[derive(Debug, Clone)]
683pub struct RangeTransform {
684    /// Original start offset
685    pub orig_start: usize,
686    /// Original end offset
687    pub orig_end: usize,
688    /// Generated start offset
689    pub gen_start: usize,
690    /// Generated end offset
691    pub gen_end: usize,
692}
693impl RangeTransform {
694    /// Create a new range transform.
695    #[allow(dead_code)]
696    pub fn new(orig_start: usize, orig_end: usize, gen_start: usize, gen_end: usize) -> Self {
697        RangeTransform {
698            orig_start,
699            orig_end,
700            gen_start,
701            gen_end,
702        }
703    }
704    /// Length of the original range.
705    #[allow(dead_code)]
706    pub fn orig_len(&self) -> usize {
707        self.orig_end.saturating_sub(self.orig_start)
708    }
709    /// Length of the generated range.
710    #[allow(dead_code)]
711    pub fn gen_len(&self) -> usize {
712        self.gen_end.saturating_sub(self.gen_start)
713    }
714    /// Whether the mapping is length-preserving.
715    #[allow(dead_code)]
716    pub fn is_length_preserving(&self) -> bool {
717        self.orig_len() == self.gen_len()
718    }
719}
720/// A sorted source map for binary search lookups.
721#[allow(dead_code)]
722#[allow(missing_docs)]
723pub struct SortedSourceMap {
724    /// Sorted (gen_offset, orig_offset) pairs
725    pub pairs: Vec<(usize, usize)>,
726}
727impl SortedSourceMap {
728    /// Create a new empty sorted source map.
729    #[allow(dead_code)]
730    pub fn new() -> Self {
731        SortedSourceMap { pairs: Vec::new() }
732    }
733    /// Add a mapping.
734    #[allow(dead_code)]
735    pub fn add(&mut self, gen: usize, orig: usize) {
736        self.pairs.push((gen, orig));
737        self.pairs.sort_by_key(|(g, _)| *g);
738    }
739    /// Look up the original offset for a generated offset.
740    #[allow(dead_code)]
741    pub fn lookup(&self, gen: usize) -> Option<usize> {
742        let idx = self.pairs.partition_point(|(g, _)| *g <= gen);
743        if idx == 0 {
744            return None;
745        }
746        Some(self.pairs[idx - 1].1)
747    }
748    /// Returns the number of pairs.
749    #[allow(dead_code)]
750    pub fn len(&self) -> usize {
751        self.pairs.len()
752    }
753    /// Returns true if empty.
754    #[allow(dead_code)]
755    pub fn is_empty(&self) -> bool {
756        self.pairs.is_empty()
757    }
758}
759/// A source map difference: what changed between two maps.
760#[allow(dead_code)]
761#[allow(missing_docs)]
762#[derive(Debug, Clone)]
763pub struct SourceMapDiff {
764    /// Number of added segments
765    pub added: usize,
766    /// Number of removed segments
767    pub removed: usize,
768    /// Number of modified segments
769    pub modified: usize,
770}
771/// Source map: the main data structure mapping source positions to AST nodes.
772///
773/// Supports IDE features such as hover, go-to-definition, semantic
774/// highlighting, and reference lookup.
775pub struct SourceMap {
776    /// All entries in the source map, sorted by span start.
777    entries: Vec<SourceEntry>,
778    /// Byte offset of each line start (index 0 = line 1).
779    line_offsets: Vec<usize>,
780    /// The original source text.
781    source: String,
782    /// Pre-computed semantic tokens.
783    semantic_tokens: Vec<SemanticToken>,
784}
785impl SourceMap {
786    /// Create a new, empty source map for the given source text.
787    #[allow(dead_code)]
788    pub fn new(source: &str) -> Self {
789        let line_offsets = Self::compute_line_offsets(source);
790        Self {
791            entries: Vec::new(),
792            line_offsets,
793            source: source.to_string(),
794            semantic_tokens: Vec::new(),
795        }
796    }
797    /// Get the original source text.
798    #[allow(dead_code)]
799    pub fn source(&self) -> &str {
800        &self.source
801    }
802    /// Get all entries.
803    #[allow(dead_code)]
804    pub fn entries(&self) -> &[SourceEntry] {
805        &self.entries
806    }
807    /// Return the total number of lines in the source.
808    #[allow(dead_code)]
809    pub fn line_count(&self) -> usize {
810        self.line_offsets.len()
811    }
812    /// Convert a byte offset to a (line, column) pair.
813    ///
814    /// Lines and columns are 1-indexed, matching the convention in `Span`.
815    #[allow(dead_code)]
816    pub fn offset_to_position(&self, offset: usize) -> (usize, usize) {
817        let line_idx = match self.line_offsets.binary_search(&offset) {
818            Ok(idx) => idx,
819            Err(idx) => {
820                if idx == 0 {
821                    0
822                } else {
823                    idx - 1
824                }
825            }
826        };
827        let line_start = self.line_offsets[line_idx];
828        let col = offset.saturating_sub(line_start);
829        (line_idx + 1, col + 1)
830    }
831    /// Convert a (line, column) pair to a byte offset.
832    ///
833    /// Lines and columns are 1-indexed.
834    #[allow(dead_code)]
835    pub fn position_to_offset(&self, line: usize, col: usize) -> usize {
836        if line == 0 || line > self.line_offsets.len() {
837            return self.source.len();
838        }
839        let line_start = self.line_offsets[line - 1];
840        let col_offset = if col > 0 { col - 1 } else { 0 };
841        let max_col = self.line_length(line);
842        line_start + col_offset.min(max_col)
843    }
844    /// Get the text content of a specific line (1-indexed).
845    #[allow(dead_code)]
846    pub fn line_content(&self, line: usize) -> &str {
847        if line == 0 || line > self.line_offsets.len() {
848            return "";
849        }
850        let start = self.line_offsets[line - 1];
851        let end = if line < self.line_offsets.len() {
852            self.line_offsets[line]
853        } else {
854            self.source.len()
855        };
856        let text = &self.source[start..end];
857        text.trim_end_matches('\n').trim_end_matches('\r')
858    }
859    /// Get the length (in bytes) of a specific line (1-indexed), excluding newline.
860    #[allow(dead_code)]
861    fn line_length(&self, line: usize) -> usize {
862        self.line_content(line).len()
863    }
864    /// Find the entry at a given (line, column) position (1-indexed).
865    #[allow(dead_code)]
866    pub fn entry_at(&self, line: usize, col: usize) -> Option<&SourceEntry> {
867        let offset = self.position_to_offset(line, col);
868        let mut best: Option<&SourceEntry> = None;
869        for entry in &self.entries {
870            if entry.contains_offset(offset) {
871                match best {
872                    None => best = Some(entry),
873                    Some(prev) => {
874                        let prev_size = prev.span.end - prev.span.start;
875                        let curr_size = entry.span.end - entry.span.start;
876                        if curr_size < prev_size {
877                            best = Some(entry);
878                        }
879                    }
880                }
881            }
882        }
883        best
884    }
885    /// Find all entries whose spans overlap with the given range.
886    #[allow(dead_code)]
887    pub fn entries_in_range(&self, start: &Span, end: &Span) -> Vec<&SourceEntry> {
888        let range_start = start.start;
889        let range_end = end.end;
890        self.entries
891            .iter()
892            .filter(|e| e.span.start < range_end && e.span.end > range_start)
893            .collect()
894    }
895    /// Get all definition entries.
896    #[allow(dead_code)]
897    pub fn definitions(&self) -> Vec<&SourceEntry> {
898        self.entries
899            .iter()
900            .filter(|e| e.kind == EntryKind::Definition)
901            .collect()
902    }
903    /// Get all references to a given name.
904    #[allow(dead_code)]
905    pub fn references_to(&self, name: &str) -> Vec<&SourceEntry> {
906        self.entries
907            .iter()
908            .filter(|e| e.kind == EntryKind::Reference && e.name.as_deref() == Some(name))
909            .collect()
910    }
911    /// Get all entries with the given kind.
912    #[allow(dead_code)]
913    pub fn entries_of_kind(&self, kind: &EntryKind) -> Vec<&SourceEntry> {
914        self.entries.iter().filter(|e| &e.kind == kind).collect()
915    }
916    /// Produce hover information for a given (line, column) position.
917    #[allow(dead_code)]
918    pub fn hover_info(&self, line: usize, col: usize) -> Option<HoverInfo> {
919        let entry = self.entry_at(line, col)?;
920        let name = entry.name.clone()?;
921        let definition_span = if entry.kind == EntryKind::Reference {
922            self.entries
923                .iter()
924                .find(|e| e.kind == EntryKind::Definition && e.name.as_deref() == Some(&name))
925                .map(|e| e.span.clone())
926        } else if entry.kind == EntryKind::Definition {
927            Some(entry.span.clone())
928        } else {
929            None
930        };
931        let doc = definition_span
932            .as_ref()
933            .and_then(|def_span| self.doc_for_definition(def_span.start));
934        Some(HoverInfo {
935            name,
936            kind: entry.kind.clone(),
937            ty: entry.ty_info.clone(),
938            doc,
939            definition_span,
940        })
941    }
942    /// Find the doc comment that immediately precedes a definition at `def_start`.
943    ///
944    /// Searches for `DocComment` entries whose span ends at or before
945    /// `def_start` and for which no *other* non-comment, non-keyword entry
946    /// falls in between.  Returns the text of the closest such comment, or
947    /// `None`.
948    fn doc_for_definition(&self, def_start: usize) -> Option<String> {
949        let best = self
950            .entries
951            .iter()
952            .filter(|e| e.kind == EntryKind::DocComment && e.span.end <= def_start)
953            .max_by_key(|e| e.span.end)?;
954        let doc_end = best.span.end;
955        let intervening_non_doc = self.entries.iter().any(|e| {
956            e.span.start >= doc_end
957                && e.span.start < def_start
958                && !matches!(
959                    e.kind,
960                    EntryKind::DocComment | EntryKind::Comment | EntryKind::Keyword
961                )
962        });
963        if intervening_non_doc {
964            None
965        } else {
966            best.name.clone()
967        }
968    }
969    /// Produce all semantic tokens for the source map.
970    #[allow(dead_code)]
971    pub fn semantic_tokens(&self) -> Vec<SemanticToken> {
972        if !self.semantic_tokens.is_empty() {
973            return self.semantic_tokens.clone();
974        }
975        self.entries
976            .iter()
977            .map(|entry| {
978                let token_type = Self::entry_kind_to_token_type(&entry.kind);
979                let modifiers = Self::entry_kind_to_modifiers(&entry.kind);
980                SemanticToken {
981                    span: entry.span.clone(),
982                    token_type,
983                    modifiers,
984                }
985            })
986            .collect()
987    }
988    /// Get the text corresponding to a span.
989    #[allow(dead_code)]
990    pub fn span_text(&self, span: &Span) -> &str {
991        let start = span.start.min(self.source.len());
992        let end = span.end.min(self.source.len());
993        &self.source[start..end]
994    }
995    /// Find the definition of a name and return its span.
996    #[allow(dead_code)]
997    pub fn go_to_definition(&self, line: usize, col: usize) -> Option<Span> {
998        let entry = self.entry_at(line, col)?;
999        let name = entry.name.as_deref()?;
1000        if entry.kind == EntryKind::Definition {
1001            return Some(entry.span.clone());
1002        }
1003        self.entries
1004            .iter()
1005            .find(|e| e.kind == EntryKind::Definition && e.name.as_deref() == Some(name))
1006            .map(|e| e.span.clone())
1007    }
1008    /// Find all occurrences (definitions + references) of a name at position.
1009    #[allow(dead_code)]
1010    pub fn find_all_occurrences(&self, line: usize, col: usize) -> Vec<&SourceEntry> {
1011        let entry = match self.entry_at(line, col) {
1012            Some(e) => e,
1013            None => return Vec::new(),
1014        };
1015        let name = match &entry.name {
1016            Some(n) => n.clone(),
1017            None => return Vec::new(),
1018        };
1019        self.entries
1020            .iter()
1021            .filter(|e| {
1022                e.name.as_deref() == Some(&name)
1023                    && matches!(e.kind, EntryKind::Definition | EntryKind::Reference)
1024            })
1025            .collect()
1026    }
1027    /// Compute line offsets for a source string.
1028    fn compute_line_offsets(source: &str) -> Vec<usize> {
1029        let mut offsets = vec![0usize];
1030        for (i, ch) in source.char_indices() {
1031            if ch == '\n' {
1032                offsets.push(i + 1);
1033            }
1034        }
1035        offsets
1036    }
1037    /// Map an `EntryKind` to a `SemanticTokenType`.
1038    fn entry_kind_to_token_type(kind: &EntryKind) -> SemanticTokenType {
1039        match kind {
1040            EntryKind::Definition => SemanticTokenType::Function,
1041            EntryKind::Reference => SemanticTokenType::Variable,
1042            EntryKind::TypeAnnotation => SemanticTokenType::Type,
1043            EntryKind::Binder => SemanticTokenType::Variable,
1044            EntryKind::Constructor => SemanticTokenType::Constructor,
1045            EntryKind::Pattern => SemanticTokenType::Variable,
1046            EntryKind::Tactic => SemanticTokenType::Tactic,
1047            EntryKind::Keyword => SemanticTokenType::Keyword,
1048            EntryKind::Literal => SemanticTokenType::Number,
1049            EntryKind::Comment => SemanticTokenType::Comment,
1050            EntryKind::DocComment => SemanticTokenType::Comment,
1051            EntryKind::Operator => SemanticTokenType::Operator,
1052        }
1053    }
1054    /// Map an `EntryKind` to semantic modifiers.
1055    fn entry_kind_to_modifiers(kind: &EntryKind) -> Vec<SemanticModifier> {
1056        match kind {
1057            EntryKind::Definition => vec![SemanticModifier::Definition],
1058            EntryKind::DocComment => vec![SemanticModifier::Documentation],
1059            _ => Vec::new(),
1060        }
1061    }
1062}
1063/// An index mapping name references to their use-site spans.
1064#[allow(dead_code)]
1065#[derive(Debug, Clone, Default)]
1066pub struct ReferenceIndex {
1067    entries: std::collections::HashMap<String, Vec<Span>>,
1068}
1069#[allow(dead_code)]
1070impl ReferenceIndex {
1071    /// Create an empty reference index.
1072    pub fn new() -> Self {
1073        Self {
1074            entries: std::collections::HashMap::new(),
1075        }
1076    }
1077    /// Record a reference to a name.
1078    pub fn record(&mut self, name: impl Into<String>, span: Span) {
1079        self.entries.entry(name.into()).or_default().push(span);
1080    }
1081    /// All use-sites for a given name.
1082    pub fn uses_of(&self, name: &str) -> &[Span] {
1083        self.entries.get(name).map(|v| v.as_slice()).unwrap_or(&[])
1084    }
1085    /// All names that are referenced.
1086    pub fn referenced_names(&self) -> Vec<&str> {
1087        self.entries.keys().map(|s| s.as_str()).collect()
1088    }
1089    /// Total number of reference entries.
1090    pub fn total_references(&self) -> usize {
1091        self.entries.values().map(|v| v.len()).sum()
1092    }
1093}
1094/// Builder for constructing a `SourceMap` during parsing.
1095pub struct SourceMapBuilder {
1096    /// Entries accumulated during parsing.
1097    entries: Vec<SourceEntry>,
1098    /// Semantic tokens accumulated during parsing.
1099    semantic_tokens: Vec<SemanticToken>,
1100    /// The original source text.
1101    source: String,
1102}
1103impl SourceMapBuilder {
1104    /// Create a new builder for the given source text.
1105    #[allow(dead_code)]
1106    pub fn new(source: &str) -> Self {
1107        Self {
1108            entries: Vec::new(),
1109            semantic_tokens: Vec::new(),
1110            source: source.to_string(),
1111        }
1112    }
1113    /// Add an arbitrary entry to the source map.
1114    #[allow(dead_code)]
1115    pub fn add_entry(&mut self, span: Span, kind: EntryKind, name: Option<String>) {
1116        self.entries.push(SourceEntry {
1117            span,
1118            kind,
1119            name,
1120            ty_info: None,
1121        });
1122    }
1123    /// Add an entry with type information.
1124    #[allow(dead_code)]
1125    pub fn add_entry_with_type(
1126        &mut self,
1127        span: Span,
1128        kind: EntryKind,
1129        name: Option<String>,
1130        ty_info: String,
1131    ) {
1132        self.entries.push(SourceEntry {
1133            span,
1134            kind,
1135            name,
1136            ty_info: Some(ty_info),
1137        });
1138    }
1139    /// Add a definition entry.
1140    #[allow(dead_code)]
1141    pub fn add_definition(&mut self, span: Span, name: &str) {
1142        self.entries.push(SourceEntry {
1143            span,
1144            kind: EntryKind::Definition,
1145            name: Some(name.to_string()),
1146            ty_info: None,
1147        });
1148    }
1149    /// Add a definition entry with type info.
1150    #[allow(dead_code)]
1151    pub fn add_definition_with_type(&mut self, span: Span, name: &str, ty_info: &str) {
1152        self.entries.push(SourceEntry {
1153            span,
1154            kind: EntryKind::Definition,
1155            name: Some(name.to_string()),
1156            ty_info: Some(ty_info.to_string()),
1157        });
1158    }
1159    /// Add a reference entry.
1160    #[allow(dead_code)]
1161    pub fn add_reference(&mut self, span: Span, name: &str) {
1162        self.entries.push(SourceEntry {
1163            span,
1164            kind: EntryKind::Reference,
1165            name: Some(name.to_string()),
1166            ty_info: None,
1167        });
1168    }
1169    /// Add a binder entry.
1170    #[allow(dead_code)]
1171    pub fn add_binder(&mut self, span: Span, name: &str) {
1172        self.entries.push(SourceEntry {
1173            span,
1174            kind: EntryKind::Binder,
1175            name: Some(name.to_string()),
1176            ty_info: None,
1177        });
1178    }
1179    /// Add a constructor entry.
1180    #[allow(dead_code)]
1181    pub fn add_constructor(&mut self, span: Span, name: &str) {
1182        self.entries.push(SourceEntry {
1183            span,
1184            kind: EntryKind::Constructor,
1185            name: Some(name.to_string()),
1186            ty_info: None,
1187        });
1188    }
1189    /// Add a keyword entry.
1190    #[allow(dead_code)]
1191    pub fn add_keyword(&mut self, span: Span) {
1192        self.entries.push(SourceEntry {
1193            span,
1194            kind: EntryKind::Keyword,
1195            name: None,
1196            ty_info: None,
1197        });
1198    }
1199    /// Add a literal entry.
1200    #[allow(dead_code)]
1201    pub fn add_literal(&mut self, span: Span) {
1202        self.entries.push(SourceEntry {
1203            span,
1204            kind: EntryKind::Literal,
1205            name: None,
1206            ty_info: None,
1207        });
1208    }
1209    /// Add an operator entry.
1210    #[allow(dead_code)]
1211    pub fn add_operator(&mut self, span: Span, symbol: &str) {
1212        self.entries.push(SourceEntry {
1213            span,
1214            kind: EntryKind::Operator,
1215            name: Some(symbol.to_string()),
1216            ty_info: None,
1217        });
1218    }
1219    /// Add a comment entry.
1220    #[allow(dead_code)]
1221    pub fn add_comment(&mut self, span: Span) {
1222        self.entries.push(SourceEntry {
1223            span,
1224            kind: EntryKind::Comment,
1225            name: None,
1226            ty_info: None,
1227        });
1228    }
1229    /// Add a doc comment entry.
1230    #[allow(dead_code)]
1231    pub fn add_doc_comment(&mut self, span: Span, text: &str) {
1232        self.entries.push(SourceEntry {
1233            span,
1234            kind: EntryKind::DocComment,
1235            name: Some(text.to_string()),
1236            ty_info: None,
1237        });
1238    }
1239    /// Add a tactic entry.
1240    #[allow(dead_code)]
1241    pub fn add_tactic(&mut self, span: Span, name: &str) {
1242        self.entries.push(SourceEntry {
1243            span,
1244            kind: EntryKind::Tactic,
1245            name: Some(name.to_string()),
1246            ty_info: None,
1247        });
1248    }
1249    /// Add a pattern entry.
1250    #[allow(dead_code)]
1251    pub fn add_pattern(&mut self, span: Span, name: Option<&str>) {
1252        self.entries.push(SourceEntry {
1253            span,
1254            kind: EntryKind::Pattern,
1255            name: name.map(|n| n.to_string()),
1256            ty_info: None,
1257        });
1258    }
1259    /// Add a type annotation entry.
1260    #[allow(dead_code)]
1261    pub fn add_type_annotation(&mut self, span: Span) {
1262        self.entries.push(SourceEntry {
1263            span,
1264            kind: EntryKind::TypeAnnotation,
1265            name: None,
1266            ty_info: None,
1267        });
1268    }
1269    /// Add a pre-computed semantic token.
1270    #[allow(dead_code)]
1271    pub fn add_semantic_token(&mut self, token: SemanticToken) {
1272        self.semantic_tokens.push(token);
1273    }
1274    /// Get the current number of entries.
1275    #[allow(dead_code)]
1276    pub fn entry_count(&self) -> usize {
1277        self.entries.len()
1278    }
1279    /// Build the final `SourceMap`.
1280    ///
1281    /// Entries are sorted by span start offset for efficient lookup.
1282    #[allow(dead_code)]
1283    pub fn build(mut self) -> SourceMap {
1284        self.entries.sort_by(|a, b| {
1285            a.span.start.cmp(&b.span.start).then_with(|| {
1286                let a_size = a.span.end - a.span.start;
1287                let b_size = b.span.end - b.span.start;
1288                a_size.cmp(&b_size)
1289            })
1290        });
1291        self.semantic_tokens
1292            .sort_by(|a, b| a.span.start.cmp(&b.span.start));
1293        let line_offsets = SourceMap::compute_line_offsets(&self.source);
1294        SourceMap {
1295            entries: self.entries,
1296            line_offsets,
1297            source: self.source,
1298            semantic_tokens: self.semantic_tokens,
1299        }
1300    }
1301}
1302/// Hover information for IDE tooltips.
1303#[derive(Clone, Debug, PartialEq)]
1304pub struct HoverInfo {
1305    /// The name at the hover position.
1306    pub name: String,
1307    /// The kind of the entry.
1308    pub kind: EntryKind,
1309    /// The type of the entry (if known).
1310    pub ty: Option<String>,
1311    /// Documentation string (if available).
1312    pub doc: Option<String>,
1313    /// Span of the definition site (if known).
1314    pub definition_span: Option<Span>,
1315}
1316/// A source map chain that composes two mappings.
1317#[allow(dead_code)]
1318#[allow(missing_docs)]
1319pub struct MapChain {
1320    /// First map (A -> B)
1321    pub first: BidiMapper,
1322    /// Second map (B -> C)
1323    pub second: BidiMapper,
1324}
1325impl MapChain {
1326    /// Create a new chain.
1327    #[allow(dead_code)]
1328    pub fn new(first: BidiMapper, second: BidiMapper) -> Self {
1329        MapChain { first, second }
1330    }
1331    /// Map from A to C.
1332    #[allow(dead_code)]
1333    pub fn a_to_c(&self, a: usize) -> Option<usize> {
1334        let b = self.first.to_gen(a)?;
1335        self.second.to_gen(b)
1336    }
1337    /// Map from C to A.
1338    #[allow(dead_code)]
1339    pub fn c_to_a(&self, c: usize) -> Option<usize> {
1340        let b = self.second.to_orig(c)?;
1341        self.first.to_orig(b)
1342    }
1343}
1344/// The kind of a document symbol.
1345#[allow(dead_code)]
1346#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1347pub enum SymbolKind {
1348    /// A theorem or lemma.
1349    Theorem,
1350    /// A definition.
1351    Definition,
1352    /// An axiom.
1353    Axiom,
1354    /// An inductive type.
1355    Inductive,
1356    /// A structure.
1357    Structure,
1358    /// A class.
1359    Class,
1360    /// An instance.
1361    Instance,
1362    /// A namespace.
1363    Namespace,
1364    /// A section.
1365    Section,
1366    /// A constructor.
1367    Constructor,
1368    /// A field.
1369    Field,
1370    /// A variable declaration.
1371    Variable,
1372}