diff --git a/cli/generate/src/parse_grammar.rs b/cli/generate/src/parse_grammar.rs index 2771d52e..2934d36b 100644 --- a/cli/generate/src/parse_grammar.rs +++ b/cli/generate/src/parse_grammar.rs @@ -110,8 +110,7 @@ fn rule_is_referenced(rule: &Rule, target: &str) -> bool { fn variable_is_used( grammar_rules: &[(String, Rule)], - extras: &[Rule], - externals: &[Rule], + other_rules: (&[Rule], &[Rule]), target_name: &str, in_progress: &mut HashSet, ) -> bool { @@ -120,9 +119,10 @@ fn variable_is_used( return true; } - if extras + if other_rules + .0 .iter() - .chain(externals.iter()) + .chain(other_rules.1.iter()) .any(|rule| rule_is_referenced(rule, target_name)) { return true; @@ -136,7 +136,7 @@ fn variable_is_used( if !rule_is_referenced(rule, target_name) || in_progress.contains(name) { return false; } - variable_is_used(grammar_rules, extras, externals, name, in_progress) + variable_is_used(grammar_rules, other_rules, name, in_progress) }); in_progress.remove(target_name); @@ -169,36 +169,6 @@ pub(crate) fn parse_grammar(input: &str) -> Result { .map(parse_rule) .collect::>(); - let mut variables = Vec::with_capacity(grammar_json.rules.len()); - - let rules = grammar_json - .rules - .into_iter() - .map(|(n, r)| Ok((n, parse_rule(serde_json::from_value(r)?)))) - .collect::>>()?; - - let mut in_progress = HashSet::new(); - - for (name, rule) in &rules { - if !variable_is_used( - &rules, - &extra_symbols, - &external_tokens, - name, - &mut in_progress, - ) { - extra_symbols.retain(|r| !rule_is_referenced(r, name)); - external_tokens.retain(|r| !rule_is_referenced(r, name)); - grammar_json.supertypes.retain(|r| r != name); - continue; - } - variables.push(Variable { - name: name.clone(), - kind: VariableType::Named, - rule: rule.clone(), - }); - } - let mut precedence_orderings = Vec::with_capacity(grammar_json.precedences.len()); for list in grammar_json.precedences { let mut ordering = Vec::with_capacity(list.len()); @@ -216,6 +186,46 @@ pub(crate) fn parse_grammar(input: &str) -> Result { precedence_orderings.push(ordering); } + let mut variables = Vec::with_capacity(grammar_json.rules.len()); + + let rules = grammar_json + .rules + .into_iter() + .map(|(n, r)| Ok((n, parse_rule(serde_json::from_value(r)?)))) + .collect::>>()?; + + let mut in_progress = HashSet::new(); + + for (name, rule) in &rules { + if !variable_is_used( + &rules, + (&extra_symbols, &external_tokens), + name, + &mut in_progress, + ) && grammar_json.word.as_ref().map_or(true, |w| w != name) + { + grammar_json.conflicts.retain(|r| !r.contains(name)); + grammar_json.supertypes.retain(|r| r != name); + grammar_json.inline.retain(|r| r != name); + extra_symbols.retain(|r| !rule_is_referenced(r, name)); + external_tokens.retain(|r| !rule_is_referenced(r, name)); + precedence_orderings.retain(|r| { + !r.iter().any(|e| { + let PrecedenceEntry::Symbol(s) = e else { + return false; + }; + s == name + }) + }); + continue; + } + variables.push(Variable { + name: name.clone(), + kind: VariableType::Named, + rule: rule.clone(), + }); + } + Ok(InputGrammar { name: grammar_json.name, word_token: grammar_json.word, diff --git a/cli/generate/src/prepare_grammar/intern_symbols.rs b/cli/generate/src/prepare_grammar/intern_symbols.rs index a96d0b5b..0941676d 100644 --- a/cli/generate/src/prepare_grammar/intern_symbols.rs +++ b/cli/generate/src/prepare_grammar/intern_symbols.rs @@ -40,22 +40,18 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> Result let mut supertype_symbols = Vec::with_capacity(grammar.supertype_symbols.len()); for supertype_symbol_name in &grammar.supertype_symbols { - supertype_symbols.push( - interner - .intern_name(supertype_symbol_name) - .ok_or_else(|| anyhow!("Undefined symbol `{supertype_symbol_name}`"))?, - ); + supertype_symbols.push(interner.intern_name(supertype_symbol_name).ok_or_else(|| { + anyhow!("Undefined symbol `{supertype_symbol_name}` in grammar's supertypes array") + })?); } let mut expected_conflicts = Vec::new(); for conflict in &grammar.expected_conflicts { let mut interned_conflict = Vec::with_capacity(conflict.len()); for name in conflict { - interned_conflict.push( - interner - .intern_name(name) - .ok_or_else(|| anyhow!("Undefined symbol `{name}`"))?, - ); + interned_conflict.push(interner.intern_name(name).ok_or_else(|| { + anyhow!("Undefined symbol `{name}` in grammar's conflicts array") + })?); } expected_conflicts.push(interned_conflict); } @@ -72,7 +68,7 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> Result word_token = Some( interner .intern_name(name) - .ok_or_else(|| anyhow!("Undefined symbol `{name}`"))?, + .ok_or_else(|| anyhow!("Undefined symbol `{name}` as grammar's word token"))?, ); }