Skip to content

Commit 2042607

Browse files
committed
Speed up native AST materialization
1 parent e815c2b commit 2042607

1 file changed

Lines changed: 106 additions & 24 deletions

File tree

  • packages/php-ext-wp-mysql-parser/src

packages/php-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.native_parser_node.new();
10991130
let rule_name = self
11001131
.grammar
@@ -1137,10 +1168,19 @@ impl NativeAstArena {
11371168
.ok_or_else(|| php_error("Native AST node index is out of range"))
11381169
}
11391170

1140-
fn child_to_zval(&self, native_ast_zval: &Zval, child: NativeAstChild) -> PhpResult<Zval> {
1171+
fn child_to_zval_with_classes(
1172+
&self,
1173+
native_ast_zval: &Zval,
1174+
child: NativeAstChild,
1175+
classes: &PhpClasses,
1176+
) -> PhpResult<Zval> {
11411177
match child {
1142-
NativeAstChild::Node(index) => self.create_php_node(native_ast_zval, index),
1143-
NativeAstChild::Token(index) => self.token_source.create_php_token(index),
1178+
NativeAstChild::Node(index) => {
1179+
self.create_php_node_with_classes(native_ast_zval, index, classes)
1180+
}
1181+
NativeAstChild::Token(index) => self
1182+
.token_source
1183+
.create_php_token_with_classes(index, classes),
11441184
}
11451185
}
11461186

@@ -1172,8 +1212,9 @@ impl NativeAstArena {
11721212
}
11731213

11741214
fn descendant_stack(&self, index: usize) -> PhpResult<Vec<NativeAstChild>> {
1175-
let mut stack = self.node(index)?.children.clone();
1176-
stack.reverse();
1215+
let node = self.node(index)?;
1216+
let mut stack = Vec::with_capacity(node.descendant_count);
1217+
stack.extend(node.children.iter().rev().copied());
11771218
Ok(stack)
11781219
}
11791220
}
@@ -1238,6 +1279,7 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child(
12381279
node_index: i64,
12391280
) -> PhpResult<Zval> {
12401281
let ast = native_ast(native_ast_zval)?;
1282+
let classes = php_classes()?;
12411283
let Some(child) = ast
12421284
.arena
12431285
.node(native_ast_node_index(node_index)?)?
@@ -1247,7 +1289,8 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child(
12471289
else {
12481290
return Ok(Zval::null());
12491291
};
1250-
ast.arena.child_to_zval(native_ast_zval, child)
1292+
ast.arena
1293+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
12511294
}
12521295

12531296
#[php_function]
@@ -1257,9 +1300,12 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child_node(
12571300
rule_name: Option<String>,
12581301
) -> PhpResult<Zval> {
12591302
let ast = native_ast(native_ast_zval)?;
1303+
let classes = php_classes()?;
12601304
for child in &ast.arena.node(native_ast_node_index(node_index)?)?.children {
12611305
if ast.arena.child_node_matches(*child, rule_name.as_deref()) {
1262-
return ast.arena.child_to_zval(native_ast_zval, *child);
1306+
return ast
1307+
.arena
1308+
.child_to_zval_with_classes(native_ast_zval, *child, &classes);
12631309
}
12641310
}
12651311
Ok(Zval::null())
@@ -1272,9 +1318,12 @@ pub fn wp_sqlite_mysql_native_ast_get_first_child_token(
12721318
token_id: Option<i64>,
12731319
) -> PhpResult<Zval> {
12741320
let ast = native_ast(native_ast_zval)?;
1321+
let classes = php_classes()?;
12751322
for child in &ast.arena.node(native_ast_node_index(node_index)?)?.children {
12761323
if ast.arena.child_token_matches(*child, token_id) {
1277-
return ast.arena.child_to_zval(native_ast_zval, *child);
1324+
return ast
1325+
.arena
1326+
.child_to_zval_with_classes(native_ast_zval, *child, &classes);
12781327
}
12791328
}
12801329
Ok(Zval::null())
@@ -1287,12 +1336,15 @@ pub fn wp_sqlite_mysql_native_ast_get_first_descendant_node(
12871336
rule_name: Option<String>,
12881337
) -> PhpResult<Zval> {
12891338
let ast = native_ast(native_ast_zval)?;
1339+
let classes = php_classes()?;
12901340
let mut stack = ast
12911341
.arena
12921342
.descendant_stack(native_ast_node_index(node_index)?)?;
12931343
while let Some(child) = stack.pop() {
12941344
if ast.arena.child_node_matches(child, rule_name.as_deref()) {
1295-
return ast.arena.child_to_zval(native_ast_zval, child);
1345+
return ast
1346+
.arena
1347+
.child_to_zval_with_classes(native_ast_zval, child, &classes);
12961348
}
12971349
if let NativeAstChild::Node(index) = child {
12981350
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1310,12 +1362,15 @@ pub fn wp_sqlite_mysql_native_ast_get_first_descendant_token(
13101362
token_id: Option<i64>,
13111363
) -> PhpResult<Zval> {
13121364
let ast = native_ast(native_ast_zval)?;
1365+
let classes = php_classes()?;
13131366
let mut stack = ast
13141367
.arena
13151368
.descendant_stack(native_ast_node_index(node_index)?)?;
13161369
while let Some(child) = stack.pop() {
13171370
if ast.arena.child_token_matches(child, token_id) {
1318-
return ast.arena.child_to_zval(native_ast_zval, child);
1371+
return ast
1372+
.arena
1373+
.child_to_zval_with_classes(native_ast_zval, child, &classes);
13191374
}
13201375
if let NativeAstChild::Node(index) = child {
13211376
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1332,12 +1387,16 @@ pub fn wp_sqlite_mysql_native_ast_get_children(
13321387
node_index: i64,
13331388
) -> PhpResult<Vec<Zval>> {
13341389
let ast = native_ast(native_ast_zval)?;
1390+
let classes = php_classes()?;
13351391
ast.arena
13361392
.node(native_ast_node_index(node_index)?)?
13371393
.children
13381394
.iter()
13391395
.copied()
1340-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1396+
.map(|child| {
1397+
ast.arena
1398+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1399+
})
13411400
.collect()
13421401
}
13431402

@@ -1348,13 +1407,17 @@ pub fn wp_sqlite_mysql_native_ast_get_child_nodes(
13481407
rule_name: Option<String>,
13491408
) -> PhpResult<Vec<Zval>> {
13501409
let ast = native_ast(native_ast_zval)?;
1410+
let classes = php_classes()?;
13511411
ast.arena
13521412
.node(native_ast_node_index(node_index)?)?
13531413
.children
13541414
.iter()
13551415
.copied()
13561416
.filter(|child| ast.arena.child_node_matches(*child, rule_name.as_deref()))
1357-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1417+
.map(|child| {
1418+
ast.arena
1419+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1420+
})
13581421
.collect()
13591422
}
13601423

@@ -1365,13 +1428,17 @@ pub fn wp_sqlite_mysql_native_ast_get_child_tokens(
13651428
token_id: Option<i64>,
13661429
) -> PhpResult<Vec<Zval>> {
13671430
let ast = native_ast(native_ast_zval)?;
1431+
let classes = php_classes()?;
13681432
ast.arena
13691433
.node(native_ast_node_index(node_index)?)?
13701434
.children
13711435
.iter()
13721436
.copied()
13731437
.filter(|child| ast.arena.child_token_matches(*child, token_id))
1374-
.map(|child| ast.arena.child_to_zval(native_ast_zval, child))
1438+
.map(|child| {
1439+
ast.arena
1440+
.child_to_zval_with_classes(native_ast_zval, child, &classes)
1441+
})
13751442
.collect()
13761443
}
13771444

@@ -1381,12 +1448,17 @@ pub fn wp_sqlite_mysql_native_ast_get_descendants(
13811448
node_index: i64,
13821449
) -> PhpResult<Vec<Zval>> {
13831450
let ast = native_ast(native_ast_zval)?;
1384-
let mut descendants = Vec::new();
1451+
let classes = php_classes()?;
1452+
let root = ast.arena.node(native_ast_node_index(node_index)?)?;
1453+
let mut descendants = Vec::with_capacity(root.descendant_count);
13851454
let mut stack = ast
13861455
.arena
13871456
.descendant_stack(native_ast_node_index(node_index)?)?;
13881457
while let Some(child) = stack.pop() {
1389-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1458+
descendants.push(
1459+
ast.arena
1460+
.child_to_zval_with_classes(native_ast_zval, child, &classes)?,
1461+
);
13901462
if let NativeAstChild::Node(index) = child {
13911463
for child in ast.arena.node(index)?.children.iter().rev() {
13921464
stack.push(*child);
@@ -1403,13 +1475,18 @@ pub fn wp_sqlite_mysql_native_ast_get_descendant_nodes(
14031475
rule_name: Option<String>,
14041476
) -> PhpResult<Vec<Zval>> {
14051477
let ast = native_ast(native_ast_zval)?;
1478+
let classes = php_classes()?;
14061479
let mut descendants = Vec::new();
14071480
let mut stack = ast
14081481
.arena
14091482
.descendant_stack(native_ast_node_index(node_index)?)?;
14101483
while let Some(child) = stack.pop() {
14111484
if ast.arena.child_node_matches(child, rule_name.as_deref()) {
1412-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1485+
descendants.push(ast.arena.child_to_zval_with_classes(
1486+
native_ast_zval,
1487+
child,
1488+
&classes,
1489+
)?);
14131490
}
14141491
if let NativeAstChild::Node(index) = child {
14151492
for child in ast.arena.node(index)?.children.iter().rev() {
@@ -1427,13 +1504,18 @@ pub fn wp_sqlite_mysql_native_ast_get_descendant_tokens(
14271504
token_id: Option<i64>,
14281505
) -> PhpResult<Vec<Zval>> {
14291506
let ast = native_ast(native_ast_zval)?;
1507+
let classes = php_classes()?;
14301508
let mut descendants = Vec::new();
14311509
let mut stack = ast
14321510
.arena
14331511
.descendant_stack(native_ast_node_index(node_index)?)?;
14341512
while let Some(child) = stack.pop() {
14351513
if ast.arena.child_token_matches(child, token_id) {
1436-
descendants.push(ast.arena.child_to_zval(native_ast_zval, child)?);
1514+
descendants.push(ast.arena.child_to_zval_with_classes(
1515+
native_ast_zval,
1516+
child,
1517+
&classes,
1518+
)?);
14371519
}
14381520
if let NativeAstChild::Node(index) = child {
14391521
for child in ast.arena.node(index)?.children.iter().rev() {

0 commit comments

Comments
 (0)