2025-01-22 02:12:17 +09:00
|
|
|
use std::fmt::{Debug, Display};
|
2025-01-07 23:15:18 +09:00
|
|
|
|
2025-01-21 00:39:25 +09:00
|
|
|
use smol_str::SmolStr;
|
2025-01-04 02:49:04 +09:00
|
|
|
|
2025-01-21 12:36:54 +09:00
|
|
|
use crate::parameter::{Parameter, ParameterKind, ParameterValue};
|
2025-01-07 23:15:18 +09:00
|
|
|
|
2025-01-21 12:36:54 +09:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
2024-09-13 16:02:30 +09:00
|
|
|
pub enum Token {
|
2025-01-07 23:15:18 +09:00
|
|
|
/// A bot-defined command / subcommand (usually) (eg. "member" in `pk;member MyName`)
|
2025-01-22 02:12:17 +09:00
|
|
|
Value {
|
|
|
|
|
name: SmolStr,
|
|
|
|
|
aliases: Vec<SmolStr>,
|
|
|
|
|
},
|
2024-09-13 16:02:30 +09:00
|
|
|
|
2025-01-15 03:52:32 +09:00
|
|
|
/// A parameter that must be provided a value
|
2025-01-21 12:36:54 +09:00
|
|
|
Parameter(Parameter),
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 23:15:18 +09:00
|
|
|
#[derive(Debug)]
|
2025-01-12 04:23:46 +09:00
|
|
|
pub enum TokenMatchError {
|
2025-01-15 03:52:32 +09:00
|
|
|
ParameterMatchError { input: SmolStr, msg: SmolStr },
|
2025-01-21 12:36:54 +09:00
|
|
|
MissingParameter { name: SmolStr },
|
2025-01-07 23:15:18 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2025-01-21 04:31:03 +09:00
|
|
|
pub(super) struct TokenMatchValue {
|
2025-01-07 23:15:18 +09:00
|
|
|
pub raw: SmolStr,
|
2025-01-21 12:36:54 +09:00
|
|
|
pub param: Option<(SmolStr, ParameterValue)>,
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
|
2025-01-14 11:53:56 +09:00
|
|
|
impl TokenMatchValue {
|
2025-01-12 04:23:46 +09:00
|
|
|
fn new_match(raw: impl Into<SmolStr>) -> TryMatchResult {
|
|
|
|
|
Some(Ok(Some(Self {
|
2025-01-07 23:15:18 +09:00
|
|
|
raw: raw.into(),
|
|
|
|
|
param: None,
|
2025-01-12 04:23:46 +09:00
|
|
|
})))
|
2025-01-07 23:15:18 +09:00
|
|
|
}
|
|
|
|
|
|
2025-01-12 04:23:46 +09:00
|
|
|
fn new_match_param(
|
|
|
|
|
raw: impl Into<SmolStr>,
|
2025-01-21 12:36:54 +09:00
|
|
|
param_name: impl Into<SmolStr>,
|
2025-01-21 04:31:03 +09:00
|
|
|
param: ParameterValue,
|
2025-01-12 04:23:46 +09:00
|
|
|
) -> TryMatchResult {
|
|
|
|
|
Some(Ok(Some(Self {
|
2025-01-07 23:15:18 +09:00
|
|
|
raw: raw.into(),
|
2025-01-21 12:36:54 +09:00
|
|
|
param: Some((param_name.into(), param)),
|
2025-01-12 04:23:46 +09:00
|
|
|
})))
|
2025-01-07 23:15:18 +09:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-13 16:02:30 +09:00
|
|
|
|
2025-01-12 04:23:46 +09:00
|
|
|
/// None -> no match
|
|
|
|
|
/// Some(Ok(None)) -> match, no value
|
|
|
|
|
/// Some(Ok(Some(_))) -> match, with value
|
|
|
|
|
/// Some(Err(_)) -> error while matching
|
|
|
|
|
// q: why do this while we could have a NoMatch in TokenMatchError?
|
|
|
|
|
// a: because we want to differentiate between no match and match failure (it matched with an error)
|
|
|
|
|
// "no match" has a different charecteristic because we want to continue matching other tokens...
|
|
|
|
|
// ...while "match failure" means we should stop matching and return the error
|
2025-01-14 11:53:56 +09:00
|
|
|
type TryMatchResult = Option<Result<Option<TokenMatchValue>, TokenMatchError>>;
|
2024-09-13 16:02:30 +09:00
|
|
|
|
2025-01-12 04:23:46 +09:00
|
|
|
impl Token {
|
2025-01-21 04:31:03 +09:00
|
|
|
pub(super) fn try_match(&self, input: Option<&str>) -> TryMatchResult {
|
2025-01-07 23:15:18 +09:00
|
|
|
let input = match input {
|
|
|
|
|
Some(input) => input,
|
|
|
|
|
None => {
|
|
|
|
|
// short circuit on:
|
|
|
|
|
return match self {
|
|
|
|
|
// missing paramaters
|
2025-01-21 12:36:54 +09:00
|
|
|
Self::Parameter(param) => Some(Err(TokenMatchError::MissingParameter {
|
|
|
|
|
name: param.name().into(),
|
|
|
|
|
})),
|
2025-01-07 23:15:18 +09:00
|
|
|
// everything else doesnt match if no input anyway
|
2025-01-22 02:12:17 +09:00
|
|
|
Self::Value { .. } => None,
|
2025-01-07 23:15:18 +09:00
|
|
|
// don't add a _ match here!
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let input = input.trim();
|
2024-09-13 16:02:30 +09:00
|
|
|
|
|
|
|
|
// try actually matching stuff
|
|
|
|
|
match self {
|
2025-01-22 02:12:17 +09:00
|
|
|
Self::Value { name, aliases } => (aliases.iter().chain(std::iter::once(name)))
|
2025-01-07 23:15:18 +09:00
|
|
|
.any(|v| v.eq(input))
|
2025-01-14 11:53:56 +09:00
|
|
|
.then(|| TokenMatchValue::new_match(input))
|
2025-01-12 04:23:46 +09:00
|
|
|
.unwrap_or(None),
|
2025-01-21 12:36:54 +09:00
|
|
|
Self::Parameter(param) => match param.kind().match_value(input) {
|
|
|
|
|
Ok(matched) => TokenMatchValue::new_match_param(input, param.name(), matched),
|
2025-01-15 03:52:32 +09:00
|
|
|
Err(err) => Some(Err(TokenMatchError::ParameterMatchError {
|
|
|
|
|
input: input.into(),
|
|
|
|
|
msg: err,
|
|
|
|
|
})),
|
|
|
|
|
}, // don't add a _ match here!
|
2025-01-07 23:15:18 +09:00
|
|
|
}
|
2024-09-13 16:02:30 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-05 00:59:59 +09:00
|
|
|
|
2025-01-08 18:31:59 +09:00
|
|
|
impl Display for Token {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
match self {
|
2025-01-24 04:08:59 +09:00
|
|
|
Self::Value { name, .. } => write!(f, "{name}"),
|
|
|
|
|
Self::Parameter(param) => param.kind().format(f, param.name()),
|
2025-01-08 18:31:59 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 04:08:59 +09:00
|
|
|
impl<const L: usize> From<(&str, [&str; L])> for Token {
|
|
|
|
|
fn from((name, aliases): (&str, [&str; L])) -> Self {
|
|
|
|
|
Self::Value {
|
|
|
|
|
name: name.into(),
|
|
|
|
|
aliases: aliases.into_iter().map(SmolStr::new).collect::<Vec<_>>(),
|
2025-01-22 02:12:17 +09:00
|
|
|
}
|
2025-01-21 00:39:25 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 04:08:59 +09:00
|
|
|
impl From<&str> for Token {
|
|
|
|
|
fn from(value: &str) -> Self {
|
|
|
|
|
Self::from((value, []))
|
2025-01-05 00:59:59 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-21 12:36:54 +09:00
|
|
|
impl From<Parameter> for Token {
|
|
|
|
|
fn from(value: Parameter) -> Self {
|
2025-01-24 04:08:59 +09:00
|
|
|
Self::Parameter(value)
|
2025-01-21 12:36:54 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<ParameterKind> for Token {
|
|
|
|
|
fn from(value: ParameterKind) -> Self {
|
2025-01-24 04:08:59 +09:00
|
|
|
Self::from(Parameter::from(value))
|
2025-01-08 18:31:59 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-21 12:36:54 +09:00
|
|
|
impl From<(&str, ParameterKind)> for Token {
|
|
|
|
|
fn from(value: (&str, ParameterKind)) -> Self {
|
2025-01-24 04:08:59 +09:00
|
|
|
Self::from(Parameter::from(value))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct TokensIterator {
|
|
|
|
|
inner: Vec<Token>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Iterator for TokensIterator {
|
|
|
|
|
type Item = Token;
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
(self.inner.len() > 0).then(|| self.inner.remove(0))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Into<Token>> From<T> for TokensIterator {
|
|
|
|
|
fn from(value: T) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
inner: vec![value.into()],
|
|
|
|
|
}
|
2025-01-08 18:31:59 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-24 04:08:59 +09:00
|
|
|
|
|
|
|
|
impl<const L: usize> From<[Token; L]> for TokensIterator {
|
|
|
|
|
fn from(value: [Token; L]) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
inner: value.into_iter().collect(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<const L: usize> From<[Self; L]> for TokensIterator {
|
|
|
|
|
fn from(value: [Self; L]) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
inner: value
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|t| t.collect::<Vec<_>>())
|
|
|
|
|
.flatten()
|
|
|
|
|
.collect(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Vec<Token>> for TokensIterator {
|
|
|
|
|
fn from(value: Vec<Token>) -> Self {
|
|
|
|
|
Self { inner: value }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
|
macro_rules! tokens {
|
|
|
|
|
($($v:expr),+$(,)*) => {
|
|
|
|
|
$crate::token::TokensIterator::from([$($crate::token::TokensIterator::from($v.clone())),+])
|
|
|
|
|
};
|
|
|
|
|
}
|