initial
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
class WP_MySQL_Lexer extends WP_MySQL_Native_Lexer {}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Parser node backed by a native (Rust) AST.
|
||||
*
|
||||
* Constructed by the native MySQL parser extension. Read methods delegate
|
||||
* into the Rust-owned AST so children are never copied into PHP unless a
|
||||
* caller actually walks the tree. On the first mutation (append_child or
|
||||
* merge_fragment), the node materializes its children into the inherited
|
||||
* `$children` array and behaves like a plain WP_Parser_Node from then on.
|
||||
*/
|
||||
class WP_MySQL_Native_Parser_Node extends WP_Parser_Node {
|
||||
private $was_mutated = false;
|
||||
|
||||
public function __construct( $rule_id, $rule_name ) {
|
||||
parent::__construct( $rule_id, $rule_name );
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if ( function_exists( 'wp_sqlite_mysql_native_ast_release_wrapper' ) ) {
|
||||
wp_sqlite_mysql_native_ast_release_wrapper( $this );
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function append_child( $node ) {
|
||||
$this->materialize_native_children();
|
||||
parent::append_child( $node );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function merge_fragment( $node ) {
|
||||
$this->materialize_native_children();
|
||||
if ( $node instanceof self ) {
|
||||
$node->materialize_native_children();
|
||||
}
|
||||
parent::merge_fragment( $node );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function has_child(): bool {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::has_child();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_has_child( $this );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function has_child_node( ?string $rule_name = null ): bool {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::has_child_node( $rule_name );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_has_child_node( $this, $rule_name );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function has_child_token( ?int $token_id = null ): bool {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::has_child_token( $token_id );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_has_child_token( $this, $token_id );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_first_child() {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_first_child();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_first_child( $this );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_first_child_node( ?string $rule_name = null ): ?WP_Parser_Node {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_first_child_node( $rule_name );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_first_child_node( $this, $rule_name );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_first_child_token( ?int $token_id = null ): ?WP_Parser_Token {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_first_child_token( $token_id );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_first_child_token( $this, $token_id );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_first_descendant_node( ?string $rule_name = null ): ?WP_Parser_Node {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_first_descendant_node( $rule_name );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_first_descendant_node( $this, $rule_name );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_first_descendant_token( ?int $token_id = null ): ?WP_Parser_Token {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_first_descendant_token( $token_id );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_first_descendant_token( $this, $token_id );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_children(): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_children();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_children( $this );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_child_nodes( ?string $rule_name = null ): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_child_nodes( $rule_name );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_child_nodes( $this, $rule_name );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_child_tokens( ?int $token_id = null ): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_child_tokens( $token_id );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_child_tokens( $this, $token_id );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_descendants(): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_descendants();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_descendants( $this );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_descendant_nodes( ?string $rule_name = null ): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_descendant_nodes( $rule_name );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_descendant_nodes( $this, $rule_name );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_descendant_tokens( ?int $token_id = null ): array {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_descendant_tokens( $token_id );
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_descendant_tokens( $this, $token_id );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_start(): int {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_start();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_start( $this );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function get_length(): int {
|
||||
if ( $this->was_mutated ) {
|
||||
return parent::get_length();
|
||||
}
|
||||
return wp_sqlite_mysql_native_ast_get_length( $this );
|
||||
}
|
||||
|
||||
private function materialize_native_children(): void {
|
||||
if ( $this->was_mutated ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->children = wp_sqlite_mysql_native_ast_get_children( $this );
|
||||
$this->was_mutated = true;
|
||||
if ( function_exists( 'wp_sqlite_mysql_native_ast_materialize_wrapper' ) ) {
|
||||
wp_sqlite_mysql_native_ast_materialize_wrapper( $this );
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Native-mode public parser entry point.
|
||||
*
|
||||
* Always extends the pure-PHP `WP_Parser` so `$parser instanceof WP_Parser`
|
||||
* keeps working for callers regardless of whether the Rust extension is
|
||||
* loaded. The actual parsing work is delegated to a composed
|
||||
* `WP_MySQL_Native_Parser` instance via the `WP_MySQL_Native_Parser_Impl`
|
||||
* trait — see that file for the per-method delegation.
|
||||
*/
|
||||
class WP_MySQL_Parser extends WP_Parser {
|
||||
use WP_MySQL_Native_Parser_Impl;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bridge helpers for the optional Rust MySQL lexer/parser extension.
|
||||
* PHP keeps the grammar object, while Rust owns the exported parser state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Export grammar internals for the native parser.
|
||||
*
|
||||
* @param WP_Parser_Grammar $grammar Parser grammar.
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function wp_sqlite_mysql_native_export_grammar( WP_Parser_Grammar $grammar ): array {
|
||||
return array(
|
||||
'highest_terminal_id' => $grammar->highest_terminal_id,
|
||||
'rules' => $grammar->rules,
|
||||
'lookahead_is_match_possible' => $grammar->lookahead_is_match_possible,
|
||||
'rule_names' => $grammar->rule_names,
|
||||
'fragment_ids' => $grammar->fragment_ids,
|
||||
);
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Native-mode `WP_MySQL_Parser` implementation, delivered as a trait.
|
||||
*
|
||||
* The class that uses this trait (`WP_MySQL_Parser` in native mode)
|
||||
* extends the pure-PHP `WP_Parser` so callers' `instanceof WP_Parser`
|
||||
* checks keep working, while the actual parsing work is delegated to
|
||||
* the Rust-registered `WP_MySQL_Native_Parser` instance held in
|
||||
* `$this->native`. `WP_Parser`'s state (`$grammar`, `$tokens`,
|
||||
* `$position`) stays inert in native mode — the trait's overrides
|
||||
* never read it.
|
||||
*
|
||||
* Adding a public method here is enough to plumb a new public method
|
||||
* through to the native parser; the using class does not need touching.
|
||||
*/
|
||||
trait WP_MySQL_Native_Parser_Impl {
|
||||
/**
|
||||
* @var WP_MySQL_Native_Parser
|
||||
*/
|
||||
private $native;
|
||||
|
||||
/**
|
||||
* @param WP_Parser_Grammar $grammar
|
||||
* @param array<WP_Parser_Token>|WP_MySQL_Native_Token_Stream $tokens
|
||||
*/
|
||||
public function __construct( WP_Parser_Grammar $grammar, $tokens ) {
|
||||
// WP_Parser's `array $tokens` constructor signature can't accept
|
||||
// the native token stream object; its `$this->tokens` /
|
||||
// `$this->position` state is inert in native mode anyway, so we
|
||||
// pass an empty array to satisfy the parent contract and keep
|
||||
// the actual tokens on the native parser.
|
||||
parent::__construct( $grammar, array() );
|
||||
$this->native = new WP_MySQL_Native_Parser( $grammar, $tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<WP_Parser_Token>|WP_MySQL_Native_Token_Stream $tokens
|
||||
*/
|
||||
public function reset_tokens( $tokens ): void {
|
||||
$this->native->reset_tokens( $tokens );
|
||||
}
|
||||
|
||||
public function next_query(): bool {
|
||||
return $this->native->next_query();
|
||||
}
|
||||
|
||||
public function get_query_ast(): ?WP_Parser_Node {
|
||||
return $this->native->get_query_ast();
|
||||
}
|
||||
|
||||
public function parse() {
|
||||
return $this->native->parse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user