1pub use main::{SyntaxTree, SyntaxTreeBuilder, SyntaxTreeMutView};
2pub use utils::{ChildScope, DfsIter};
3
4use crate::graph::nodes::Inaccessible;
5use crate::graph::tags::ChildTag;
6
7type Graph<T = Inaccessible, E = ChildTag> = slotgraph::DiGraph<T, E>;
8
9mod stage {
10 use crate::graph::PermTkn;
11
12 #[derive(Debug)]
13 pub struct FullAccess(pub(super) PermTkn);
14
15 #[derive(Debug)]
16 pub struct ViewingAccess<'a>(pub(super) &'a PermTkn);
17
18 pub struct ModificationAccess<'a>(pub(super) &'a mut PermTkn);
19
20 #[derive(Default, Debug)]
21 pub struct NoAccess;
22
23 pub(super) trait CanAccess {
24 fn tkn(&self) -> &PermTkn;
25 }
26
27 impl CanAccess for FullAccess {
28 fn tkn(&self) -> &PermTkn {
29 &self.0
30 }
31 }
32
33 impl CanAccess for ViewingAccess<'_> {
34 fn tkn(&self) -> &PermTkn {
35 self.0
36 }
37 }
38
39 impl CanAccess for ModificationAccess<'_> {
40 fn tkn(&self) -> &PermTkn {
41 self.0
42 }
43 }
44}
45
46mod main {
47 use std::fmt::{Display, Formatter};
48
49 use kodept_core::{ConvertibleToMut, ConvertibleToRef};
50 use slotgraph::export::{Config, Direction, Dot};
51 use slotgraph::SubDiGraph;
52
53 use crate::graph::{AnyNode, Change, ChangeSet, Identifiable, NodeId, PermTkn};
54 use crate::graph::nodes::Inaccessible;
55 use crate::graph::tags::{ChildTag, TAGS_DESC};
56 use crate::graph::tree::{ChildScope, DfsIter, Graph};
57 use crate::graph::tree::stage::{
58 CanAccess, FullAccess, ModificationAccess, NoAccess, ViewingAccess,
59 };
60 use crate::graph::utils::OptVec;
61 use crate::node_properties::{Node, NodeWithParent};
62 use crate::Uninit;
63
64 #[derive(Debug)]
65 pub struct SyntaxTree<Permission = NoAccess> {
66 pub(super) graph: Graph,
67 pub(super) stage: Permission,
68 }
69
70 pub type SyntaxTreeBuilder = SyntaxTree<FullAccess>;
71 pub type SyntaxTreeMutView<'token> = SyntaxTree<ModificationAccess<'token>>;
72
73 impl Default for SyntaxTree<FullAccess> {
74 fn default() -> Self {
75 Self {
77 graph: Default::default(),
78 stage: FullAccess(PermTkn::new()),
79 }
80 }
81 }
82
83 impl SyntaxTree<FullAccess> {
84 pub fn new() -> SyntaxTree<FullAccess> {
85 SyntaxTree::default()
86 }
87
88 pub fn export_dot<'a>(&'a self, config: &'a [Config]) -> impl Display + 'a {
89 struct Wrapper<'c>(SubDiGraph<String, &'static str>, &'c [Config]);
90 impl Display for Wrapper<'_> {
91 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92 let dot = Dot::with_config(&self.0, self.1);
93 write!(f, "{dot}")
94 }
95 }
96
97 let mapping = self.graph.map(
98 |id, node| format!("{} [{}]", node.ro(&self.stage.0).name(), id),
99 |_, &edge| TAGS_DESC[edge as usize],
100 );
101 Wrapper(mapping, config)
102 }
103 }
104
105 #[allow(private_bounds)]
106 impl<U: CanAccess> SyntaxTree<U> {
107 pub fn add_node<T>(&mut self, node: Uninit<T>) -> ChildScope<'_, T, U>
108 where
109 T: Identifiable + Into<AnyNode>,
110 {
111 let id = self
112 .graph
113 .add_node_with_key(|id| Inaccessible::new(node.unwrap(id.into())));
114 ChildScope::new(self, id.into())
115 }
116
117 pub fn build(self) -> SyntaxTree<NoAccess> {
118 SyntaxTree {
119 graph: self.graph,
120 stage: NoAccess,
121 }
122 }
123 }
124
125 impl SyntaxTree<ViewingAccess<'_>> {
126 fn apply_change(&mut self, change: Change) {
127 match change {
128 Change::Delete { child_id, .. } => {
129 self.graph.remove_node(child_id.into());
130 }
131 Change::Add {
132 parent_id,
133 child,
134 tag,
135 } => {
136 let child_id = self
137 .graph
138 .add_node_with_key(|id| Inaccessible::new(child.unwrap(id.into())));
139 self.graph.add_edge(parent_id.into(), child_id, tag);
140 }
141 Change::Replace { from_id, to } => {
142 match self.graph.node_weight_mut(from_id.into()) {
143 None => {}
144 Some(x) => *x = Inaccessible::new(to.unwrap(from_id)),
145 };
146 }
147 Change::DeleteSelf { node_id } => {
148 self.graph.remove_node(node_id.into());
149 }
150 };
151 }
152 }
153
154 impl<U> SyntaxTree<U> {
155 pub(crate) fn children_of_raw<T>(
156 &self,
157 id: NodeId<T>,
158 tag: ChildTag,
159 ) -> OptVec<&Inaccessible> {
160 self.graph
161 .children(id.into())
162 .filter(|it| self.graph[it.0].data == tag)
163 .map(|it| &self.graph[it.1])
164 .collect()
165 }
166
167 pub fn dfs(&self) -> DfsIter {
168 let mut roots = self.graph.externals(Direction::Incoming);
169 let (Some(start), None) = (roots.next(), roots.next()) else {
170 panic!("Syntax tree should have a root")
171 };
172
173 DfsIter::new(&self.graph, start)
174 }
175 }
176
177 impl SyntaxTree {
178 pub fn children_of<'b, T, U>(
179 &'b self,
180 id: NodeId<T>,
181 token: &'b PermTkn,
182 tag: ChildTag,
183 ) -> OptVec<&U>
184 where
185 AnyNode: ConvertibleToRef<U>,
186 {
187 self.graph
188 .children(id.into())
189 .filter(|it| self.graph[it.0].data == tag)
190 .filter_map(|it| self.graph[it.1].ro(token).try_as_ref())
191 .collect()
192 }
193
194 pub fn get<'b, T>(&'b self, id: NodeId<T>, token: &'b PermTkn) -> Option<&T>
195 where
196 AnyNode: ConvertibleToRef<T>,
197 {
198 let node_ref = self.graph.node_weight(id.into())?;
199 node_ref.ro(token).try_as_ref()
200 }
201
202 pub fn get_mut<'b, T>(&'b self, id: NodeId<T>, token: &'b mut PermTkn) -> Option<&mut T>
203 where
204 AnyNode: ConvertibleToMut<T>,
205 {
206 let node_ref = self.graph.node_weight(id.into())?;
207 node_ref.rw(token).try_as_mut()
208 }
209
210 pub fn parent_of<'a, T>(&'a self, id: NodeId<T>, token: &'a PermTkn) -> Option<&AnyNode> {
211 let mut parents = self.graph.parents(id.into());
212 if let (Some((_, parent_id)), None) = (parents.next(), parents.next()) {
213 Some(self.graph[parent_id].ro(token))
214 } else {
215 None
216 }
217 }
218
219 pub fn parent_of_mut<'a, T>(
220 &'a self,
221 id: NodeId<T>,
222 token: &'a mut PermTkn,
223 ) -> &mut T::Parent
224 where
225 T: NodeWithParent + Node,
226 AnyNode: ConvertibleToMut<T::Parent>,
227 {
228 let mut parents = self.graph.parents(id.into());
229 let (Some((_, parent_id)), None) = (parents.next(), parents.next()) else {
230 panic!(
231 "NodeWithParent contract violated: such kind of nodes should always have a parent"
232 )
233 };
234 let parent_ref = self.graph[parent_id].rw(token);
235 parent_ref.try_as_mut().expect("Node has wrong type")
236 }
237
238 pub fn apply_changes(self, changes: ChangeSet, token: &PermTkn) -> Self {
239 let mut this = self.modify(token);
240 for change in changes {
241 this.apply_change(change);
242 }
243 this.build()
244 }
245
246 fn modify(self, token: &PermTkn) -> SyntaxTree<ViewingAccess> {
247 SyntaxTree {
248 graph: self.graph,
249 stage: ViewingAccess(token),
250 }
251 }
252 }
253}
254
255mod utils {
256 use std::collections::VecDeque;
257 use std::iter::FusedIterator;
258
259 use kodept_core::structure::span::CodeHolder;
260 use slotgraph::{Key, NodeKey};
261 use slotgraph::export::NodeCount;
262
263 use crate::graph::{AnyNode, HasChildrenMarker, NodeId, SyntaxTree};
264 use crate::graph::nodes::Inaccessible;
265 use crate::graph::tags::ChildTag;
266 use crate::graph::tree::Graph;
267 use crate::graph::tree::stage::{CanAccess, FullAccess};
268 use crate::rlt_accessor::RLTFamily;
269 use crate::traits::{Linker, PopulateTree};
270 use crate::visit_side::VisitSide;
271
272 pub struct ChildScope<'arena, T, Stage = FullAccess> {
273 tree: &'arena mut SyntaxTree<Stage>,
274 id: Key<T>,
275 }
276
277 pub enum TraverseState {
278 DescendDeeper,
279 Exit,
280 }
281
282 pub struct DfsIter<'a> {
283 stack: VecDeque<(NodeKey, TraverseState)>,
284 edges_buffer: Vec<NodeKey>,
285 graph: &'a Graph,
286 }
287
288 impl<'arena> DfsIter<'arena> {
289 pub(super) fn new(graph: &'arena Graph, start: NodeKey) -> Self {
290 let mut stack = VecDeque::with_capacity(graph.node_count());
291 stack.push_back((start, TraverseState::DescendDeeper));
292
293 Self {
294 stack,
295 edges_buffer: vec![],
296 graph,
297 }
298 }
299 }
300
301 impl<'arena> Iterator for DfsIter<'arena> {
302 type Item = (&'arena Inaccessible, VisitSide);
303
304 fn next(&mut self) -> Option<Self::Item> {
305 let (next, descend) = self.stack.pop_back()?;
306 let current = self.graph.node_weight(next)?;
307 if matches!(descend, TraverseState::Exit) {
308 return Some((current, VisitSide::Exiting));
309 }
310
311 self.edges_buffer.clear();
312 self.edges_buffer
313 .extend(self.graph.children(next).map(|it| it.1));
314 self.edges_buffer.reverse();
315 let edges_iter = self.edges_buffer.iter();
316 if edges_iter.len() != 0 {
317 self.stack.push_back((next, TraverseState::Exit));
318 for child in edges_iter {
319 self.stack.push_back((*child, TraverseState::DescendDeeper));
320 }
321 Some((current, VisitSide::Entering))
322 } else {
323 Some((current, VisitSide::Leaf))
324 }
325 }
326
327 fn size_hint(&self) -> (usize, Option<usize>) {
328 (self.stack.len(), Some(self.graph.node_count() * 2))
329 }
330 }
331
332 impl FusedIterator for DfsIter<'_> {}
333
334 impl<'arena, T, S> ChildScope<'arena, T, S> {
335 pub(super) fn new(tree: &'arena mut SyntaxTree<S>, node_id: Key<T>) -> Self {
336 Self { tree, id: node_id }
337 }
338
339 fn add_child_by_ref<U, const TAG: ChildTag>(&mut self, child_id: NodeKey)
340 where
341 U: Into<AnyNode>,
342 T: HasChildrenMarker<U, TAG>,
343 {
344 self.tree.graph.add_edge(self.id.into(), child_id, TAG);
345 }
346
347 #[allow(private_bounds)]
348 pub fn with_rlt<U>(self, context: &mut impl Linker, rlt_node: &U) -> Self
349 where
350 U: Into<RLTFamily> + Clone,
351 T: Into<AnyNode>,
352 S: CanAccess,
353 {
354 let element = &self.tree.graph[NodeKey::from(self.id)];
355 let node = element.ro(self.tree.stage.tkn());
356
357 context.link(node, rlt_node);
358 self
359 }
360
361 pub fn id(&self) -> NodeId<T> {
362 self.id.into()
363 }
364 }
365
366 impl<T> ChildScope<'_, T, FullAccess> {
367 #[allow(private_bounds)]
368 pub fn with_children_from<'b, const TAG: ChildTag, U>(
369 mut self,
370 iter: impl IntoIterator<Item = &'b U>,
371 context: &mut (impl Linker + CodeHolder),
372 ) -> Self
373 where
374 T: HasChildrenMarker<U::Output, TAG>,
375 U: PopulateTree + 'b,
376 {
377 for item in iter {
378 let child_id = item.convert(self.tree, context);
379 self.add_child_by_ref(child_id.into());
380 }
381 self
382 }
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use crate::FileDecl;
389 use crate::graph::SyntaxTreeBuilder;
390
391 #[test]
392 fn test_tree_creation() {
393 let mut builder = SyntaxTreeBuilder::new();
394
395 let id = builder.add_node(FileDecl::uninit()).id();
396
397 let tree = builder.build();
398 let children = tree.children_of_raw(id, 0);
399
400 assert!(children.is_empty());
401 }
402}