Skip to content

Commit 23b1c02

Browse files
committed
Add lazy native parser node facade
When a native parser is in use, expose query results through a node class that defers child materialization until callers actually walk the tree. The base WP_Parser_Node::$children visibility is loosened to protected so the facade can populate it on demand.
1 parent 857fbec commit 23b1c02

3 files changed

Lines changed: 183 additions & 1 deletion

File tree

packages/mysql-on-sqlite/src/load.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
if ( class_exists( 'WP_MySQL_Native_Parser', false ) ) {
2929
require_once __DIR__ . '/mysql/native/mysql-rust-bridge.php';
30+
require_once __DIR__ . '/mysql/native/class-wp-mysql-native-parser-node.php';
3031
require_once __DIR__ . '/mysql/native/class-wp-mysql-parser.php';
3132
} else {
3233
require_once __DIR__ . '/mysql/class-wp-mysql-parser.php';
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<?php
2+
3+
/**
4+
* Parser node backed by a native (Rust) AST.
5+
*
6+
* Constructed by the native MySQL parser extension. Read methods delegate
7+
* into the Rust-owned AST so children are never copied into PHP unless a
8+
* caller actually walks the tree. On the first mutation (append_child or
9+
* merge_fragment), the node materializes its children into the inherited
10+
* `$children` array and behaves like a plain WP_Parser_Node from then on.
11+
*/
12+
class WP_MySQL_Native_Parser_Node extends WP_Parser_Node {
13+
private $native_ast = null;
14+
private $native_node_index = null;
15+
private $was_mutated = false;
16+
17+
public function __construct( $rule_id, $rule_name, $native_ast = null, $native_node_index = null ) {
18+
parent::__construct( $rule_id, $rule_name );
19+
20+
$this->native_ast = $native_ast;
21+
$this->native_node_index = $native_node_index;
22+
}
23+
24+
/** @inheritDoc */
25+
public function append_child( $node ) {
26+
$this->materialize_native_children();
27+
parent::append_child( $node );
28+
}
29+
30+
/** @inheritDoc */
31+
public function merge_fragment( $node ) {
32+
$this->materialize_native_children();
33+
if ( $node instanceof self ) {
34+
$node->materialize_native_children();
35+
}
36+
parent::merge_fragment( $node );
37+
}
38+
39+
/** @inheritDoc */
40+
public function has_child(): bool {
41+
if ( $this->was_mutated() ) {
42+
return parent::has_child();
43+
}
44+
return wp_sqlite_mysql_native_ast_has_child( $this->native_ast, $this->native_node_index );
45+
}
46+
47+
/** @inheritDoc */
48+
public function has_child_node( ?string $rule_name = null ): bool {
49+
if ( $this->was_mutated() ) {
50+
return parent::has_child_node( $rule_name );
51+
}
52+
return wp_sqlite_mysql_native_ast_has_child_node( $this->native_ast, $this->native_node_index, $rule_name );
53+
}
54+
55+
/** @inheritDoc */
56+
public function has_child_token( ?int $token_id = null ): bool {
57+
if ( $this->was_mutated() ) {
58+
return parent::has_child_token( $token_id );
59+
}
60+
return wp_sqlite_mysql_native_ast_has_child_token( $this->native_ast, $this->native_node_index, $token_id );
61+
}
62+
63+
/** @inheritDoc */
64+
public function get_first_child() {
65+
if ( $this->was_mutated() ) {
66+
return parent::get_first_child();
67+
}
68+
return wp_sqlite_mysql_native_ast_get_first_child( $this->native_ast, $this->native_node_index );
69+
}
70+
71+
/** @inheritDoc */
72+
public function get_first_child_node( ?string $rule_name = null ): ?WP_Parser_Node {
73+
if ( $this->was_mutated() ) {
74+
return parent::get_first_child_node( $rule_name );
75+
}
76+
return wp_sqlite_mysql_native_ast_get_first_child_node( $this->native_ast, $this->native_node_index, $rule_name );
77+
}
78+
79+
/** @inheritDoc */
80+
public function get_first_child_token( ?int $token_id = null ): ?WP_Parser_Token {
81+
if ( $this->was_mutated() ) {
82+
return parent::get_first_child_token( $token_id );
83+
}
84+
return wp_sqlite_mysql_native_ast_get_first_child_token( $this->native_ast, $this->native_node_index, $token_id );
85+
}
86+
87+
/** @inheritDoc */
88+
public function get_first_descendant_node( ?string $rule_name = null ): ?WP_Parser_Node {
89+
if ( $this->was_mutated() ) {
90+
return parent::get_first_descendant_node( $rule_name );
91+
}
92+
return wp_sqlite_mysql_native_ast_get_first_descendant_node( $this->native_ast, $this->native_node_index, $rule_name );
93+
}
94+
95+
/** @inheritDoc */
96+
public function get_first_descendant_token( ?int $token_id = null ): ?WP_Parser_Token {
97+
if ( $this->was_mutated() ) {
98+
return parent::get_first_descendant_token( $token_id );
99+
}
100+
return wp_sqlite_mysql_native_ast_get_first_descendant_token( $this->native_ast, $this->native_node_index, $token_id );
101+
}
102+
103+
/** @inheritDoc */
104+
public function get_children(): array {
105+
if ( $this->was_mutated() ) {
106+
return parent::get_children();
107+
}
108+
return wp_sqlite_mysql_native_ast_get_children( $this->native_ast, $this->native_node_index );
109+
}
110+
111+
/** @inheritDoc */
112+
public function get_child_nodes( ?string $rule_name = null ): array {
113+
if ( $this->was_mutated() ) {
114+
return parent::get_child_nodes( $rule_name );
115+
}
116+
return wp_sqlite_mysql_native_ast_get_child_nodes( $this->native_ast, $this->native_node_index, $rule_name );
117+
}
118+
119+
/** @inheritDoc */
120+
public function get_child_tokens( ?int $token_id = null ): array {
121+
if ( $this->was_mutated() ) {
122+
return parent::get_child_tokens( $token_id );
123+
}
124+
return wp_sqlite_mysql_native_ast_get_child_tokens( $this->native_ast, $this->native_node_index, $token_id );
125+
}
126+
127+
/** @inheritDoc */
128+
public function get_descendants(): array {
129+
if ( $this->was_mutated() ) {
130+
return parent::get_descendants();
131+
}
132+
return wp_sqlite_mysql_native_ast_get_descendants( $this->native_ast, $this->native_node_index );
133+
}
134+
135+
/** @inheritDoc */
136+
public function get_descendant_nodes( ?string $rule_name = null ): array {
137+
if ( $this->was_mutated() ) {
138+
return parent::get_descendant_nodes( $rule_name );
139+
}
140+
return wp_sqlite_mysql_native_ast_get_descendant_nodes( $this->native_ast, $this->native_node_index, $rule_name );
141+
}
142+
143+
/** @inheritDoc */
144+
public function get_descendant_tokens( ?int $token_id = null ): array {
145+
if ( $this->was_mutated() ) {
146+
return parent::get_descendant_tokens( $token_id );
147+
}
148+
return wp_sqlite_mysql_native_ast_get_descendant_tokens( $this->native_ast, $this->native_node_index, $token_id );
149+
}
150+
151+
/** @inheritDoc */
152+
public function get_start(): int {
153+
if ( $this->was_mutated() ) {
154+
return parent::get_start();
155+
}
156+
return wp_sqlite_mysql_native_ast_get_start( $this->native_ast, $this->native_node_index );
157+
}
158+
159+
/** @inheritDoc */
160+
public function get_length(): int {
161+
if ( $this->was_mutated() ) {
162+
return parent::get_length();
163+
}
164+
return wp_sqlite_mysql_native_ast_get_length( $this->native_ast, $this->native_node_index );
165+
}
166+
167+
private function was_mutated(): bool {
168+
return $this->was_mutated;
169+
}
170+
171+
private function materialize_native_children(): void {
172+
if ( $this->was_mutated ) {
173+
return;
174+
}
175+
176+
$this->children = wp_sqlite_mysql_native_ast_get_children( $this->native_ast, $this->native_node_index );
177+
$this->native_ast = null;
178+
$this->native_node_index = null;
179+
$this->was_mutated = true;
180+
}
181+
}

packages/mysql-on-sqlite/src/parser/class-wp-parser-node.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class WP_Parser_Node {
1515
*/
1616
public $rule_id;
1717
public $rule_name;
18-
private $children = array();
18+
protected $children = array();
1919

2020
public function __construct( $rule_id, $rule_name ) {
2121
$this->rule_id = $rule_id;

0 commit comments

Comments
 (0)