Skip to main content

meta_language/grammar/
decorators.rs

1//! The grammar and syntax tree levels of [`DecoratorSet`].
2
3use super::feature_runtime::SyntaxTree;
4use super::merge::rename_grammar_rule;
5use super::{Grammar, GrammarFormat, RuleKind};
6use crate::decorators::{
7    DecoratorError, DecoratorLevel, DecoratorRecord, DecoratorSet, decorator_record, record_field,
8};
9
10/// The grammar the `importer` or `grammar-rule` decorators of `decorators`
11/// make of `grammar`.
12///
13/// Each rule is shown as `{ name, kind, concept }`, with
14/// `format` (the grammar's source format) added at the `importer` level.
15/// Setting `name` renames the rule and every reference to it, setting `kind`
16/// or `concept` changes the rule, and `drop` removes it. The rules are
17/// decorated in grammar order; a grammar without decorators of the level is
18/// returned unchanged.
19///
20/// # Errors
21///
22/// A [`DecoratorError`] for an unknown rule kind or a rename the grammar
23/// refuses.
24pub fn decorate_grammar(
25    grammar: &Grammar,
26    decorators: &DecoratorSet,
27    level: DecoratorLevel,
28) -> Result<Grammar, DecoratorError> {
29    if !decorators.has(level) {
30        return Ok(grammar.clone());
31    }
32    let mut renames = Vec::new();
33    let mut rules = Vec::new();
34    for rule in grammar.rules() {
35        let mut record = DecoratorRecord::new();
36        record.insert("name".to_owned(), rule.name.clone());
37        record.insert("kind".to_owned(), rule.kind.as_str().to_owned());
38        record.insert(
39            "concept".to_owned(),
40            rule.concept.clone().unwrap_or_default(),
41        );
42        if level == DecoratorLevel::Importer {
43            let format = grammar.source_format().map_or("", GrammarFormat::as_str);
44            record.insert("format".to_owned(), format.to_owned());
45        }
46        let Some(decorated) = decorators.decorate(level, &record) else {
47            continue;
48        };
49        let mut rule = rule.clone();
50        let kind = record_field(&decorated, "kind");
51        rule.kind = RuleKind::from_tag(kind).ok_or_else(|| {
52            DecoratorError::new(format!("a decorator set the unknown rule kind {kind:?}"))
53        })?;
54        let concept = record_field(&decorated, "concept");
55        rule.concept = (!concept.is_empty()).then(|| concept.to_owned());
56        let name = record_field(&decorated, "name");
57        if name != rule.name {
58            renames.push((rule.name.clone(), name.to_owned()));
59        }
60        rules.push(rule);
61    }
62    let mut result = grammar.clone();
63    result.rules = rules;
64    for (from, to) in renames {
65        result = rename_grammar_rule(&result, &from, &to, None, &[])
66            .map_err(|error| DecoratorError::new(error.to_string()))?
67            .grammar;
68    }
69    Ok(result)
70}
71
72fn optional(text: &str) -> Option<String> {
73    (!text.is_empty()).then(|| text.to_owned())
74}
75
76/// The syntax tree the `executor` and `recovery` decorators of `decorators`
77/// make of `tree`.
78///
79/// The `executor` level shows every node and token as
80/// `{ type, kind, field, text }` (`text` for tokens): setting `kind` or
81/// `field` changes it, and `drop` replaces a node with its children, so the
82/// tree still holds every byte; a token cannot be dropped. The `recovery`
83/// level shows every ERROR node as `{ type, reason, text }` and every MISSING
84/// node as `{ type, kind }`: setting `reason` or `kind` changes it, and
85/// `drop` removes a MISSING node, which spans no input; an ERROR node cannot
86/// be dropped.
87///
88/// # Errors
89///
90/// A [`DecoratorError`] when a decorator drops a token, an ERROR node or the
91/// root.
92pub fn decorate_syntax_tree(
93    tree: &SyntaxTree,
94    decorators: &DecoratorSet,
95    source: &[u8],
96) -> Result<SyntaxTree, DecoratorError> {
97    if !decorators.has(DecoratorLevel::Executor) && !decorators.has(DecoratorLevel::Recovery) {
98        return Ok(tree.clone());
99    }
100    let mut roots = visit(tree, decorators, source)?;
101    if roots.len() != 1 {
102        return Err(DecoratorError::new(
103            "a decorator dropped the root of the syntax tree",
104        ));
105    }
106    Ok(roots.remove(0))
107}
108
109fn visit(
110    tree: &SyntaxTree,
111    decorators: &DecoratorSet,
112    source: &[u8],
113) -> Result<Vec<SyntaxTree>, DecoratorError> {
114    let text_of = |start: usize, end: usize| {
115        String::from_utf8_lossy(source.get(start..end).unwrap_or_default()).into_owned()
116    };
117    let mut copy = tree.clone();
118    match &mut copy {
119        SyntaxTree::Node {
120            kind,
121            field,
122            children,
123            ..
124        } => {
125            let mut record = DecoratorRecord::new();
126            record.insert("type".to_owned(), "node".to_owned());
127            record.insert("kind".to_owned(), kind.clone());
128            record.insert("field".to_owned(), field.clone().unwrap_or_default());
129            let decorated = decorators.decorate(DecoratorLevel::Executor, &record);
130            let mut visited = Vec::new();
131            for child in children.iter() {
132                visited.extend(visit(child, decorators, source)?);
133            }
134            let Some(decorated) = decorated else {
135                return Ok(visited);
136            };
137            record_field(&decorated, "kind").clone_into(kind);
138            *field = optional(record_field(&decorated, "field"));
139            *children = visited;
140        }
141        SyntaxTree::Token {
142            kind,
143            field,
144            start,
145            end,
146            ..
147        } => {
148            let mut record = DecoratorRecord::new();
149            record.insert("type".to_owned(), "token".to_owned());
150            record.insert("kind".to_owned(), kind.clone().unwrap_or_default());
151            record.insert("field".to_owned(), field.clone().unwrap_or_default());
152            record.insert("text".to_owned(), text_of(*start, *end));
153            let Some(decorated) = decorators.decorate(DecoratorLevel::Executor, &record) else {
154                return Err(DecoratorError::new(format!(
155                    "a decorator dropped the token {}; the executor level keeps every token",
156                    kind.as_deref().unwrap_or_default()
157                )));
158            };
159            *kind = optional(record_field(&decorated, "kind"));
160            *field = optional(record_field(&decorated, "field"));
161        }
162        SyntaxTree::Error {
163            start, end, reason, ..
164        } => {
165            let mut record = DecoratorRecord::new();
166            record.insert("type".to_owned(), "error".to_owned());
167            record.insert("reason".to_owned(), reason.clone().unwrap_or_default());
168            record.insert("text".to_owned(), text_of(*start, *end));
169            let Some(decorated) = decorators.decorate(DecoratorLevel::Recovery, &record) else {
170                return Err(DecoratorError::new(
171                    "a decorator dropped an ERROR node; only a MISSING node can be dropped",
172                ));
173            };
174            *reason = optional(record_field(&decorated, "reason"));
175        }
176        SyntaxTree::Missing { kind, .. } => {
177            let mut record = DecoratorRecord::new();
178            record.insert("type".to_owned(), "missing".to_owned());
179            record.insert("kind".to_owned(), kind.clone().unwrap_or_default());
180            let Some(decorated) = decorators.decorate(DecoratorLevel::Recovery, &record) else {
181                return Ok(Vec::new());
182            };
183            *kind = optional(record_field(&decorated, "kind"));
184        }
185        SyntaxTree::Embed { root, .. } => {
186            let mut roots = visit(root, decorators, source)?;
187            if roots.len() != 1 {
188                return Err(DecoratorError::new(
189                    "a decorator dropped the root of an embedded tree",
190                ));
191            }
192            **root = roots.remove(0);
193        }
194    }
195    Ok(vec![copy])
196}
197
198/// The emitted grammar `source` after the `emitter` decorators of
199/// `decorators`.
200///
201/// They see each line as `{ format, number, line }` (`number`
202/// counts from 1): setting `line` rewrites it and `drop` removes it. Apply it
203/// to the source an emitter such as [`super::emit_gbnf`] returns; the emit
204/// report is kept as it is.
205#[must_use]
206pub fn decorate_emitted(format: &str, source: &str, decorators: &DecoratorSet) -> String {
207    if !decorators.has(DecoratorLevel::Emitter) {
208        return source.to_owned();
209    }
210    let (body, ending) = source
211        .strip_suffix('\n')
212        .map_or((source, ""), |body| (body, "\n"));
213    let kept: Vec<String> = body
214        .split('\n')
215        .enumerate()
216        .filter_map(|(index, line)| {
217            let number = (index + 1).to_string();
218            let record = decorator_record([
219                ("format", format),
220                ("number", number.as_str()),
221                ("line", line),
222            ]);
223            decorators
224                .decorate(DecoratorLevel::Emitter, &record)
225                .map(|decorated| record_field(&decorated, "line").to_owned())
226        })
227        .collect();
228    if kept.is_empty() {
229        String::new()
230    } else {
231        format!("{}{ending}", kept.join("\n"))
232    }
233}