Skip to content

Commit 38ebab5

Browse files
committed
Speed up native AST materialization
1 parent a6f897d commit 38ebab5

1 file changed

Lines changed: 106 additions & 24 deletions

File tree

  • packages/mysql-on-sqlite/ext/wp-mysql-parser/src

packages/mysql-on-sqlite/ext/wp-mysql-parser/src/lib.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,19 @@ fn update_object_property(
9393
}
9494

9595
fn create_mysql_token(sql_zval: &Zval, token: TokenInfo, no_backslash: bool) -> PhpResult<Zval> {
96+
let classes = php_classes()?;
97+
create_mysql_token_with_classes(sql_zval, token, no_backslash, &classes)
98+
}
99+
100+
fn create_mysql_token_with_classes(
101+
sql_zval: &Zval,
102+
token: TokenInfo,
103+
no_backslash: bool,
104+
classes: &PhpClasses,
105+
) -> PhpResult<Zval> {
96106
let id = token.id;
97107
let start = i64::try_from(token.start).map_err(php_error)?;
98108
let length = i64::try_from(token.end.saturating_sub(token.start)).map_err(php_error)?;
99-
let classes = php_classes()?;
100109
let mut object = classes.mysql_token.new();
101110

102111
update_object_property(&mut object, classes.parser_token, "id", id)?;
@@ -940,7 +949,7 @@ enum ParserTokenSource {
940949
}
941950

942951
impl ParserTokenSource {
943-
fn create_php_token(&self, index: usize) -> PhpResult<Zval> {
952+
fn create_php_token_with_classes(&self, index: usize, classes: &PhpClasses) -> PhpResult<Zval> {
944953
match self {
945954
Self::Php(tokens) => tokens
946955
.get(index)
@@ -955,7 +964,7 @@ impl ParserTokenSource {
955964
.get(index)
956965
.copied()
957966
.ok_or_else(|| php_error("Parser token index is out of range"))?;
958-
create_mysql_token(sql_zval, token, *no_backslash)
967+
create_mysql_token_with_classes(sql_zval, token, *no_backslash, classes)
959968
}
960969
}
961970
}
@@ -1020,6 +1029,7 @@ struct NativeAstNode {
10201029
children: Vec<NativeAstChild>,
10211030
first_token: Option<usize>,
10221031
last_token: Option<usize>,
1032+
descendant_count: usize,
10231033
}
10241034

10251035
struct NativeAstArena {
@@ -1049,10 +1059,12 @@ impl NativeAstArena {
10491059
let index = self.nodes.len();
10501060
let mut first_token = None;
10511061
let mut last_token = None;
1062+
let mut descendant_count = 0;
10521063
for child in &children {
10531064
match child {
10541065
NativeAstChild::Node(child_index) => {
10551066
if let Some(node) = self.nodes.get(*child_index) {
1067+
descendant_count += 1 + node.descendant_count;
10561068
if first_token.is_none() {
10571069
first_token = node.first_token;
10581070
}
@@ -1066,6 +1078,7 @@ impl NativeAstArena {
10661078
first_token = Some(*token_index);
10671079
}
10681080
last_token = Some(*token_index);
1081+
descendant_count += 1;
10691082
}
10701083
}
10711084
}
@@ -1075,26 +1088,44 @@ impl NativeAstArena {
10751088
children,
10761089
first_token,
10771090
last_token,
1091+
descendant_count,
10781092
});
10791093
index
10801094
}
10811095

10821096
fn create_php_ast(&self, native_ast_zval: &Zval) -> PhpResult<Zval> {
1097+
let classes = php_classes()?;
1098+
self.create_php_ast_with_classes(native_ast_zval, &classes)
1099+
}
1100+
1101+
fn create_php_ast_with_classes(
1102+
&self,
1103+
native_ast_zval: &Zval,
1104+
classes: &PhpClasses,
1105+
) -> PhpResult<Zval> {
10831106
match self.root {
10841107
NativeAstRoot::No => Ok(Zval::null()),
10851108
NativeAstRoot::Empty => {
10861109
let mut zval = Zval::new();
10871110
zval.set_bool(true);
10881111
Ok(zval)
10891112
}
1090-
NativeAstRoot::Node(index) => self.create_php_node(native_ast_zval, index),
1091-
NativeAstRoot::Token(index) => self.token_source.create_php_token(index),
1113+
NativeAstRoot::Node(index) => {
1114+
self.create_php_node_with_classes(native_ast_zval, index, classes)
1115+
}
1116+
NativeAstRoot::Token(index) => self
1117+
.token_source
1118+
.create_php_token_with_classes(index, classes),
10921119
}
10931120
}
10941121

1095-
fn create_php_node(&self, native_ast_zval: &Zval, index: usize) -> PhpResult<Zval> {
1122+
fn create_php_node_with_classes(
1123+
&self,
1124+
native_ast_zval: &Zval,
1125+
index: usize,
1126+
classes: &PhpClasses,
1127+
) -> PhpResult<Zval> {
10961128
let node = self.node(index)?;
1097-
let classes = php_classes()?;
10981129
let mut object = classes.parser_node.new();
10991130
let rule_name = self
11001131
.grammar
@@ -1127,10 +1158,19 @@ impl NativeAstArena {
11271158
.ok_or_else(|| php_error("Native AST node index is out of range"))
11281159
}
11291160

1130-
fn child_to_zval(&self, native_ast_zval: &Zval, child: NativeAstChild) -> PhpResult<Zval> {
1161+
fn child_to_zval_with_classes(
1162+
&self,
1163+
native_ast_zval: &Zval,
1164+
child: NativeAstChild,
1165+
classes: &PhpClasses,
1166+
) -> PhpResult<Zval> {
11311167
match child {
1132-
NativeAstChild::Node(index) => self.create_php_node(native_ast_zval, index),
1133-
NativeAstChild::Token(index) => self.token_source.create_php_token(index),
1168+
NativeAstChild::Node(index) => {
1169+
self.create_php_node_with_classes(native_ast_zval, index, classes)
1170+
}
1171+
NativeAstChild::Token(index) => self
1172+
.token_source
1173+
.create_php_token_with_classes(index, classes),
11341174
}
11351175
}
11361176

@@ -1162,8 +1202,9 @@ impl NativeAstArena {
11621202
}
11631203

11641204
fn descendant_stack(&self, index: usize) -> PhpResult<Vec<NativeAstChild>> {
1165-
let mut stack = self.node(index)?.children.clone();
1166-
stack.reverse();
1205+
let node = self.node(index)?;
1206+
let mut stack = Vec::with_capacity(node.descendant_count);
1207+
stack.extend(node.children.iter().rev().copied());
11671208
Ok(stack)
11681209
}
11691210
}
@@ -1228,6 +1269,7 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child(
12281269
node_index: i64,
12291270
) -> PhpResult<Zval> {
12301271
let ast = native_ast(native_ast_zval)?;
1272+
let classes = php_classes()?;
12311273
let Some(child) = ast
12321274
.arena
12331275
.node(native_ast_node_index(node_index)?)?
@@ -1237,7 +1279,8 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child(
12371279
else {
12381280
return Ok(Zval::null());
12391281
};
1240-
ast.arena.child_to_zval(native_ast_zval, child)
1282+
ast.arena
1283+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
12411284
}
12421285

12431286
#[php_function]
@@ -1247,9 +1290,12 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child_node(
12471290
rule_name: Option<String>,
12481291
) -> PhpResult<Zval> {
12491292
let ast = native_ast(native_ast_zval)?;
1293+
let classes = php_classes()?;
12501294
for child in &ast.arena.node(native_ast_node_index(node_index)?)?.children {
12511295
if ast.arena.child_node_matches(*child, rule_name.as_deref()) {
1252-
return ast.arena.child_to_zval(native_ast_zval, *child);
1296+
return ast
1297+
.arena
1298+
.child_to_zval_with_classes(native_ast_zval, *child, &classes);
12531299
}
12541300
}
12551301
Ok(Zval::null())
@@ -1262,9 +1308,12 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child_token(
12621308
token_id: Option<i64>,
12631309
) -> PhpResult<Zval> {
12641310
let ast = native_ast(native_ast_zval)?;
1311+
let classes = php_classes()?;
12651312
for child in &ast.arena.node(native_ast_node_index(node_index)?)?.children {
12661313
if ast.arena.child_token_matches(*child, token_id) {
1267-
return ast.arena.child_to_zval(native_ast_zval, *child);
1314+
return ast
1315+
.arena
1316+
.child_to_zval_with_classes(native_ast_zval, *child, &classes);
12681317
}
12691318
}
12701319
Ok(Zval::null())
@@ -1277,12 +1326,15 @@ pub fn wp_sqlite_mysql_native_ast_get_first_descendant_node(
12771326
rule_name: Option<String>,
12781327
) -> PhpResult<Zval> {
12791328
let ast = native_ast(native_ast_zval)?;
1329+
let classes = php_classes()?;
12801330
let mut stack = ast
12811331
.arena
12821332
.descendant_stack(native_ast_node_index(node_index)?)?;
12831333
while let Some(child) = stack.pop() {
12841334
if ast.arena.child_node_matches(child, rule_name.as_deref()) {
1285-
return ast.arena.child_to_zval(native_ast_zval, child);
1335+
return ast
1336+
.arena
1337+
.child_to_zval_with_classes(native_ast_zval, child, &classes);
12861338
}
12871339
if let NativeAstChild::Node(index) = child {
12881340
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1300,12 +1352,15 @@ pub fn wp_sqlite_mysql_native_ast_get_first_descendant_token(
13001352
token_id: Option<i64>,
13011353
) -> PhpResult<Zval> {
13021354
let ast = native_ast(native_ast_zval)?;
1355+
let classes = php_classes()?;
13031356
let mut stack = ast
13041357
.arena
13051358
.descendant_stack(native_ast_node_index(node_index)?)?;
13061359
while let Some(child) = stack.pop() {
13071360
if ast.arena.child_token_matches(child, token_id) {
1308-
return ast.arena.child_to_zval(native_ast_zval, child);
1361+
return ast
1362+
.arena
1363+
.child_to_zval_with_classes(native_ast_zval, child, &classes);
13091364
}
13101365
if let NativeAstChild::Node(index) = child {
13111366
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1322,12 +1377,16 @@ pub fn wp_sqlite_mysql_native_ast_get_children(
13221377
node_index: i64,
13231378
) -> PhpResult<Vec<Zval>> {
13241379
let ast = native_ast(native_ast_zval)?;
1380+
let classes = php_classes()?;
13251381
ast.arena
13261382
.node(native_ast_node_index(node_index)?)?
13271383
.children
13281384
.iter()
13291385
.copied()
1330-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1386+
.map(|child| {
1387+
ast.arena
1388+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1389+
})
13311390
.collect()
13321391
}
13331392

@@ -1338,13 +1397,17 @@ pub fn wp_sqlite_mysql_native_ast_get_child_nodes(
13381397
rule_name: Option<String>,
13391398
) -> PhpResult<Vec<Zval>> {
13401399
let ast = native_ast(native_ast_zval)?;
1400+
let classes = php_classes()?;
13411401
ast.arena
13421402
.node(native_ast_node_index(node_index)?)?
13431403
.children
13441404
.iter()
13451405
.copied()
13461406
.filter(|child| ast.arena.child_node_matches(*child, rule_name.as_deref()))
1347-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1407+
.map(|child| {
1408+
ast.arena
1409+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1410+
})
13481411
.collect()
13491412
}
13501413

@@ -1355,13 +1418,17 @@ pub fn wp_sqlite_mysql_native_ast_get_child_tokens(
13551418
token_id: Option<i64>,
13561419
) -> PhpResult<Vec<Zval>> {
13571420
let ast = native_ast(native_ast_zval)?;
1421+
let classes = php_classes()?;
13581422
ast.arena
13591423
.node(native_ast_node_index(node_index)?)?
13601424
.children
13611425
.iter()
13621426
.copied()
13631427
.filter(|child| ast.arena.child_token_matches(*child, token_id))
1364-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1428+
.map(|child| {
1429+
ast.arena
1430+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1431+
})
13651432
.collect()
13661433
}
13671434

@@ -1371,12 +1438,17 @@ pub fn wp_sqlite_mysql_native_ast_get_descendants(
13711438
node_index: i64,
13721439
) -> PhpResult<Vec<Zval>> {
13731440
let ast = native_ast(native_ast_zval)?;
1374-
let mut descendants = Vec::new();
1441+
let classes = php_classes()?;
1442+
let root = ast.arena.node(native_ast_node_index(node_index)?)?;
1443+
let mut descendants = Vec::with_capacity(root.descendant_count);
13751444
let mut stack = ast
13761445
.arena
13771446
.descendant_stack(native_ast_node_index(node_index)?)?;
13781447
while let Some(child) = stack.pop() {
1379-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1448+
descendants.push(
1449+
ast.arena
1450+
.child_to_zval_with_classes(native_ast_zval, child, &classes)?,
1451+
);
13801452
if let NativeAstChild::Node(index) = child {
13811453
for child in ast.arena.node(index)?.children.iter().rev() {
13821454
stack.push(*child);
@@ -1393,13 +1465,18 @@ pub fn wp_sqlite_mysql_native_ast_get_descendant_nodes(
13931465
rule_name: Option<String>,
13941466
) -> PhpResult<Vec<Zval>> {
13951467
let ast = native_ast(native_ast_zval)?;
1468+
let classes = php_classes()?;
13961469
let mut descendants = Vec::new();
13971470
let mut stack = ast
13981471
.arena
13991472
.descendant_stack(native_ast_node_index(node_index)?)?;
14001473
while let Some(child) = stack.pop() {
14011474
if ast.arena.child_node_matches(child, rule_name.as_deref()) {
1402-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1475+
descendants.push(ast.arena.child_to_zval_with_classes(
1476+
native_ast_zval,
1477+
child,
1478+
&classes,
1479+
)?);
14031480
}
14041481
if let NativeAstChild::Node(index) = child {
14051482
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1417,13 +1494,18 @@ pub fn wp_sqlite_mysql_native_ast_get_descendant_tokens(
14171494
token_id: Option<i64>,
14181495
) -> PhpResult<Vec<Zval>> {
14191496
let ast = native_ast(native_ast_zval)?;
1497+
let classes = php_classes()?;
14201498
let mut descendants = Vec::new();
14211499
let mut stack = ast
14221500
.arena
14231501
.descendant_stack(native_ast_node_index(node_index)?)?;
14241502
while let Some(child) = stack.pop() {
14251503
if ast.arena.child_token_matches(child, token_id) {
1426-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1504+
descendants.push(ast.arena.child_to_zval_with_classes(
1505+
native_ast_zval,
1506+
child,
1507+
&classes,
1508+
)?);
14271509
}
14281510
if let NativeAstChild::Node(index) = child {
14291511
for child in ast.arena.node(index)?.children.iter().rev() {

0 commit comments

Comments
 (0)