2025-01-05 00:59:59 +09:00
|
|
|
use smol_str::{SmolStr, ToSmolStr};
|
2025-01-04 02:49:04 +09:00
|
|
|
|
2025-01-05 13:00:06 +09:00
|
|
|
type ParamName = &'static str;
|
|
|
|
|
|
2024-09-13 16:02:30 +09:00
|
|
|
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
|
|
|
|
pub enum Token {
|
|
|
|
|
/// Token used to represent a finished command (i.e. no more parameters required)
|
|
|
|
|
// todo: this is likely not the right way to represent this
|
|
|
|
|
Empty,
|
|
|
|
|
|
|
|
|
|
/// A bot-defined value ("member" in `pk;member MyName`)
|
2025-01-04 02:49:04 +09:00
|
|
|
Value(Vec<SmolStr>),
|
2024-09-13 16:02:30 +09:00
|
|
|
/// A command defined by multiple values
|
|
|
|
|
// todo!
|
2025-01-04 02:49:04 +09:00
|
|
|
MultiValue(Vec<Vec<SmolStr>>),
|
2024-09-13 16:02:30 +09:00
|
|
|
|
2025-01-05 13:00:06 +09:00
|
|
|
FullString(ParamName),
|
2024-09-13 16:02:30 +09:00
|
|
|
|
|
|
|
|
/// Member reference (hid or member name)
|
2025-01-05 13:00:06 +09:00
|
|
|
MemberRef(ParamName),
|
|
|
|
|
MemberPrivacyTarget(ParamName),
|
2024-09-13 16:02:30 +09:00
|
|
|
|
2025-01-05 02:21:23 +09:00
|
|
|
/// System reference
|
2025-01-05 13:00:06 +09:00
|
|
|
SystemRef(ParamName),
|
2025-01-05 02:21:23 +09:00
|
|
|
|
2025-01-05 13:00:06 +09:00
|
|
|
PrivacyLevel(ParamName),
|
2024-09-13 16:02:30 +09:00
|
|
|
|
|
|
|
|
// currently not included in command definitions
|
|
|
|
|
// todo: flags with values
|
|
|
|
|
Flag,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum TokenMatchResult {
|
|
|
|
|
NoMatch,
|
|
|
|
|
/// Token matched, optionally with a value.
|
2025-01-04 02:49:04 +09:00
|
|
|
Match(Option<SmolStr>),
|
2025-01-05 13:00:06 +09:00
|
|
|
MissingParameter {
|
|
|
|
|
name: ParamName,
|
|
|
|
|
},
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// move this somewhere else
|
2025-01-05 02:21:23 +09:00
|
|
|
const MEMBER_PRIVACY_TARGETS: &[&str] = &["visibility", "name", "todo"];
|
2024-09-13 16:02:30 +09:00
|
|
|
|
|
|
|
|
impl Token {
|
2025-01-04 02:49:04 +09:00
|
|
|
pub fn try_match(&self, input: Option<SmolStr>) -> TokenMatchResult {
|
2024-09-13 16:02:30 +09:00
|
|
|
// short circuit on empty things
|
|
|
|
|
if matches!(self, Self::Empty) && input.is_none() {
|
|
|
|
|
return TokenMatchResult::Match(None);
|
|
|
|
|
} else if input.is_none() {
|
2025-01-05 13:00:06 +09:00
|
|
|
return match self {
|
|
|
|
|
Self::FullString(param_name) => TokenMatchResult::MissingParameter { name: param_name },
|
|
|
|
|
Self::MemberRef(param_name) => TokenMatchResult::MissingParameter { name: param_name },
|
|
|
|
|
Self::MemberPrivacyTarget(param_name) => TokenMatchResult::MissingParameter { name: param_name },
|
|
|
|
|
Self::SystemRef(param_name) => TokenMatchResult::MissingParameter { name: param_name },
|
|
|
|
|
Self::PrivacyLevel(param_name) => TokenMatchResult::MissingParameter { name: param_name },
|
|
|
|
|
_ => TokenMatchResult::NoMatch,
|
|
|
|
|
}
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
|
2025-01-05 13:00:06 +09:00
|
|
|
let input = input.as_ref().map(|s| s.trim()).unwrap();
|
2024-09-13 16:02:30 +09:00
|
|
|
|
|
|
|
|
// try actually matching stuff
|
|
|
|
|
match self {
|
|
|
|
|
Self::Empty => return TokenMatchResult::NoMatch,
|
|
|
|
|
Self::Flag => unreachable!(), // matched upstream
|
2025-01-05 13:00:06 +09:00
|
|
|
Self::Value(values) if values.iter().any(|v| v.eq(input)) => {
|
|
|
|
|
return TokenMatchResult::Match(None);
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
2025-01-05 13:00:06 +09:00
|
|
|
Self::Value(_) => {}
|
2024-09-13 16:02:30 +09:00
|
|
|
Self::MultiValue(_) => todo!(),
|
2025-01-05 13:00:06 +09:00
|
|
|
Self::FullString(_) => return TokenMatchResult::Match(Some(input.into())),
|
|
|
|
|
Self::SystemRef(_) => return TokenMatchResult::Match(Some(input.into())),
|
|
|
|
|
Self::MemberRef(_) => return TokenMatchResult::Match(Some(input.into())),
|
|
|
|
|
Self::MemberPrivacyTarget(_) if MEMBER_PRIVACY_TARGETS.contains(&input) => {
|
|
|
|
|
return TokenMatchResult::Match(Some(input.into()))
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
2025-01-05 13:00:06 +09:00
|
|
|
Self::MemberPrivacyTarget(_) => {}
|
|
|
|
|
Self::PrivacyLevel(_) if input == "public" || input == "private" => {
|
|
|
|
|
return TokenMatchResult::Match(Some(input.into()))
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
2025-01-05 13:00:06 +09:00
|
|
|
Self::PrivacyLevel(_) => {}
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
// note: must not add a _ case to the above match
|
|
|
|
|
// instead, for conditional matches, also add generic cases with no return
|
|
|
|
|
|
|
|
|
|
return TokenMatchResult::NoMatch;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-05 00:59:59 +09:00
|
|
|
|
|
|
|
|
pub trait ToToken {
|
|
|
|
|
fn to_token(&self) -> Token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToToken for Token {
|
|
|
|
|
fn to_token(&self) -> Token {
|
|
|
|
|
self.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToToken for &str {
|
|
|
|
|
fn to_token(&self) -> Token {
|
|
|
|
|
Token::Value(vec![self.to_smolstr()])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToToken for [&str] {
|
|
|
|
|
fn to_token(&self) -> Token {
|
|
|
|
|
Token::Value(self.into_iter().map(|s| s.to_smolstr()).collect())
|
|
|
|
|
}
|
2025-01-05 02:21:23 +09:00
|
|
|
}
|