macroonz_compiler/token/generation/
compose.rs1use super::{GeneratedDelimiter, GeneratedToken};
10use crate::bounded::Overflow;
11
12#[must_use]
18pub fn rendered_identifier(spelling: &str) -> bool {
19 let mut characters = spelling.chars();
20 let Some(head) = characters.next() else {
21 return false;
22 };
23 if !head.is_ascii_alphabetic() && head != '_' {
24 return false;
25 }
26 if spelling == "_" {
27 return false;
28 }
29 characters.all(|character| character.is_ascii_alphanumeric() || character == '_')
30}
31
32#[must_use]
37pub fn rust_keyword(spelling: &str) -> bool {
38 matches!(
39 spelling,
40 "abstract"
41 | "as"
42 | "async"
43 | "await"
44 | "become"
45 | "box"
46 | "break"
47 | "const"
48 | "continue"
49 | "crate"
50 | "do"
51 | "dyn"
52 | "else"
53 | "enum"
54 | "extern"
55 | "false"
56 | "final"
57 | "fn"
58 | "for"
59 | "gen"
60 | "if"
61 | "impl"
62 | "in"
63 | "let"
64 | "loop"
65 | "macro"
66 | "match"
67 | "mod"
68 | "move"
69 | "mut"
70 | "override"
71 | "priv"
72 | "pub"
73 | "ref"
74 | "return"
75 | "self"
76 | "Self"
77 | "static"
78 | "struct"
79 | "super"
80 | "trait"
81 | "true"
82 | "try"
83 | "type"
84 | "typeof"
85 | "unsafe"
86 | "unsized"
87 | "use"
88 | "virtual"
89 | "where"
90 | "while"
91 | "yield"
92 )
93}
94
95#[must_use]
100pub fn rendered_name(spelling: &str) -> bool {
101 rendered_identifier(spelling) && !rust_keyword(spelling)
102}
103
104pub fn group(
110 delimiter: GeneratedDelimiter,
111 tokens: Vec<GeneratedToken>,
112) -> Result<GeneratedToken, Overflow> {
113 GeneratedToken::group(delimiter, tokens)
114}
115
116#[must_use]
120pub fn metavariable(name: &str) -> Vec<GeneratedToken> {
121 vec![GeneratedToken::joint('$'), GeneratedToken::word(name)]
122}
123
124#[must_use]
126pub fn absolute_path(segments: &[&str]) -> Vec<GeneratedToken> {
127 let mut tokens = Vec::new();
128 extend_path(&mut tokens, segments);
129 tokens
130}
131
132#[must_use]
136pub fn bound_path(root: &str, segments: &[&str]) -> Vec<GeneratedToken> {
137 let mut tokens = vec![GeneratedToken::word(root)];
138 extend_path(&mut tokens, segments);
139 tokens
140}
141
142#[must_use]
144pub fn twin_path(binding: &str, segments: &[&str]) -> Vec<GeneratedToken> {
145 let mut tokens = metavariable(binding);
146 extend_path(&mut tokens, segments);
147 tokens
148}
149
150#[must_use]
154pub(crate) fn segmented_twin_path(
155 root_binding: &str,
156 segment_binding: &str,
157 segments: &[&str],
158) -> Vec<GeneratedToken> {
159 let mut tokens = metavariable(root_binding);
160 tokens.push(GeneratedToken::joint('$'));
161 tokens.push(GeneratedToken::fixed_group(
162 GeneratedDelimiter::Parenthesis,
163 [
164 GeneratedToken::joint(':'),
165 GeneratedToken::alone(':'),
166 GeneratedToken::joint('$'),
167 GeneratedToken::word(segment_binding),
168 ],
169 ));
170 tokens.push(GeneratedToken::alone('*'));
171 extend_path(&mut tokens, segments);
172 tokens
173}
174
175fn extend_path(tokens: &mut Vec<GeneratedToken>, segments: &[&str]) {
177 for segment in segments {
178 tokens.push(GeneratedToken::joint(':'));
179 tokens.push(GeneratedToken::alone(':'));
180 tokens.push(GeneratedToken::word(segment));
181 }
182}
183
184pub fn call(
190 mut path: Vec<GeneratedToken>,
191 arguments: Vec<GeneratedToken>,
192) -> Result<Vec<GeneratedToken>, Overflow> {
193 path.push(group(GeneratedDelimiter::Parenthesis, arguments)?);
194 Ok(path)
195}
196
197pub fn method_call(
203 mut receiver: Vec<GeneratedToken>,
204 method: &str,
205 arguments: Vec<GeneratedToken>,
206) -> Result<Vec<GeneratedToken>, Overflow> {
207 receiver.push(GeneratedToken::alone('.'));
208 receiver.push(GeneratedToken::word(method));
209 call(receiver, arguments)
210}
211
212pub fn method_chain(
218 mut receiver: Vec<GeneratedToken>,
219 methods: &[&str],
220) -> Result<Vec<GeneratedToken>, Overflow> {
221 for method in methods {
222 receiver = method_call(receiver, method, Vec::new())?;
223 }
224 Ok(receiver)
225}
226
227#[must_use]
231pub fn bound_local(name: &str, expression: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
232 let mut tokens = vec![
233 GeneratedToken::word("let"),
234 GeneratedToken::word(name),
235 GeneratedToken::alone('='),
236 ];
237 tokens.extend(expression);
238 tokens.push(GeneratedToken::alone(';'));
239 tokens
240}
241
242#[must_use]
244pub fn result_type(ok: Vec<GeneratedToken>, error: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
245 let mut tokens = absolute_path(&["core", "result", "Result"]);
246 tokens.push(GeneratedToken::alone('<'));
247 tokens.extend(ok);
248 tokens.push(GeneratedToken::alone(','));
249 tokens.extend(error);
250 tokens.push(GeneratedToken::alone('>'));
251 tokens
252}
253
254#[must_use]
258pub fn constant(
259 name: &str,
260 kind: Vec<GeneratedToken>,
261 value: Vec<GeneratedToken>,
262) -> Vec<GeneratedToken> {
263 let mut tokens = vec![GeneratedToken::word("const"), GeneratedToken::word(name)];
264 tokens.push(GeneratedToken::alone(':'));
265 tokens.extend(kind);
266 tokens.push(GeneratedToken::alone('='));
267 tokens.extend(value);
268 tokens.push(GeneratedToken::alone(';'));
269 tokens
270}
271
272pub fn function(
280 name: &str,
281 parameters: Vec<GeneratedToken>,
282 result: Vec<GeneratedToken>,
283 body: Vec<GeneratedToken>,
284) -> Result<Vec<GeneratedToken>, Overflow> {
285 let mut tokens = vec![
286 GeneratedToken::word("fn"),
287 GeneratedToken::word(name),
288 group(GeneratedDelimiter::Parenthesis, parameters)?,
289 GeneratedToken::joint('-'),
290 GeneratedToken::alone('>'),
291 ];
292 tokens.extend(result);
293 tokens.push(group(GeneratedDelimiter::Brace, body)?);
294 Ok(tokens)
295}
296
297#[must_use]
299pub fn equality(mut left: Vec<GeneratedToken>, right: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
300 left.push(GeneratedToken::joint('='));
301 left.push(GeneratedToken::alone('='));
302 left.extend(right);
303 left
304}
305
306#[must_use]
308pub fn and_all(comparisons: Vec<Vec<GeneratedToken>>) -> Vec<GeneratedToken> {
309 let mut tokens = Vec::new();
310 for (position, comparison) in comparisons.into_iter().enumerate() {
311 if position > 0 {
312 tokens.push(GeneratedToken::joint('&'));
313 tokens.push(GeneratedToken::alone('&'));
314 }
315 tokens.extend(comparison);
316 }
317 tokens
318}
319
320#[must_use]
322pub fn comma(mut left: Vec<GeneratedToken>, right: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
323 left.push(GeneratedToken::alone(','));
324 left.extend(right);
325 left
326}
327
328#[must_use]
330pub fn comma_many(parts: Vec<Vec<GeneratedToken>>) -> Vec<GeneratedToken> {
331 let mut tokens = Vec::new();
332 for (position, part) in parts.into_iter().enumerate() {
333 if position > 0 {
334 tokens.push(GeneratedToken::alone(','));
335 }
336 tokens.extend(part);
337 }
338 tokens
339}
340
341#[must_use]
343pub fn text_pair(first: &str, second: &str) -> Vec<GeneratedToken> {
344 vec![
345 GeneratedToken::text(first),
346 GeneratedToken::alone(','),
347 GeneratedToken::text(second),
348 ]
349}
350
351pub fn attribute(body: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
357 Ok(vec![
358 GeneratedToken::alone('#'),
359 group(GeneratedDelimiter::Bracket, body)?,
360 ])
361}
362
363pub fn documentation(sentence: &str) -> Result<Vec<GeneratedToken>, Overflow> {
369 attribute(vec![
370 GeneratedToken::word("doc"),
371 GeneratedToken::alone('='),
372 GeneratedToken::text(sentence),
373 ])
374}
375
376pub fn roster(items: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
382 let mut tokens = absolute_path(&["std", "vec"]);
383 tokens.push(GeneratedToken::alone('!'));
384 tokens.push(group(GeneratedDelimiter::Bracket, items)?);
385 Ok(tokens)
386}