1use codebase::{BufId, BufRange};
2use std::cmp;
3use std::fmt::Debug;
4use std::rc::Rc;
5
6pub trait Span: Clone + Debug + PartialEq {
7 fn extend(&self, other: &Self) -> Self;
8}
9
10#[cfg(test)]
11impl Span for () {
12 fn extend(&self, _: &Self) -> Self {}
13}
14
15pub trait Source {
16 type Span: Span;
17 fn span(&self) -> Self::Span;
18}
19
20pub trait TokenTracker {
21 type Span: Span;
22 type BufContext: Clone + LexemeRefFactory<Span = Self::Span>;
23 fn mk_buf_context(
24 &mut self,
25 buf_id: BufId,
26 included_from: Option<Self::Span>,
27 ) -> Self::BufContext;
28}
29
30pub trait LexemeRefFactory {
31 type Span;
32 fn mk_lexeme_ref(&self, range: BufRange) -> Self::Span;
33}
34
35#[derive(Clone, Debug, PartialEq)]
36pub enum TokenRefData {
37 Lexeme {
38 range: BufRange,
39 context: Rc<BufContextData>,
40 },
41}
42
43#[derive(Debug, PartialEq)]
44pub struct BufContextData {
45 pub buf_id: BufId,
46 pub included_from: Option<TokenRefData>,
47}
48
49pub struct SimpleTokenTracker;
50
51impl TokenTracker for SimpleTokenTracker {
52 type Span = TokenRefData;
53 type BufContext = SimpleBufTokenRefFactory;
54 fn mk_buf_context(
55 &mut self,
56 buf_id: BufId,
57 included_from: Option<Self::Span>,
58 ) -> Self::BufContext {
59 let context = Rc::new(BufContextData {
60 buf_id,
61 included_from,
62 });
63 SimpleBufTokenRefFactory { context }
64 }
65}
66
67#[derive(Clone)]
68pub struct SimpleBufTokenRefFactory {
69 context: Rc<BufContextData>,
70}
71
72impl LexemeRefFactory for SimpleBufTokenRefFactory {
73 type Span = TokenRefData;
74 fn mk_lexeme_ref(&self, range: BufRange) -> Self::Span {
75 TokenRefData::Lexeme {
76 range,
77 context: self.context.clone(),
78 }
79 }
80}
81
82impl Span for TokenRefData {
83 fn extend(&self, other: &Self) -> Self {
84 use self::TokenRefData::*;
85 match (self, other) {
86 (
87 Lexeme { range, context },
88 Lexeme {
89 range: other_range,
90 context: other_context,
91 },
92 )
93 if Rc::ptr_eq(context, other_context) =>
94 {
95 Lexeme {
96 range: cmp::min(range.start, other_range.start)
97 ..cmp::max(range.end, other_range.end),
98 context: (*context).clone(),
99 }
100 }
101 _ => unreachable!(),
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use codebase::TextCache;
110
111 #[test]
112 fn extend_span() {
113 let mut codebase = TextCache::new();
114 let src = "left right";
115 let buf_id = codebase.add_src_buf("/my/file", src);
116 let context = Rc::new(BufContextData {
117 buf_id,
118 included_from: None,
119 });
120 let left = TokenRefData::Lexeme {
121 range: BufRange::from(0..4),
122 context: context.clone(),
123 };
124 let right = TokenRefData::Lexeme {
125 range: BufRange::from(5..10),
126 context: context.clone(),
127 };
128 let combined = left.extend(&right);
129 assert_eq!(
130 combined,
131 TokenRefData::Lexeme {
132 range: BufRange::from(0..10),
133 context
134 }
135 )
136 }
137}