use crate::syntax_kind::SyntaxKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Profile {
Typl,
Ridl,
Rsdl,
}
const TYPL_KEYWORDS: &[(&str, SyntaxKind)] = &[
("package", SyntaxKind::PackageKw),
("import", SyntaxKind::ImportKw),
("as", SyntaxKind::AsKw),
("internal", SyntaxKind::InternalKw),
("type", SyntaxKind::TypeKw),
("const", SyntaxKind::ConstKw),
("struct", SyntaxKind::StructKw),
("enum", SyntaxKind::EnumKw),
("enumset", SyntaxKind::EnumsetKw),
("union", SyntaxKind::UnionKw),
("boolean", SyntaxKind::BooleanKw),
("integer", SyntaxKind::IntegerKw),
("float", SyntaxKind::FloatKw),
("string", SyntaxKind::StringKw),
("bytes", SyntaxKind::BytesKw),
("true", SyntaxKind::TrueKw),
("false", SyntaxKind::FalseKw),
("step", SyntaxKind::StepKw),
("match", SyntaxKind::MatchKw),
("reserved", SyntaxKind::ReservedKw),
("error", SyntaxKind::ErrorKw),
];
const RIDL_KEYWORDS: &[(&str, SyntaxKind)] = &[
("interface", SyntaxKind::InterfaceKw),
("service", SyntaxKind::ServiceKw),
("signal", SyntaxKind::SignalKw),
("event", SyntaxKind::EventKw),
("command", SyntaxKind::CommandKw),
("query", SyntaxKind::QueryKw),
("fixed", SyntaxKind::FixedKw),
("require", SyntaxKind::RequireKw),
("ensure", SyntaxKind::EnsureKw),
];
const RSDL_KEYWORDS: &[(&str, SyntaxKind)] = &[
("system", SyntaxKind::SystemKw),
("component", SyntaxKind::ComponentKw),
("distribution", SyntaxKind::DistributionKw),
("deployment", SyntaxKind::DeploymentKw),
("machine", SyntaxKind::MachineKw),
("offers", SyntaxKind::OffersKw),
("requires", SyntaxKind::RequiresKw),
("for", SyntaxKind::ForKw),
];
pub const FAMILY_RESERVED: &[&str] = &[
"package",
"import",
"as",
"internal",
"type",
"const",
"struct",
"enum",
"enumset",
"union",
"boolean",
"integer",
"float",
"string",
"bytes",
"true",
"false",
"step",
"match",
"reserved",
"error",
"interface",
"service",
"signal",
"event",
"command",
"query",
"fixed",
"view",
"display",
"input",
"action",
"activate",
"toggle",
"select",
"adjust",
"dismiss",
"fetch",
"states",
"during",
"navigate",
"scroll",
"drag",
"observe",
"surface",
"agent",
"require",
"ensure",
"model",
"function",
"let",
"init",
"last",
"case",
"if",
"then",
"else",
"when",
"emit",
"merge",
"current",
"state",
"transition",
"automaton",
"system",
"component",
"distribution",
"deployment",
"machine",
"offers",
"requires",
"for",
];
pub fn typl_keyword(text: &str) -> Option<SyntaxKind> {
TYPL_KEYWORDS
.iter()
.find(|(word, _)| *word == text)
.map(|(_, kind)| *kind)
}
pub fn ridl_keyword(text: &str) -> Option<SyntaxKind> {
RIDL_KEYWORDS
.iter()
.find(|(word, _)| *word == text)
.map(|(_, kind)| *kind)
}
pub fn rsdl_keyword(text: &str) -> Option<SyntaxKind> {
RSDL_KEYWORDS
.iter()
.find(|(word, _)| *word == text)
.map(|(_, kind)| *kind)
}
pub fn keyword_in(profile: Profile, text: &str) -> Option<SyntaxKind> {
match profile {
Profile::Typl => typl_keyword(text),
Profile::Ridl => typl_keyword(text).or_else(|| ridl_keyword(text)),
Profile::Rsdl => typl_keyword(text).or_else(|| rsdl_keyword(text)),
}
}
pub fn is_reserved(text: &str) -> bool {
FAMILY_RESERVED.contains(&text)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn family_registry_is_consistent() {
for (word, _) in TYPL_KEYWORDS
.iter()
.chain(RIDL_KEYWORDS)
.chain(RSDL_KEYWORDS)
{
assert!(
FAMILY_RESERVED.contains(word),
"used keyword `{word}` is missing from FAMILY_RESERVED",
);
}
for (word, _) in RIDL_KEYWORDS {
assert!(
typl_keyword(word).is_none(),
"`{word}` is in both TYPL_KEYWORDS and RIDL_KEYWORDS",
);
}
for (word, _) in RSDL_KEYWORDS {
assert!(
typl_keyword(word).is_none() && ridl_keyword(word).is_none(),
"`{word}` is in RSDL_KEYWORDS and in the typl or ridl table",
);
}
for (i, word) in FAMILY_RESERVED.iter().enumerate() {
assert!(
!FAMILY_RESERVED[..i].contains(word),
"duplicate registry word `{word}`",
);
}
}
#[test]
fn keyword_in_maps_per_profile() {
assert_eq!(keyword_in(Profile::Typl, "type"), Some(SyntaxKind::TypeKw));
assert_eq!(keyword_in(Profile::Ridl, "type"), Some(SyntaxKind::TypeKw));
assert_eq!(keyword_in(Profile::Typl, "signal"), None);
assert_eq!(
keyword_in(Profile::Ridl, "signal"),
Some(SyntaxKind::SignalKw)
);
assert_eq!(
keyword_in(Profile::Ridl, "ensure"),
Some(SyntaxKind::EnsureKw)
);
assert_eq!(keyword_in(Profile::Typl, "model"), None);
assert_eq!(keyword_in(Profile::Ridl, "model"), None);
assert_eq!(keyword_in(Profile::Ridl, "Speed"), None);
}
#[test]
fn used_keywords_map_to_their_kind() {
assert_eq!(typl_keyword("package"), Some(SyntaxKind::PackageKw));
assert_eq!(typl_keyword("enumset"), Some(SyntaxKind::EnumsetKw));
assert_eq!(typl_keyword("error"), Some(SyntaxKind::ErrorKw));
assert_eq!(typl_keyword("signal"), None);
assert_eq!(typl_keyword("Speed"), None);
}
#[test]
fn reserved_covers_used_and_unused() {
assert!(is_reserved("type")); assert!(is_reserved("signal")); assert!(is_reserved("model")); assert!(!is_reserved("Speed")); assert!(!is_reserved("node")); }
#[test]
fn fixed_is_an_active_ridl_keyword_and_final_is_not_reserved() {
assert_eq!(
keyword_in(Profile::Ridl, "fixed"),
Some(SyntaxKind::FixedKw),
"`fixed` is the provisioned-constant keyword in the ridl profile"
);
assert!(
!FAMILY_RESERVED.contains(&"final"),
"`final` was retired from the registry, the way `default` was"
);
}
}