use super::{GeneratedDelimiter, GeneratedToken};
use crate::bounded::Overflow;
#[must_use]
pub fn rendered_identifier(spelling: &str) -> bool {
let mut characters = spelling.chars();
let Some(head) = characters.next() else {
return false;
};
if !head.is_ascii_alphabetic() && head != '_' {
return false;
}
if spelling == "_" {
return false;
}
characters.all(|character| character.is_ascii_alphanumeric() || character == '_')
}
#[must_use]
pub fn rust_keyword(spelling: &str) -> bool {
matches!(
spelling,
"abstract"
| "as"
| "async"
| "await"
| "become"
| "box"
| "break"
| "const"
| "continue"
| "crate"
| "do"
| "dyn"
| "else"
| "enum"
| "extern"
| "false"
| "final"
| "fn"
| "for"
| "gen"
| "if"
| "impl"
| "in"
| "let"
| "loop"
| "macro"
| "match"
| "mod"
| "move"
| "mut"
| "override"
| "priv"
| "pub"
| "ref"
| "return"
| "self"
| "Self"
| "static"
| "struct"
| "super"
| "trait"
| "true"
| "try"
| "type"
| "typeof"
| "unsafe"
| "unsized"
| "use"
| "virtual"
| "where"
| "while"
| "yield"
)
}
#[must_use]
pub fn rendered_name(spelling: &str) -> bool {
rendered_identifier(spelling) && !rust_keyword(spelling)
}
pub fn group(
delimiter: GeneratedDelimiter,
tokens: Vec<GeneratedToken>,
) -> Result<GeneratedToken, Overflow> {
GeneratedToken::group(delimiter, tokens)
}
#[must_use]
pub fn metavariable(name: &str) -> Vec<GeneratedToken> {
vec![GeneratedToken::joint('$'), GeneratedToken::word(name)]
}
#[must_use]
pub fn absolute_path(segments: &[&str]) -> Vec<GeneratedToken> {
let mut tokens = Vec::new();
extend_path(&mut tokens, segments);
tokens
}
#[must_use]
pub fn bound_path(root: &str, segments: &[&str]) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::word(root)];
extend_path(&mut tokens, segments);
tokens
}
#[must_use]
pub fn twin_path(binding: &str, segments: &[&str]) -> Vec<GeneratedToken> {
let mut tokens = metavariable(binding);
extend_path(&mut tokens, segments);
tokens
}
#[must_use]
pub(crate) fn segmented_twin_path(
root_binding: &str,
segment_binding: &str,
segments: &[&str],
) -> Vec<GeneratedToken> {
let mut tokens = metavariable(root_binding);
tokens.push(GeneratedToken::joint('$'));
tokens.push(GeneratedToken::fixed_group(
GeneratedDelimiter::Parenthesis,
[
GeneratedToken::joint(':'),
GeneratedToken::alone(':'),
GeneratedToken::joint('$'),
GeneratedToken::word(segment_binding),
],
));
tokens.push(GeneratedToken::alone('*'));
extend_path(&mut tokens, segments);
tokens
}
fn extend_path(tokens: &mut Vec<GeneratedToken>, segments: &[&str]) {
for segment in segments {
tokens.push(GeneratedToken::joint(':'));
tokens.push(GeneratedToken::alone(':'));
tokens.push(GeneratedToken::word(segment));
}
}
pub fn call(
mut path: Vec<GeneratedToken>,
arguments: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
path.push(group(GeneratedDelimiter::Parenthesis, arguments)?);
Ok(path)
}
pub fn method_call(
mut receiver: Vec<GeneratedToken>,
method: &str,
arguments: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
receiver.push(GeneratedToken::alone('.'));
receiver.push(GeneratedToken::word(method));
call(receiver, arguments)
}
pub fn method_chain(
mut receiver: Vec<GeneratedToken>,
methods: &[&str],
) -> Result<Vec<GeneratedToken>, Overflow> {
for method in methods {
receiver = method_call(receiver, method, Vec::new())?;
}
Ok(receiver)
}
#[must_use]
pub fn bound_local(name: &str, expression: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
let mut tokens = vec![
GeneratedToken::word("let"),
GeneratedToken::word(name),
GeneratedToken::alone('='),
];
tokens.extend(expression);
tokens.push(GeneratedToken::alone(';'));
tokens
}
#[must_use]
pub fn result_type(ok: Vec<GeneratedToken>, error: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
let mut tokens = absolute_path(&["core", "result", "Result"]);
tokens.push(GeneratedToken::alone('<'));
tokens.extend(ok);
tokens.push(GeneratedToken::alone(','));
tokens.extend(error);
tokens.push(GeneratedToken::alone('>'));
tokens
}
#[must_use]
pub fn constant(
name: &str,
kind: Vec<GeneratedToken>,
value: Vec<GeneratedToken>,
) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::word("const"), GeneratedToken::word(name)];
tokens.push(GeneratedToken::alone(':'));
tokens.extend(kind);
tokens.push(GeneratedToken::alone('='));
tokens.extend(value);
tokens.push(GeneratedToken::alone(';'));
tokens
}
pub fn function(
name: &str,
parameters: Vec<GeneratedToken>,
result: Vec<GeneratedToken>,
body: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = vec![
GeneratedToken::word("fn"),
GeneratedToken::word(name),
group(GeneratedDelimiter::Parenthesis, parameters)?,
GeneratedToken::joint('-'),
GeneratedToken::alone('>'),
];
tokens.extend(result);
tokens.push(group(GeneratedDelimiter::Brace, body)?);
Ok(tokens)
}
#[must_use]
pub fn equality(mut left: Vec<GeneratedToken>, right: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
left.push(GeneratedToken::joint('='));
left.push(GeneratedToken::alone('='));
left.extend(right);
left
}
#[must_use]
pub fn and_all(comparisons: Vec<Vec<GeneratedToken>>) -> Vec<GeneratedToken> {
let mut tokens = Vec::new();
for (position, comparison) in comparisons.into_iter().enumerate() {
if position > 0 {
tokens.push(GeneratedToken::joint('&'));
tokens.push(GeneratedToken::alone('&'));
}
tokens.extend(comparison);
}
tokens
}
#[must_use]
pub fn comma(mut left: Vec<GeneratedToken>, right: Vec<GeneratedToken>) -> Vec<GeneratedToken> {
left.push(GeneratedToken::alone(','));
left.extend(right);
left
}
#[must_use]
pub fn comma_many(parts: Vec<Vec<GeneratedToken>>) -> Vec<GeneratedToken> {
let mut tokens = Vec::new();
for (position, part) in parts.into_iter().enumerate() {
if position > 0 {
tokens.push(GeneratedToken::alone(','));
}
tokens.extend(part);
}
tokens
}
#[must_use]
pub fn text_pair(first: &str, second: &str) -> Vec<GeneratedToken> {
vec![
GeneratedToken::text(first),
GeneratedToken::alone(','),
GeneratedToken::text(second),
]
}
pub fn attribute(body: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
Ok(vec![
GeneratedToken::alone('#'),
group(GeneratedDelimiter::Bracket, body)?,
])
}
pub fn documentation(sentence: &str) -> Result<Vec<GeneratedToken>, Overflow> {
attribute(vec![
GeneratedToken::word("doc"),
GeneratedToken::alone('='),
GeneratedToken::text(sentence),
])
}
pub fn roster(items: Vec<GeneratedToken>) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = absolute_path(&["std", "vec"]);
tokens.push(GeneratedToken::alone('!'));
tokens.push(group(GeneratedDelimiter::Bracket, items)?);
Ok(tokens)
}