@@ -65,6 +65,16 @@ struct SyntaxNodeData<'a> {
6565 id : SyntaxNodeId < ' a > ,
6666}
6767
68+ impl < ' db > SyntaxNodeData < ' db > {
69+ /// Gets the kind of the given node's parent if it exists.
70+ pub fn parent ( & self , db : & ' db dyn Database ) -> Option < SyntaxNode < ' db > > {
71+ match self . id ( db) {
72+ SyntaxNodeId :: Root ( _) => None ,
73+ SyntaxNodeId :: Child { parent, .. } => Some ( * parent) ,
74+ }
75+ }
76+ }
77+
6878impl < ' db > cairo_lang_debug:: DebugWithDb < ' db > for SyntaxNodeData < ' db > {
6979 type Db = dyn Database ;
7080 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > , db : & ' db Self :: Db ) -> std:: fmt:: Result {
@@ -82,57 +92,81 @@ impl<'db> cairo_lang_debug::DebugWithDb<'db> for SyntaxNodeData<'db> {
8292/// tracked functions to ensure uniqueness of SyntaxNodes.
8393/// Use `SyntaxNode::new_root` or `SyntaxNode::new_root_with_offset` to create root nodes.
8494#[ derive( Clone , Copy , PartialEq , Eq , Hash , salsa:: Update ) ]
85- pub struct SyntaxNode < ' a > ( SyntaxNodeData < ' a > ) ;
95+ pub struct SyntaxNode < ' a > {
96+ data : SyntaxNodeData < ' a > ,
97+ /// Cached parent data to avoid database lookups. None for root nodes.
98+ parent : Option < SyntaxNodeData < ' a > > ,
99+ }
86100
87101impl < ' db > std:: fmt:: Debug for SyntaxNode < ' db > {
88102 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
89- write ! ( f, "SyntaxNode({:x})" , self . 0 . as_id( ) . index( ) )
103+ write ! ( f, "SyntaxNode({:x})" , self . data . as_id( ) . index( ) )
90104 }
91105}
92106
93107impl < ' db > cairo_lang_debug:: DebugWithDb < ' db > for SyntaxNode < ' db > {
94108 type Db = dyn Database ;
95109 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > , db : & ' db Self :: Db ) -> std:: fmt:: Result {
96- self . 0 . fmt ( f, db)
110+ self . data . fmt ( f, db)
97111 }
98112}
99113
100114impl < ' db > SyntaxNode < ' db > {
101115 /// Get the offset of this syntax node from the beginning of the file.
102116 pub fn offset ( self , db : & ' db dyn Database ) -> TextOffset {
103- self . 0 . offset ( db)
117+ self . data . offset ( db)
104118 }
105119
106120 /// Get the parent syntax node, if any.
107121 pub fn parent ( self , db : & ' db dyn Database ) -> Option < SyntaxNode < ' db > > {
108- match self . 0 . id ( db) {
122+ match self . data . id ( db) {
109123 SyntaxNodeId :: Child { parent, .. } => Some ( * parent) ,
110124 SyntaxNodeId :: Root ( _) => None ,
111125 }
112126 }
113127
128+ /// Get the grandparent syntax node, if any.
129+ /// This uses a cached parent when available, avoiding some database lookups.
130+ pub fn grandparent ( self , db : & ' db dyn Database ) -> Option < SyntaxNode < ' db > > {
131+ self . parent ?. parent ( db)
132+ }
133+
134+ /// Check if this syntax node is the root of the syntax tree.
135+ pub fn is_root ( self ) -> bool {
136+ self . parent . is_none ( )
137+ }
138+
114139 /// Get the stable pointer for this syntax node.
115140 pub fn stable_ptr ( self , _db : & ' db dyn Database ) -> SyntaxStablePtrId < ' db > {
116141 SyntaxStablePtrId ( self )
117142 }
118143
119144 pub fn raw_id ( & self , db : & ' db dyn Database ) -> & ' db SyntaxNodeId < ' db > {
120- self . 0 . id ( db)
145+ self . data . id ( db)
121146 }
122147
123148 /// Get the key fields of this syntax node. These define the unique identifier of the node.
124149 pub fn key_fields ( self , db : & ' db dyn Database ) -> & ' db [ GreenId < ' db > ] {
125- match self . 0 . id ( db) {
150+ match self . data . id ( db) {
126151 SyntaxNodeId :: Child { key_fields, .. } => key_fields,
127152 SyntaxNodeId :: Root ( _) => & [ ] ,
128153 }
129154 }
130155
131156 /// Returns the file id of the file containing this node.
132157 pub fn file_id ( & self , db : & ' db dyn Database ) -> FileId < ' db > {
133- match self . 0 . id ( db) {
134- SyntaxNodeId :: Child { parent, .. } => parent. file_id ( db) ,
158+ // Use cached parent if available to avoid database lookup
159+ if let Some ( parent_data) = self . parent {
160+ return match parent_data. id ( db) {
161+ SyntaxNodeId :: Child { parent, .. } => parent. file_id ( db) ,
162+ SyntaxNodeId :: Root ( file_id) => * file_id,
163+ } ;
164+ }
165+ match self . data . id ( db) {
135166 SyntaxNodeId :: Root ( file_id) => * file_id,
167+ SyntaxNodeId :: Child { .. } => {
168+ unreachable ! ( "Parent already checked and found to not exist." )
169+ }
136170 }
137171 }
138172
@@ -142,18 +176,26 @@ impl<'db> SyntaxNode<'db> {
142176 /// n = 2: return the grand parent.
143177 /// And so on...
144178 /// Assumes that the `n`th parent exists. Panics otherwise.
145- pub fn nth_parent < ' r : ' db > ( & self , db : & ' r dyn Database , n : usize ) -> SyntaxNode < ' db > {
146- let mut ptr = * self ;
147- for _ in 0 ..n {
148- ptr = ptr. parent ( db) . unwrap_or_else ( || {
149- panic ! (
150- "N'th parent did not exist. File {} Offset {:?}" ,
151- self . file_id( db) . long( db) . full_path( db) ,
152- self . offset( db)
153- )
154- } ) ;
179+ pub fn nth_parent < ' r : ' db > ( & self , db : & ' r dyn Database , mut n : usize ) -> SyntaxNode < ' db > {
180+ let mut result = Some ( * self ) ;
181+ while let Some ( p) = result
182+ && n > 1
183+ {
184+ result = p. grandparent ( db) ;
185+ n -= 2 ;
155186 }
156- ptr
187+ if let Some ( p) = result
188+ && n == 1
189+ {
190+ result = p. parent ( db) ;
191+ }
192+ result. unwrap_or_else ( || {
193+ panic ! (
194+ "N'th parent did not exist. File {} Offset {:?}" ,
195+ self . file_id( db) . long( db) . full_path( db) ,
196+ self . offset( db)
197+ )
198+ } )
157199 }
158200}
159201
@@ -165,7 +207,12 @@ pub fn new_syntax_node<'db>(
165207 offset : TextOffset ,
166208 id : SyntaxNodeId < ' db > ,
167209) -> SyntaxNode < ' db > {
168- SyntaxNode ( SyntaxNodeData :: new ( db, green, offset, id) )
210+ let parent = match & id {
211+ SyntaxNodeId :: Child { parent, .. } => Some ( parent. data ) ,
212+ SyntaxNodeId :: Root ( _) => None ,
213+ } ;
214+ let data = SyntaxNodeData :: new ( db, green, offset, id) ;
215+ SyntaxNode { data, parent }
169216}
170217
171218// Construction methods
@@ -212,7 +259,7 @@ impl<'a> SyntaxNode<'a> {
212259
213260 /// Returns the green node of the syntax node.
214261 pub fn green_node ( & self , db : & ' a dyn Database ) -> & ' a GreenNode < ' a > {
215- self . 0 . green ( db) . long ( db)
262+ self . data . green ( db) . long ( db)
216263 }
217264
218265 /// Returns the span of the syntax node without trivia.
@@ -507,17 +554,17 @@ impl<'a> SyntaxNode<'a> {
507554
508555 /// Gets the kind of the given node's parent if it exists.
509556 pub fn parent_kind ( & self , db : & dyn Database ) -> Option < SyntaxKind > {
510- Some ( self . parent ( db) ? . kind ( db) )
557+ Some ( self . parent ? . green ( db) . long ( db) . kind )
511558 }
512559
513560 /// Gets the kind of the given node's grandparent if it exists.
514561 pub fn grandparent_kind ( & self , db : & dyn Database ) -> Option < SyntaxKind > {
515- Some ( self . parent ( db) ?. parent ( db) ? . kind ( db ) )
562+ self . parent ( db) ?. parent_kind ( db)
516563 }
517564
518565 /// Gets the kind of the given node's grandgrandparent if it exists.
519566 pub fn grandgrandparent_kind ( & self , db : & dyn Database ) -> Option < SyntaxKind > {
520- Some ( self . parent ( db) ?. parent ( db) ? . parent ( db ) ? . kind ( db ) )
567+ self . grandparent ( db) ?. parent_kind ( db)
521568 }
522569}
523570
0 commit comments