From 52936490aaf274bd02b901fc197382aceb3b33bf Mon Sep 17 00:00:00 2001 From: Shugo Maeda Date: Tue, 28 Jul 2026 13:52:45 +0900 Subject: [PATCH] Avoid a quadratic walk when parsing long call chains parse_expression_terminator runs after every infix operator and called pm_block_call_p, which walks the whole receiver chain, even when the binding power alone already decided the result. Check the binding power first; pm_block_call_p is pure, so the condition is unchanged. Parsing "a" followed by 8000 ".b" links drops from 44.8ms to 0.46ms. Co-Authored-By: Claude Opus 5 --- src/prism.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/prism.c b/src/prism.c index 3b6b6f64fb..1f62ea5add 100644 --- a/src/prism.c +++ b/src/prism.c @@ -22403,11 +22403,7 @@ parse_expression_terminator(pm_parser_t *parser, pm_node_t *node) { // A block call (command with do-block, or any call chained // from one) can only be followed by call chaining (., ::, // &.), composition (and/or), and modifier operators. - if (pm_block_call_p(node)) { - return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL; - } - - return false; + return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node); } case PM_SUPER_NODE: case PM_YIELD_NODE: @@ -22419,10 +22415,7 @@ parse_expression_terminator(pm_parser_t *parser, pm_node_t *node) { /* A super carrying a do-block is a block call, so it may also be * followed by call chaining (`.`, `::`, `&.`). */ - if (pm_block_call_p(node)) { - return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL; - } - return false; + return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node); case PM_DEF_NODE: // An endless method whose body is a command-style call (e.g., // `def f = foo bar`) is a command assignment and can only be