1use 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
10pub 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
76pub 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#[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}