Skip to main content

meta_language/grammar/merge/
rename.rs

1//! Binding-aware renaming of grammar rules and restoring source names.
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use super::normalize::quote;
6use super::{GrammarRenameError, GrammarRenameErrorKind, RenamedGrammar, RuleAlias};
7use crate::grammar::{
8    FeatureExpr, Grammar, GrammarDeclarations, GrammarExpr, GrammarMacro, GrammarRule,
9    GrammarScanner, Operation, PrecedenceEntry,
10};
11
12/// Renames one rule and every reference to it.
13///
14/// Recursive references, references inside captures and references qualified
15/// with `namespace` (as `namespace.rule` or `namespace::rule`) are renamed.
16/// Capture labels are a separate scope and are never renamed. The returned
17/// aliases map canonical names back to the original source names, so the
18/// grammar can be exported with them.
19pub fn rename_grammar_rule(
20    grammar: &Grammar,
21    from: &str,
22    to: &str,
23    namespace: Option<&str>,
24    aliases: &[RuleAlias],
25) -> Result<RenamedGrammar, GrammarRenameError> {
26    if to.is_empty() || to.chars().any(char::is_whitespace) {
27        return Err(GrammarRenameError::new(
28            GrammarRenameErrorKind::InvalidName,
29            format!("invalid rule name {}", quote(to)),
30        ));
31    }
32    if grammar.rule(from).is_none() {
33        return Err(GrammarRenameError::new(
34            GrammarRenameErrorKind::UnknownRule,
35            format!("grammar has no rule {from}"),
36        ));
37    }
38    if from == to {
39        return Ok(RenamedGrammar {
40            grammar: grammar.clone(),
41            aliases: aliases.to_vec(),
42        });
43    }
44    let mut mapping = vec![(from.to_owned(), to.to_owned())];
45    if let Some(namespace) = namespace {
46        mapping.push((format!("{namespace}.{from}"), format!("{namespace}.{to}")));
47        mapping.push((format!("{namespace}::{from}"), format!("{namespace}::{to}")));
48    }
49    let mut taken = grammar.referenced_nonterminals();
50    taken.extend(grammar.rules().iter().map(|rule| rule.name.clone()));
51    if let Some((_, target)) = mapping.iter().find(|(_, target)| taken.contains(target)) {
52        return Err(GrammarRenameError::new(
53            GrammarRenameErrorKind::Collision,
54            format!("renaming {from} to {to} would capture the existing name {target}"),
55        ));
56    }
57    let mut chained = false;
58    let mut next_aliases: Vec<RuleAlias> = aliases
59        .iter()
60        .map(|alias| {
61            if alias.canonical == from {
62                chained = true;
63                RuleAlias {
64                    canonical: to.to_owned(),
65                    original: alias.original.clone(),
66                }
67            } else {
68                alias.clone()
69            }
70        })
71        .collect();
72    if !chained {
73        next_aliases.push(RuleAlias {
74            canonical: to.to_owned(),
75            original: from.to_owned(),
76        });
77    }
78    Ok(RenamedGrammar {
79        grammar: rename_all(grammar, &mapping.into_iter().collect()),
80        aliases: next_aliases,
81    })
82}
83
84/// Renames canonical rule names back to their source names for export.
85pub fn restore_source_names(
86    grammar: &Grammar,
87    aliases: &[RuleAlias],
88    namespace: Option<&str>,
89) -> Result<Grammar, GrammarRenameError> {
90    let mut mapping = BTreeMap::new();
91    for RuleAlias {
92        canonical,
93        original,
94    } in aliases
95    {
96        if grammar.rule(canonical).is_none() || canonical == original {
97            continue;
98        }
99        mapping.insert(canonical.clone(), original.clone());
100        if let Some(namespace) = namespace {
101            mapping.insert(
102                format!("{namespace}.{canonical}"),
103                format!("{namespace}.{original}"),
104            );
105            mapping.insert(
106                format!("{namespace}::{canonical}"),
107                format!("{namespace}::{original}"),
108            );
109        }
110    }
111    let rename = |name: &str| {
112        mapping
113            .get(name)
114            .cloned()
115            .unwrap_or_else(|| name.to_owned())
116    };
117    let rule_names: Vec<String> = grammar
118        .rules()
119        .iter()
120        .map(|rule| rename(&rule.name))
121        .collect();
122    let unique: BTreeSet<&String> = rule_names.iter().collect();
123    let captured = grammar
124        .referenced_nonterminals()
125        .iter()
126        .filter(|name| grammar.rule(name).is_none())
127        .any(|name| rule_names.contains(&rename(name)));
128    if unique.len() != rule_names.len() || captured {
129        return Err(GrammarRenameError::new(
130            GrammarRenameErrorKind::Collision,
131            "restoring source names would give two bindings the same name",
132        ));
133    }
134    Ok(rename_all(grammar, &mapping))
135}
136
137/// Renames rules and every reference to them: in rule bodies, in rule
138/// actions and in the declarations (extras, conflict groups, macro bodies and
139/// scanner operations). Macro names, scanner names and tokens are separate
140/// scopes. A parameter is used through its own `(parameter name)` form,
141/// never through a reference, so renaming never touches it.
142fn rename_all(grammar: &Grammar, mapping: &BTreeMap<String, String>) -> Grammar {
143    let rename = |name: &str| {
144        mapping
145            .get(name)
146            .cloned()
147            .unwrap_or_else(|| name.to_owned())
148    };
149    let mut renamed = Grammar::new();
150    for rule in grammar.rules() {
151        renamed.add_rule(GrammarRule {
152            name: rename(&rule.name),
153            ..renamed_rule(rule, &rename)
154        });
155    }
156    if let Some(start) = grammar.start() {
157        renamed.set_start(rename(start));
158    }
159    renamed.source_format = grammar.source_format();
160    renamed.set_declarations(map_declarations(grammar.declarations(), &rename));
161    renamed
162}
163
164/// A rule with its body and action references renamed; its own name is kept.
165pub(super) fn renamed_rule(rule: &GrammarRule, rename: &dyn Fn(&str) -> String) -> GrammarRule {
166    let mut attributes = rule.attributes.clone();
167    if let Some(action) = &rule.attributes.action {
168        attributes.action = Some(map_operations(action, rename));
169    }
170    GrammarRule {
171        name: rule.name.clone(),
172        expr: map_references(&rule.expr, rename),
173        kind: rule.kind,
174        concept: rule.concept.clone(),
175        source_names: rule.source_names.clone(),
176        doc: rule.doc.clone(),
177        attributes,
178    }
179}
180
181/// The declarations with every rule reference renamed.
182pub(super) fn map_declarations(
183    declarations: &GrammarDeclarations,
184    rename: &dyn Fn(&str) -> String,
185) -> GrammarDeclarations {
186    GrammarDeclarations {
187        matching: declarations.matching.clone(),
188        settling: declarations.settling.clone(),
189        imports: declarations.imports.clone(),
190        modes: declarations.modes.clone(),
191        extras: declarations
192            .extras
193            .iter()
194            .map(|extra| map_references(extra, rename))
195            .collect(),
196        conflicts: declarations
197            .conflicts
198            .iter()
199            .map(|group| group.iter().map(|name| rename(name)).collect())
200            .collect(),
201        precedences: declarations
202            .precedences
203            .iter()
204            .map(|order| {
205                order
206                    .iter()
207                    .map(|entry| match entry {
208                        PrecedenceEntry::Rule(name) => PrecedenceEntry::Rule(rename(name)),
209                        PrecedenceEntry::Name(_) => entry.clone(),
210                    })
211                    .collect()
212            })
213            .collect(),
214        macros: declarations
215            .macros
216            .iter()
217            .map(|declared| GrammarMacro {
218                name: declared.name.clone(),
219                parameters: declared.parameters.clone(),
220                expression: map_references(&declared.expression, rename),
221            })
222            .collect(),
223        scanners: declarations
224            .scanners
225            .iter()
226            .map(|scanner| GrammarScanner {
227                name: scanner.name.clone(),
228                tokens: scanner.tokens.clone(),
229                operations: map_operations(&scanner.operations, rename),
230            })
231            .collect(),
232    }
233}
234
235/// Operations with every rule reference in their expressions renamed.
236pub(super) fn map_operations(
237    operations: &[Operation],
238    rename: &dyn Fn(&str) -> String,
239) -> Vec<Operation> {
240    operations
241        .iter()
242        .map(|operation| {
243            let mut copy = operation.clone();
244            copy.map_expressions(&mut |expr| *expr = map_references(expr, rename));
245            copy
246        })
247        .collect()
248}
249
250pub(super) fn map_references(expr: &GrammarExpr, rename: &dyn Fn(&str) -> String) -> GrammarExpr {
251    let map = |inner: &GrammarExpr| Box::new(map_references(inner, rename));
252    match expr {
253        GrammarExpr::NonTerminal(name) => GrammarExpr::NonTerminal(rename(name)),
254        GrammarExpr::Choice {
255            ordered,
256            alternatives,
257        } => GrammarExpr::Choice {
258            ordered: *ordered,
259            alternatives: alternatives
260                .iter()
261                .map(|item| map_references(item, rename))
262                .collect(),
263        },
264        GrammarExpr::Sequence(items) => GrammarExpr::Sequence(
265            items
266                .iter()
267                .map(|item| map_references(item, rename))
268                .collect(),
269        ),
270        GrammarExpr::Optional(inner) => GrammarExpr::Optional(map(inner)),
271        GrammarExpr::ZeroOrMore(inner) => GrammarExpr::ZeroOrMore(map(inner)),
272        GrammarExpr::OneOrMore(inner) => GrammarExpr::OneOrMore(map(inner)),
273        GrammarExpr::Repeat { expr, min, max } => GrammarExpr::Repeat {
274            expr: map(expr),
275            min: *min,
276            max: *max,
277        },
278        GrammarExpr::And(inner) => GrammarExpr::And(map(inner)),
279        GrammarExpr::Not(inner) => GrammarExpr::Not(map(inner)),
280        GrammarExpr::Capture { label, expr } => GrammarExpr::Capture {
281            label: label.clone(),
282            expr: map(expr),
283        },
284        GrammarExpr::Feature(feature) => {
285            let mut copy =
286                GrammarExpr::rewrite_feature(feature, |inner| map_references(inner, rename));
287            if let GrammarExpr::Feature(renamed) = &mut copy
288                && let FeatureExpr::Call { name, .. } = renamed.as_mut()
289            {
290                *name = rename(name);
291            }
292            copy
293        }
294        other => other.clone(),
295    }
296}