const GLEAM_RESERVED: &[&str] = &[
"as",
"assert",
"auto",
"case",
"const",
"delegate",
"derive",
"echo",
"else",
"fn",
"if",
"implement",
"import",
"let",
"macro",
"opaque",
"panic",
"pub",
"test",
"todo",
"type",
"use",
];
#[must_use]
pub(crate) fn is_snake_identifier(text: &str) -> bool {
let mut chars = text.chars();
let Some(first) = chars.next() else {
return false;
};
first.is_ascii_lowercase()
&& chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
}
#[must_use]
pub(crate) fn is_reserved_word(text: &str) -> bool {
GLEAM_RESERVED.contains(&text)
}
#[cfg(test)]
mod tests {
use super::{is_reserved_word, is_snake_identifier};
#[test]
fn snake_identifiers_are_classified() {
for valid in ["a", "reserve_inventory", "charge_payment", "a1", "x_2_y"] {
assert!(is_snake_identifier(valid), "{valid} should be valid");
}
for invalid in ["", "Reserve", "1a", "a-b", "_a", "a b", "naïve"] {
assert!(!is_snake_identifier(invalid), "{invalid} should be invalid");
}
}
#[test]
fn reserved_words_are_recognised() {
assert!(is_reserved_word("type"));
assert!(is_reserved_word("case"));
assert!(!is_reserved_word("reserve_inventory"));
}
}