1111 * children are never materialized into PHP arrays unless something actually
1212 * asks for them.
1313 *
14- * Read methods eagerly call `materialize_native_children()` — once the
15- * children have been copied into PHP, `was_mutated()` returns true and the
16- * call falls through to the parent implementation. The `was_mutated` flag is
17- * NOT a runtime check for whether the native extension is loaded — if this
18- * class is in use, the extension is loaded by definition. It tracks whether
19- * THIS specific node has had its children pulled into the inherited
20- * `$children` array (which happens on first read or first mutation via
21- * `append_child()` / `merge_fragment()`). From that point on, the node is a
22- * plain PHP-backed `WP_Parser_Node`.
14+ * The hedge in those methods (`if ( $this->has_unmaterialized_native_ast() )`)
15+ * is NOT a runtime check for whether the native extension is loaded — if this
16+ * class is in use, the extension is loaded by definition. It checks whether
17+ * THIS specific node still has an authoritative native AST behind it. A node
18+ * loses its native backing the first time it is mutated from PHP via
19+ * `append_child()` or `merge_fragment()`: those overrides call
20+ * `materialize_native_children()`, which copies the native children into the
21+ * inherited `$children` array and then drops the native AST reference. From
22+ * that point on, the node is a plain PHP-backed `WP_Parser_Node` and the read
23+ * methods fall through to the parent implementation.
2324 *
2425 * Mutation from PHP is real and intentional — query rewriters in
2526 * `WP_PDO_MySQL_On_SQLite` (e.g. building synthetic `count(*)` expressions)
3031class WP_MySQL_Native_Parser_Node extends WP_Parser_Node {
3132 private $ native_ast = null ;
3233 private $ native_node_index = null ;
33- private $ was_mutated = false ;
3434
3535 public function __construct ( $ rule_id , $ rule_name , $ native_ast = null , $ native_node_index = null ) {
3636 parent ::__construct ( $ rule_id , $ rule_name );
@@ -67,113 +67,145 @@ public function merge_fragment( $node ) {
6767
6868 /** @inheritDoc */
6969 public function has_child (): bool {
70- $ this ->materialize_native_children ();
70+ if ( $ this ->has_unmaterialized_native_ast () ) {
71+ return wp_sqlite_mysql_native_ast_has_child ( $ this ->native_ast , $ this ->native_node_index );
72+ }
7173 return parent ::has_child ();
7274 }
7375
7476 /** @inheritDoc */
7577 public function has_child_node ( ?string $ rule_name = null ): bool {
76- $ this ->materialize_native_children ();
78+ if ( $ this ->has_unmaterialized_native_ast () ) {
79+ return wp_sqlite_mysql_native_ast_has_child_node ( $ this ->native_ast , $ this ->native_node_index , $ rule_name );
80+ }
7781 return parent ::has_child_node ( $ rule_name );
7882 }
7983
8084 /** @inheritDoc */
8185 public function has_child_token ( ?int $ token_id = null ): bool {
82- $ this ->materialize_native_children ();
86+ if ( $ this ->has_unmaterialized_native_ast () ) {
87+ return wp_sqlite_mysql_native_ast_has_child_token ( $ this ->native_ast , $ this ->native_node_index , $ token_id );
88+ }
8389 return parent ::has_child_token ( $ token_id );
8490 }
8591
8692 /** @inheritDoc */
8793 public function get_first_child () {
88- $ this ->materialize_native_children ();
94+ if ( $ this ->has_unmaterialized_native_ast () ) {
95+ return wp_sqlite_mysql_native_ast_get_first_child ( $ this ->native_ast , $ this ->native_node_index );
96+ }
8997 return parent ::get_first_child ();
9098 }
9199
92100 /** @inheritDoc */
93101 public function get_first_child_node ( ?string $ rule_name = null ): ?WP_Parser_Node {
94- $ this ->materialize_native_children ();
102+ if ( $ this ->has_unmaterialized_native_ast () ) {
103+ return wp_sqlite_mysql_native_ast_get_first_child_node ( $ this ->native_ast , $ this ->native_node_index , $ rule_name );
104+ }
95105 return parent ::get_first_child_node ( $ rule_name );
96106 }
97107
98108 /** @inheritDoc */
99109 public function get_first_child_token ( ?int $ token_id = null ): ?WP_Parser_Token {
100- $ this ->materialize_native_children ();
110+ if ( $ this ->has_unmaterialized_native_ast () ) {
111+ return wp_sqlite_mysql_native_ast_get_first_child_token ( $ this ->native_ast , $ this ->native_node_index , $ token_id );
112+ }
101113 return parent ::get_first_child_token ( $ token_id );
102114 }
103115
104116 /** @inheritDoc */
105117 public function get_first_descendant_node ( ?string $ rule_name = null ): ?WP_Parser_Node {
106- $ this ->materialize_native_children ();
118+ if ( $ this ->has_unmaterialized_native_ast () ) {
119+ return wp_sqlite_mysql_native_ast_get_first_descendant_node ( $ this ->native_ast , $ this ->native_node_index , $ rule_name );
120+ }
107121 return parent ::get_first_descendant_node ( $ rule_name );
108122 }
109123
110124 /** @inheritDoc */
111125 public function get_first_descendant_token ( ?int $ token_id = null ): ?WP_Parser_Token {
112- $ this ->materialize_native_children ();
126+ if ( $ this ->has_unmaterialized_native_ast () ) {
127+ return wp_sqlite_mysql_native_ast_get_first_descendant_token ( $ this ->native_ast , $ this ->native_node_index , $ token_id );
128+ }
113129 return parent ::get_first_descendant_token ( $ token_id );
114130 }
115131
116132 /** @inheritDoc */
117133 public function get_children (): array {
118- $ this ->materialize_native_children ();
134+ if ( $ this ->has_unmaterialized_native_ast () ) {
135+ return wp_sqlite_mysql_native_ast_get_children ( $ this ->native_ast , $ this ->native_node_index );
136+ }
119137 return parent ::get_children ();
120138 }
121139
122140 /** @inheritDoc */
123141 public function get_child_nodes ( ?string $ rule_name = null ): array {
124- $ this ->materialize_native_children ();
142+ if ( $ this ->has_unmaterialized_native_ast () ) {
143+ return wp_sqlite_mysql_native_ast_get_child_nodes ( $ this ->native_ast , $ this ->native_node_index , $ rule_name );
144+ }
125145 return parent ::get_child_nodes ( $ rule_name );
126146 }
127147
128148 /** @inheritDoc */
129149 public function get_child_tokens ( ?int $ token_id = null ): array {
130- $ this ->materialize_native_children ();
150+ if ( $ this ->has_unmaterialized_native_ast () ) {
151+ return wp_sqlite_mysql_native_ast_get_child_tokens ( $ this ->native_ast , $ this ->native_node_index , $ token_id );
152+ }
131153 return parent ::get_child_tokens ( $ token_id );
132154 }
133155
134156 /** @inheritDoc */
135157 public function get_descendants (): array {
136- $ this ->materialize_native_children ();
158+ if ( $ this ->has_unmaterialized_native_ast () ) {
159+ return wp_sqlite_mysql_native_ast_get_descendants ( $ this ->native_ast , $ this ->native_node_index );
160+ }
137161 return parent ::get_descendants ();
138162 }
139163
140164 /** @inheritDoc */
141165 public function get_descendant_nodes ( ?string $ rule_name = null ): array {
142- $ this ->materialize_native_children ();
166+ if ( $ this ->has_unmaterialized_native_ast () ) {
167+ return wp_sqlite_mysql_native_ast_get_descendant_nodes ( $ this ->native_ast , $ this ->native_node_index , $ rule_name );
168+ }
143169 return parent ::get_descendant_nodes ( $ rule_name );
144170 }
145171
146172 /** @inheritDoc */
147173 public function get_descendant_tokens ( ?int $ token_id = null ): array {
148- $ this ->materialize_native_children ();
174+ if ( $ this ->has_unmaterialized_native_ast () ) {
175+ return wp_sqlite_mysql_native_ast_get_descendant_tokens ( $ this ->native_ast , $ this ->native_node_index , $ token_id );
176+ }
149177 return parent ::get_descendant_tokens ( $ token_id );
150178 }
151179
152180 /** @inheritDoc */
153181 public function get_start (): int {
154- $ this ->materialize_native_children ();
182+ if ( $ this ->has_unmaterialized_native_ast () ) {
183+ return wp_sqlite_mysql_native_ast_get_start ( $ this ->native_ast , $ this ->native_node_index );
184+ }
155185 return parent ::get_start ();
156186 }
157187
158188 /** @inheritDoc */
159189 public function get_length (): int {
160- $ this ->materialize_native_children ();
190+ if ( $ this ->has_unmaterialized_native_ast () ) {
191+ return wp_sqlite_mysql_native_ast_get_length ( $ this ->native_ast , $ this ->native_node_index );
192+ }
161193 return parent ::get_length ();
162194 }
163195
164196 /**
165- * Indicates whether this node has been mutated from PHP .
197+ * Indicates whether this node still has an unmaterialized native AST .
166198 *
167- * Returns false for freshly-parsed nodes whose children still live in the
168- * Rust-owned AST buffer; returns true once `append_child()` or
169- * `merge_fragment()` has copied the children into the inherited
170- * `$children` array and dropped the native AST reference .
199+ * Returns true for freshly-parsed nodes whose children live in the
200+ * Rust-owned AST buffer; returns false once the node has been mutated and
201+ * its children copied into the inherited `$children` array (see
202+ * self::materialize_native_children()) .
171203 *
172204 * This is a per-instance state check, not a check for whether the native
173205 * extension is loaded.
174206 */
175- private function was_mutated (): bool {
176- return $ this ->was_mutated ;
207+ private function has_unmaterialized_native_ast (): bool {
208+ return null !== $ this ->native_ast ;
177209 }
178210
179211 /**
@@ -182,17 +214,16 @@ private function was_mutated(): bool {
182214 *
183215 * Called before any mutation (append_child, merge_fragment) so the node's
184216 * authoritative state lives in PHP from that point on. After this runs,
185- * was_mutated () returns true and read methods fall through to the parent
186- * WP_Parser_Node implementation.
217+ * has_unmaterialized_native_ast () returns false and read methods fall
218+ * through to the parent WP_Parser_Node implementation.
187219 */
188220 private function materialize_native_children (): void {
189- if ( $ this ->was_mutated ) {
221+ if ( ! $ this ->has_unmaterialized_native_ast () ) {
190222 return ;
191223 }
192224
193225 $ this ->children = wp_sqlite_mysql_native_ast_get_children ( $ this ->native_ast , $ this ->native_node_index );
194226 $ this ->native_ast = null ;
195227 $ this ->native_node_index = null ;
196- $ this ->was_mutated = true ;
197228 }
198229}
0 commit comments