auto_lsp_core/ast/
builder.rs1use crate::errors::ParseErrorAccumulator;
20use crate::{ast::AstNode, errors::AstError};
21use salsa::Accumulator;
22use std::ops::ControlFlow;
23use std::sync::Arc;
24use tree_sitter::{Node, TreeCursor};
25
26pub type TryFromParams<'from> = (
28 &'from Node<'from>, &'from dyn salsa::Database, &'from mut Builder, usize, Option<usize>, );
34
35#[derive(Default)]
41pub struct Builder {
42 id_ctr: usize,
43 nodes: Vec<Arc<dyn AstNode>>,
44}
45
46impl Builder {
47 pub fn len(&self) -> usize {
48 self.nodes.len()
49 }
50
51 pub fn is_empty(&self) -> bool {
52 self.nodes.is_empty()
53 }
54
55 pub fn take_nodes(self) -> Vec<Arc<dyn AstNode>> {
56 self.nodes
57 }
58
59 fn next_id(&mut self) -> usize {
60 self.id_ctr += 1;
61 self.id_ctr
62 }
63
64 fn create<'db, T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>>(
68 &mut self,
69 db: &'db dyn salsa::Database,
70 cursor: &TreeCursor,
71 parent_id: Option<usize>,
72 ) -> Result<Arc<T>, AstError> {
73 let node = cursor.node();
74 let id = self.next_id();
76 let result = T::try_from((&node, db, self, id, parent_id)).map(Arc::new)?;
77 self.nodes.push(result.clone());
79 Ok(result)
80 }
81
82 pub fn builder<'cursor, F>(
84 &'cursor mut self,
85 db: &'cursor dyn salsa::Database,
86 node: &'cursor Node<'cursor>,
87 parent: Option<usize>,
88 mut f: F,
89 ) where
90 F: for<'cb> FnMut(
91 &'cb mut TreeWalk<'cursor>,
92 ) -> ControlFlow<(), &'cb mut TreeWalk<'cursor>>,
93 {
94 TreeWalk::new(self, db, node, parent).walk(&mut f);
95 }
96}
97
98pub struct TreeWalk<'cursor> {
100 db: &'cursor dyn salsa::Database,
101 builder: &'cursor mut Builder, cursor: TreeCursor<'cursor>, parent: Option<usize>,
104}
105
106impl<'cursor> TreeWalk<'cursor> {
107 fn new(
108 builder: &'cursor mut Builder,
109 db: &'cursor dyn salsa::Database,
110 node: &'cursor Node<'cursor>,
111 parent: Option<usize>,
112 ) -> Self {
113 let cursor = node.walk();
114 Self {
115 builder,
116 db,
117 cursor,
118 parent,
119 }
120 }
121
122 fn walk<F>(&mut self, mut f: F)
127 where
128 F: FnMut(&mut Self) -> ControlFlow<(), &mut Self>,
129 {
130 if self.cursor.goto_first_child() {
131 let _ = f(self);
132
133 while self.cursor.goto_next_sibling() {
134 let _ = f(self);
135 }
136 }
137 }
138 pub fn on_field_id<
143 T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
144 const FIELD_ID: u16,
145 >(
146 &mut self,
147 result: &mut Result<Option<Arc<T>>, AstError>,
148 ) -> ControlFlow<(), &mut Self> {
149 if let Some(field) = self.cursor.field_id() {
150 if field == std::num::NonZero::new(FIELD_ID).expect("FIELD_ID should be non-zero") {
151 *result = self
152 .builder
153 .create(self.db, &self.cursor, self.parent)
154 .map(Some);
155 return ControlFlow::Break(());
156 }
157 }
158 ControlFlow::Continue(self)
159 }
160
161 pub fn on_vec_field_id<
165 T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
166 const FIELD_ID: u16,
167 >(
168 &mut self,
169 result: &mut Vec<Arc<T>>,
170 ) -> ControlFlow<(), &mut Self> {
171 if let Some(field) = self.cursor.field_id() {
172 if field == std::num::NonZero::new(FIELD_ID).expect("FIELD_ID should be non-zero") {
173 match self.builder.create(self.db, &self.cursor, self.parent) {
174 Ok(node) => result.push(node),
175 Err(e) => ParseErrorAccumulator::accumulate(e.into(), self.db),
178 };
179 return ControlFlow::Break(());
180 }
181 }
182 ControlFlow::Continue(self)
183 }
184
185 pub fn on_children_id<
189 T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
190 >(
191 &mut self,
192 result: &mut Result<Option<Arc<T>>, AstError>,
193 ) -> ControlFlow<(), &mut Self> {
194 let node = self.cursor.node();
195 if T::contains(&node) {
196 *result = self
197 .builder
198 .create(self.db, &self.cursor, self.parent)
199 .map(Some);
200 return ControlFlow::Break(());
201 }
202 ControlFlow::Continue(self)
203 }
204
205 pub fn on_vec_children_id<
209 T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
210 >(
211 &mut self,
212 result: &mut Vec<Arc<T>>,
213 ) -> ControlFlow<(), &mut Self> {
214 if T::contains(&self.cursor.node()) {
215 match self.builder.create(self.db, &self.cursor, self.parent) {
216 Ok(node) => result.push(node),
217 Err(e) => ParseErrorAccumulator::accumulate(e.into(), self.db),
220 };
221 return ControlFlow::Break(());
222 }
223 ControlFlow::Continue(self)
224 }
225}