1 use crate::{ 2 cow_mut::CowMut, 3 green::{node_cache::NodeCache, GreenElement, GreenNode, SyntaxKind}, 4 NodeOrToken, 5 }; 6 7 /// A checkpoint for maybe wrapping a node. See `GreenNodeBuilder::checkpoint` for details. 8 #[derive(Clone, Copy, Debug)] 9 pub struct Checkpoint(usize); 10 11 /// A builder for a green tree. 12 #[derive(Default, Debug)] 13 pub struct GreenNodeBuilder<'cache> { 14 cache: CowMut<'cache, NodeCache>, 15 parents: Vec<(SyntaxKind, usize)>, 16 children: Vec<(u64, GreenElement)>, 17 } 18 19 impl GreenNodeBuilder<'_> { 20 /// Creates new builder. new() -> GreenNodeBuilder<'static>21 pub fn new() -> GreenNodeBuilder<'static> { 22 GreenNodeBuilder::default() 23 } 24 25 /// Reusing `NodeCache` between different `GreenNodeBuilder`s saves memory. 26 /// It allows to structurally share underlying trees. with_cache(cache: &mut NodeCache) -> GreenNodeBuilder<'_>27 pub fn with_cache(cache: &mut NodeCache) -> GreenNodeBuilder<'_> { 28 GreenNodeBuilder { 29 cache: CowMut::Borrowed(cache), 30 parents: Vec::new(), 31 children: Vec::new(), 32 } 33 } 34 35 /// Adds new token to the current branch. 36 #[inline] token(&mut self, kind: SyntaxKind, text: &str)37 pub fn token(&mut self, kind: SyntaxKind, text: &str) { 38 let (hash, token) = self.cache.token(kind, text); 39 self.children.push((hash, token.into())); 40 } 41 42 /// Start new node and make it current. 43 #[inline] start_node(&mut self, kind: SyntaxKind)44 pub fn start_node(&mut self, kind: SyntaxKind) { 45 let len = self.children.len(); 46 self.parents.push((kind, len)); 47 } 48 49 /// Finish current branch and restore previous 50 /// branch as current. 51 #[inline] finish_node(&mut self)52 pub fn finish_node(&mut self) { 53 let (kind, first_child) = self.parents.pop().unwrap(); 54 let (hash, node) = self.cache.node(kind, &mut self.children, first_child); 55 self.children.push((hash, node.into())); 56 } 57 58 /// Prepare for maybe wrapping the next node. 59 /// The way wrapping works is that you first of all get a checkpoint, 60 /// then you place all tokens you want to wrap, and then *maybe* call 61 /// `start_node_at`. 62 /// Example: 63 /// ```rust 64 /// # use rowan::{GreenNodeBuilder, SyntaxKind}; 65 /// # const PLUS: SyntaxKind = SyntaxKind(0); 66 /// # const OPERATION: SyntaxKind = SyntaxKind(1); 67 /// # struct Parser; 68 /// # impl Parser { 69 /// # fn peek(&self) -> Option<SyntaxKind> { None } 70 /// # fn parse_expr(&mut self) {} 71 /// # } 72 /// # let mut builder = GreenNodeBuilder::new(); 73 /// # let mut parser = Parser; 74 /// let checkpoint = builder.checkpoint(); 75 /// parser.parse_expr(); 76 /// if parser.peek() == Some(PLUS) { 77 /// // 1 + 2 = Add(1, 2) 78 /// builder.start_node_at(checkpoint, OPERATION); 79 /// parser.parse_expr(); 80 /// builder.finish_node(); 81 /// } 82 /// ``` 83 #[inline] checkpoint(&self) -> Checkpoint84 pub fn checkpoint(&self) -> Checkpoint { 85 Checkpoint(self.children.len()) 86 } 87 88 /// Wrap the previous branch marked by `checkpoint` in a new branch and 89 /// make it current. 90 #[inline] start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind)91 pub fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) { 92 let Checkpoint(checkpoint) = checkpoint; 93 assert!( 94 checkpoint <= self.children.len(), 95 "checkpoint no longer valid, was finish_node called early?" 96 ); 97 98 if let Some(&(_, first_child)) = self.parents.last() { 99 assert!( 100 checkpoint >= first_child, 101 "checkpoint no longer valid, was an unmatched start_node_at called?" 102 ); 103 } 104 105 self.parents.push((kind, checkpoint)); 106 } 107 108 /// Complete tree building. Make sure that 109 /// `start_node_at` and `finish_node` calls 110 /// are paired! 111 #[inline] finish(mut self) -> GreenNode112 pub fn finish(mut self) -> GreenNode { 113 assert_eq!(self.children.len(), 1); 114 match self.children.pop().unwrap().1 { 115 NodeOrToken::Node(node) => node, 116 NodeOrToken::Token(_) => panic!(), 117 } 118 } 119 } 120