From 253003ccf8fdb6f35ce1a3acdeb13568cf75d492 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Fri, 29 Aug 2025 02:57:37 -0400 Subject: [PATCH] fix(generate): warn users when extra rule can lead to parser hang When a *named* rule in the extras is able to match the empty string, parsing can hang in certain situations (i.e. near EOF). (cherry picked from commit ac171eb2802ffc21c2a59ad84220c3e8d44f8647) --- cli/generate/src/parse_grammar.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cli/generate/src/parse_grammar.rs b/cli/generate/src/parse_grammar.rs index 18bee720..2dbf7701 100644 --- a/cli/generate/src/parse_grammar.rs +++ b/cli/generate/src/parse_grammar.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use anyhow::Result; +use regex::Regex; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use thiserror::Error; @@ -262,6 +263,27 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { }); continue; } + + if extra_symbols + .iter() + .any(|r| rule_is_referenced(r, name, false)) + { + let inner_rule = if let Rule::Metadata { rule, .. } = rule { + rule + } else { + rule + }; + let matches_empty = match inner_rule { + Rule::String(rule_str) => rule_str.is_empty(), + Rule::Pattern(ref value, _) => Regex::new(value) + .map(|reg| reg.is_match("")) + .unwrap_or(false), + _ => false, + }; + if matches_empty { + eprintln!("Warning: Named extra rule `{name}` matches the empty string. Inline this to avoid infinite loops while parsing."); + } + } variables.push(Variable { name: name.clone(), kind: VariableType::Named,