Skip to content

Commit 7bfc257

Browse files
span pair
1 parent 45b3758 commit 7bfc257

File tree

6 files changed

+87
-106
lines changed

6 files changed

+87
-106
lines changed

crates/djls-templates/src/lexer.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use djls_source::Span;
22

33
use crate::db::Db as TemplateDb;
4+
use crate::spans::SpanPair;
45
use crate::tokens::Token;
56
use crate::tokens::TokenContent;
6-
use crate::tokens::TokenSpans;
77

88
const BLOCK_TAG_START: &str = "{%";
99
const BLOCK_TAG_END: &str = "%}";
@@ -64,7 +64,7 @@ impl<'db> Lexer<'db> {
6464
fn lex_django_construct(
6565
&mut self,
6666
end: &str,
67-
token_fn: impl FnOnce(TokenContent<'db>, TokenSpans) -> Token<'db>,
67+
token_fn: impl FnOnce(TokenContent<'db>, SpanPair) -> Token<'db>,
6868
) -> Token<'db> {
6969
let opening_len = 2;
7070
let content_start = self.start + opening_len;
@@ -79,7 +79,7 @@ impl<'db> Lexer<'db> {
7979
self.consume_n(end.len());
8080
let full_end = self.current;
8181
let full_span = Span::from_bounds(self.start, full_end);
82-
token_fn(content, TokenSpans::new(span, full_span))
82+
token_fn(content, SpanPair::new(span, full_span))
8383
}
8484
Err(err_text) => {
8585
let content_end = self.current;
@@ -88,7 +88,7 @@ impl<'db> Lexer<'db> {
8888
let content = TokenContent::new(self.db, err_text);
8989
Token::Error {
9090
content,
91-
spans: TokenSpans::new(span, full_span),
91+
spans: SpanPair::new(span, full_span),
9292
}
9393
}
9494
}
@@ -101,7 +101,7 @@ impl<'db> Lexer<'db> {
101101
self.consume(); // \n of \r\n
102102
}
103103
let span = Span::from_bounds(self.start, self.current);
104-
let spans = TokenSpans::new(span, span);
104+
let spans = SpanPair::new(span, span);
105105
Token::Newline { spans }
106106
} else {
107107
self.consume(); // Consume the first whitespace
@@ -112,7 +112,7 @@ impl<'db> Lexer<'db> {
112112
self.consume();
113113
}
114114
let span = Span::from_bounds(self.start, self.current);
115-
let spans = TokenSpans::new(span, span);
115+
let spans = SpanPair::new(span, span);
116116
Token::Whitespace { spans }
117117
}
118118
}
@@ -134,7 +134,7 @@ impl<'db> Lexer<'db> {
134134
let text = &self.source[text_start..self.current];
135135
let content = TokenContent::new(self.db, text.to_string());
136136
let span = Span::from_bounds(self.start, self.current);
137-
let spans = TokenSpans::new(span, span);
137+
let spans = SpanPair::new(span, span);
138138
Token::Text { content, spans }
139139
}
140140

crates/djls-templates/src/lib.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod error;
5050
mod lexer;
5151
pub mod nodelist;
5252
mod parser;
53+
mod spans;
5354
mod tokens;
5455

5556
pub use db::Db;
@@ -64,6 +65,7 @@ pub use nodelist::NodeList;
6465
pub use parser::ParseError;
6566
pub use parser::Parser;
6667
use salsa::Accumulator;
68+
use spans::SpanPair;
6769
use tokens::TokenStream;
6870

6971
/// Lex a template file into tokens.
@@ -108,12 +110,9 @@ pub fn parse_template(db: &dyn Db, file: File) -> Option<NodeList<'_>> {
108110

109111
let text = source.as_ref();
110112
let span = djls_source::Span::from_bounds(0, text.len());
113+
let spans = SpanPair::new(span, span);
111114
let error_node = Node::Error {
112-
node: ErrorNode {
113-
span,
114-
full_span: span,
115-
error: err,
116-
},
115+
node: ErrorNode { spans, error: err },
117116
};
118117

119118
NodeList::new(db, vec![error_node])

crates/djls-templates/src/nodelist.rs

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use djls_source::Span;
22

33
use crate::db::Db as TemplateDb;
44
use crate::parser::ParseError;
5+
use crate::spans::SpanPair;
56

67
#[salsa::tracked(debug)]
78
pub struct NodeList<'db> {
@@ -15,23 +16,19 @@ pub enum Node<'db> {
1516
Tag {
1617
name: TagName<'db>,
1718
bits: Vec<TagBit<'db>>,
18-
span: Span,
19-
full_span: Span,
19+
spans: SpanPair,
2020
},
2121
Comment {
2222
content: String,
23-
span: Span,
24-
full_span: Span,
23+
spans: SpanPair,
2524
},
2625
Text {
27-
span: Span,
28-
full_span: Span,
26+
spans: SpanPair,
2927
},
3028
Variable {
3129
var: VariableName<'db>,
3230
filters: Vec<FilterName<'db>>,
33-
span: Span,
34-
full_span: Span,
31+
spans: SpanPair,
3532
},
3633
Error {
3734
node: ErrorNode,
@@ -42,40 +39,40 @@ impl<'db> Node<'db> {
4239
#[must_use]
4340
pub fn span(&self) -> Span {
4441
match self {
45-
Node::Tag { span, .. }
46-
| Node::Variable { span, .. }
47-
| Node::Comment { span, .. }
48-
| Node::Text { span, .. } => *span,
49-
Node::Error { node, .. } => node.span,
42+
Node::Tag { spans, .. }
43+
| Node::Variable { spans, .. }
44+
| Node::Comment { spans, .. }
45+
| Node::Text { spans, .. } => spans.content,
46+
Node::Error { node, .. } => node.spans.content,
5047
}
5148
}
5249

5350
#[must_use]
5451
pub fn full_span(&self) -> Span {
5552
match self {
56-
Node::Variable { full_span, .. }
57-
| Node::Comment { full_span, .. }
58-
| Node::Tag { full_span, .. }
59-
| Node::Text { full_span, .. } => *full_span,
60-
Node::Error { node } => node.full_span,
53+
Node::Variable { spans, .. }
54+
| Node::Comment { spans, .. }
55+
| Node::Tag { spans, .. }
56+
| Node::Text { spans, .. } => spans.lexeme,
57+
Node::Error { node } => node.spans.lexeme,
6158
}
6259
}
6360

6461
pub fn identifier_span(&self, db: &'db dyn TemplateDb) -> Option<Span> {
6562
match self {
66-
Node::Tag { name, span, .. } => {
63+
Node::Tag { name, spans, .. } => {
6764
// Just the tag name (e.g., "if" in "{% if user.is_authenticated %}")
6865
let name_len = name.text(db).len();
6966
Some(Span {
70-
start: span.start,
67+
start: spans.content.start,
7168
length: u32::try_from(name_len).unwrap_or(0),
7269
})
7370
}
74-
Node::Variable { var, span, .. } => {
71+
Node::Variable { var, spans, .. } => {
7572
// Just the variable name (e.g., "user" in "{{ user.name|title }}")
7673
let var_len = var.text(db).len();
7774
Some(Span {
78-
start: span.start,
75+
start: spans.content.start,
7976
length: u32::try_from(var_len).unwrap_or(0),
8077
})
8178
}
@@ -86,8 +83,7 @@ impl<'db> Node<'db> {
8683

8784
#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
8885
pub struct ErrorNode {
89-
pub span: Span,
90-
pub full_span: Span,
86+
pub spans: SpanPair,
9187
pub error: ParseError,
9288
}
9389

crates/djls-templates/src/parser.rs

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::nodelist::NodeList;
1313
use crate::nodelist::TagBit;
1414
use crate::nodelist::TagName;
1515
use crate::nodelist::VariableName;
16+
use crate::spans::SpanPair;
1617
use crate::tokens::span_from_token;
1718
use crate::tokens::Token;
1819
use crate::tokens::TokenStream;
@@ -76,10 +77,10 @@ impl<'db> Parser<'db> {
7677
let token = self.peek_previous()?;
7778

7879
let span = span_from_token(token, self.db);
80+
let full_span = token.full_span().unwrap_or(span);
7981
Ok(Node::Comment {
8082
content: token.content(self.db),
81-
span,
82-
full_span: token.full_span().unwrap_or(span),
83+
spans: SpanPair::new(span, full_span),
8384
})
8485
}
8586

@@ -125,8 +126,7 @@ impl<'db> Parser<'db> {
125126
Ok(Node::Tag {
126127
name,
127128
bits,
128-
span,
129-
full_span,
129+
spans: SpanPair::new(span, full_span),
130130
})
131131
}
132132

@@ -160,8 +160,7 @@ impl<'db> Parser<'db> {
160160
Ok(Node::Variable {
161161
var,
162162
filters,
163-
span,
164-
full_span,
163+
spans: SpanPair::new(span, full_span),
165164
})
166165
}
167166

@@ -196,8 +195,7 @@ impl<'db> Parser<'db> {
196195
let span = Span::new(start, length);
197196

198197
Ok(Node::Text {
199-
span,
200-
full_span: span,
198+
spans: SpanPair::new(span, span),
201199
})
202200
}
203201

@@ -265,22 +263,18 @@ impl<'db> Parser<'db> {
265263
.map(|token| {
266264
let span = span_from_token(token, self.db);
267265
let full_span = token.full_span().unwrap_or(span);
268-
(span, full_span)
266+
SpanPair::new(span, full_span)
269267
});
270268

271-
let (span, full_span) = spans.unwrap_or_else(|| {
269+
let spans = spans.unwrap_or_else(|| {
272270
let empty = Span::new(0, 0);
273-
(empty, empty)
271+
SpanPair::new(empty, empty)
274272
});
275273

276274
self.report_error(&error);
277275

278276
Node::Error {
279-
node: ErrorNode {
280-
span,
281-
full_span,
282-
error,
283-
},
277+
node: ErrorNode { spans, error },
284278
}
285279
}
286280
}
@@ -433,44 +427,34 @@ mod tests {
433427
impl TestNode {
434428
fn from_node(node: &Node<'_>, db: &dyn crate::db::Db) -> Self {
435429
match node {
436-
Node::Tag {
437-
name,
438-
bits,
439-
span,
440-
full_span,
441-
} => TestNode::Tag {
430+
Node::Tag { name, bits, spans } => TestNode::Tag {
442431
name: name.text(db).to_string(),
443432
bits: bits.iter().map(|b| b.text(db).to_string()).collect(),
444-
span: (span.start, span.length),
445-
full_span: (full_span.start, full_span.length),
433+
span: spans.content_tuple(),
434+
full_span: spans.lexeme_tuple(),
446435
},
447-
Node::Comment {
448-
content,
449-
span,
450-
full_span,
451-
} => TestNode::Comment {
436+
Node::Comment { content, spans } => TestNode::Comment {
452437
content: content.clone(),
453-
span: (span.start, span.length),
454-
full_span: (full_span.start, full_span.length),
438+
span: spans.content_tuple(),
439+
full_span: spans.lexeme_tuple(),
455440
},
456-
Node::Text { span, full_span } => TestNode::Text {
457-
span: (span.start, span.length),
458-
full_span: (full_span.start, full_span.length),
441+
Node::Text { spans } => TestNode::Text {
442+
span: spans.content_tuple(),
443+
full_span: spans.lexeme_tuple(),
459444
},
460445
Node::Variable {
461446
var,
462447
filters,
463-
span,
464-
full_span,
448+
spans,
465449
} => TestNode::Variable {
466450
var: var.text(db).to_string(),
467451
filters: filters.iter().map(|f| f.text(db).to_string()).collect(),
468-
span: (span.start, span.length),
469-
full_span: (full_span.start, full_span.length),
452+
span: spans.content_tuple(),
453+
full_span: spans.lexeme_tuple(),
470454
},
471455
Node::Error { node } => TestNode::Error {
472-
span: (node.span.start, node.span.length),
473-
full_span: (node.full_span.start, node.full_span.length),
456+
span: node.spans.content_tuple(),
457+
full_span: node.spans.lexeme_tuple(),
474458
error: node.error.clone(),
475459
},
476460
}

crates/djls-templates/src/spans.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use djls_source::Span;
2+
3+
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
4+
pub struct SpanPair {
5+
pub content: Span,
6+
pub lexeme: Span,
7+
}
8+
9+
impl SpanPair {
10+
#[must_use]
11+
pub fn new(content: Span, lexeme: Span) -> Self {
12+
Self { content, lexeme }
13+
}
14+
15+
#[must_use]
16+
pub fn content_tuple(&self) -> (u32, u32) {
17+
(self.content.start, self.content.length)
18+
}
19+
20+
#[must_use]
21+
pub fn lexeme_tuple(&self) -> (u32, u32) {
22+
(self.lexeme.start, self.lexeme.length)
23+
}
24+
}

0 commit comments

Comments
 (0)