cairo_lang_syntax/node/
with_db.rs1use cairo_lang_filesystem::span::TextWidth;
2use cairo_lang_primitive_token::{PrimitiveSpan, PrimitiveToken, ToPrimitiveTokenStream};
3use salsa::Database;
4
5use super::SyntaxNode;
6
7pub struct SyntaxNodeWithDb<'a> {
8 node: &'a SyntaxNode<'a>,
9 db: &'a dyn Database,
10}
11
12impl<'a> SyntaxNodeWithDb<'a> {
13 pub fn new(node: &'a SyntaxNode<'a>, db: &'a dyn Database) -> Self {
14 Self { node, db }
15 }
16}
17
18impl<'a> ToPrimitiveTokenStream for SyntaxNodeWithDb<'a> {
19 type Iter = SyntaxNodeWithDbIterator<'a>;
20
21 fn to_primitive_token_stream(&self) -> Self::Iter {
22 SyntaxNodeWithDbIterator::new(self.db, self.node)
24 }
25}
26
27pub struct SyntaxNodeWithDbIterator<'a> {
28 iter_stack: Vec<&'a SyntaxNode<'a>>,
30 buffer: Vec<PrimitiveToken>,
34 db: &'a dyn Database,
35}
36
37impl<'a> SyntaxNodeWithDbIterator<'a> {
38 pub fn new(db: &'a dyn Database, node: &'a SyntaxNode<'a>) -> Self {
39 Self { db, buffer: Vec::with_capacity(3), iter_stack: vec![node] }
40 }
41}
42
43impl<'a> Iterator for SyntaxNodeWithDbIterator<'a> {
44 type Item = PrimitiveToken;
45
46 fn next(&mut self) -> Option<Self::Item> {
47 loop {
52 if let Some(item) = self.buffer.pop() {
54 return Some(item);
56 }
57 let node = self.iter_stack.pop()?;
58 if node.green_node(self.db).kind.is_terminal() {
62 token_from_syntax_node(node, self.db, &mut self.buffer);
63 } else {
64 self.iter_stack.extend(node.get_children(self.db).iter().rev());
65 }
66 }
67 }
68}
69
70fn token_from_syntax_node(
83 node: &SyntaxNode<'_>,
84 db: &dyn Database,
85 result: &mut Vec<PrimitiveToken>,
86) {
87 let span_without_trivia = node.span_without_trivia(db);
88 let span_with_trivia = node.span(db);
89 let text = node.get_text(db);
90 let prefix_len = span_without_trivia.start - span_with_trivia.start;
91 let (prefix, rest) = text.split_at(prefix_len.as_u32() as usize);
92 let suffix_len = span_with_trivia.end - span_without_trivia.end;
93 let (content, suffix) = rest.split_at(rest.len() - suffix_len.as_u32() as usize);
94 if suffix_len > TextWidth::ZERO {
95 result.push(PrimitiveToken {
96 content: suffix.to_string(),
97 span: Some(PrimitiveSpan {
98 start: span_without_trivia.end.as_u32() as usize,
99 end: span_with_trivia.end.as_u32() as usize,
100 }),
101 });
102 }
103 if !content.is_empty() {
104 result.push(PrimitiveToken {
105 content: content.to_string(),
106 span: Some(PrimitiveSpan {
107 start: span_without_trivia.start.as_u32() as usize,
108 end: span_without_trivia.end.as_u32() as usize,
109 }),
110 });
111 }
112 if prefix_len > TextWidth::ZERO {
113 result.push(PrimitiveToken {
114 content: prefix.to_string(),
115 span: Some(PrimitiveSpan {
116 start: span_with_trivia.start.as_u32() as usize,
117 end: span_without_trivia.start.as_u32() as usize,
118 }),
119 });
120 }
121}