@@ -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. 
102116pub  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. 
107121pub  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. 
115140pub  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. 
124149pub  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. 
132157pub  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,22 @@ 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  ptr = Some ( * self ) ; 
181+         while  ptr. is_some ( )  && n > 1  { 
182+             ptr = ptr. and_then ( |p| p. grandparent ( db) ) ; 
183+             n -= 2 ; 
155184        } 
156-         ptr
185+         if  n == 1  { 
186+             ptr = ptr. and_then ( |p| p. parent ( db) ) ; 
187+         } 
188+         ptr. unwrap_or_else ( || { 
189+             panic ! ( 
190+                 "N'th parent did not exist. File {} Offset {:?}" , 
191+                 self . file_id( db) . long( db) . full_path( db) , 
192+                 self . offset( db) 
193+             ) 
194+         } ) 
157195    } 
158196} 
159197
@@ -165,7 +203,12 @@ pub fn new_syntax_node<'db>(
165203    offset :  TextOffset , 
166204    id :  SyntaxNodeId < ' db > , 
167205)  -> SyntaxNode < ' db >  { 
168-     SyntaxNode ( SyntaxNodeData :: new ( db,  green,  offset,  id) ) 
206+     let  parent = match  & id { 
207+         SyntaxNodeId :: Child  {  parent,  .. }  => Some ( parent. data ) , 
208+         SyntaxNodeId :: Root ( _)  => None , 
209+     } ; 
210+     let  data = SyntaxNodeData :: new ( db,  green,  offset,  id) ; 
211+     SyntaxNode  {  data,  parent } 
169212} 
170213
171214// Construction methods 
@@ -212,7 +255,7 @@ impl<'a> SyntaxNode<'a> {
212255
213256    /// Returns the green node of the syntax node. 
214257pub  fn  green_node ( & self ,  db :  & ' a  dyn  Database )  -> & ' a  GreenNode < ' a >  { 
215-         self . 0 . green ( db) . long ( db) 
258+         self . data . green ( db) . long ( db) 
216259    } 
217260
218261    /// Returns the span of the syntax node without trivia. 
@@ -507,17 +550,17 @@ impl<'a> SyntaxNode<'a> {
507550
508551    /// Gets the kind of the given node's parent if it exists. 
509552pub  fn  parent_kind ( & self ,  db :  & dyn  Database )  -> Option < SyntaxKind >  { 
510-         Some ( self . parent ( db) ? . kind ( db) ) 
553+         Some ( self . parent ? . green ( db) . long ( db) . kind ) 
511554    } 
512555
513556    /// Gets the kind of the given node's grandparent if it exists. 
514557pub  fn  grandparent_kind ( & self ,  db :  & dyn  Database )  -> Option < SyntaxKind >  { 
515-         Some ( self . parent ( db) ?. parent ( db) ? . kind ( db ) ) 
558+         self . parent ( db) ?. parent_kind ( db) 
516559    } 
517560
518561    /// Gets the kind of the given node's grandgrandparent if it exists. 
519562pub  fn  grandgrandparent_kind ( & self ,  db :  & dyn  Database )  -> Option < SyntaxKind >  { 
520-         Some ( self . parent ( db) ?. parent ( db) ? . parent ( db ) ? . kind ( db ) ) 
563+         self . grandparent ( db) ?. parent_kind ( db) 
521564    } 
522565} 
523566
0 commit comments