just/src/attribute.rs

130 lines
2.9 KiB
Rust

use super::*;
#[derive(
EnumDiscriminants, PartialEq, Debug, Clone, Serialize, Ord, PartialOrd, Eq, IntoStaticStr,
)]
#[strum(serialize_all = "kebab-case")]
#[serde(rename_all = "kebab-case")]
#[strum_discriminants(name(AttributeDiscriminant))]
#[strum_discriminants(derive(EnumString))]
#[strum_discriminants(strum(serialize_all = "kebab-case"))]
pub(crate) enum Attribute<'src> {
Confirm(Option<StringLiteral<'src>>),
Doc(Option<StringLiteral<'src>>),
Group(StringLiteral<'src>),
Linux,
Macos,
NoCd,
NoExitMessage,
NoQuiet,
Private,
Unix,
Windows,
}
impl AttributeDiscriminant {
fn argument_range(self) -> RangeInclusive<usize> {
match self {
Self::Confirm | Self::Doc => 0..=1,
Self::Group => 1..=1,
Self::Linux
| Self::Macos
| Self::NoCd
| Self::NoExitMessage
| Self::NoQuiet
| Self::Private
| Self::Unix
| Self::Windows => 0..=0,
}
}
}
impl<'src> Attribute<'src> {
pub(crate) fn new(
name: Name<'src>,
argument: Option<StringLiteral<'src>>,
) -> CompileResult<'src, Self> {
use AttributeDiscriminant::*;
let discriminant = name
.lexeme()
.parse::<AttributeDiscriminant>()
.ok()
.ok_or_else(|| {
name.error(CompileErrorKind::UnknownAttribute {
attribute: name.lexeme(),
})
})?;
let found = argument.as_ref().iter().count();
let range = discriminant.argument_range();
if !range.contains(&found) {
return Err(
name.error(CompileErrorKind::AttributeArgumentCountMismatch {
attribute: name.lexeme(),
found,
min: *range.start(),
max: *range.end(),
}),
);
}
Ok(match discriminant {
Confirm => Self::Confirm(argument),
Doc => Self::Doc(argument),
Group => Self::Group(argument.unwrap()),
Linux => Self::Linux,
Macos => Self::Macos,
NoCd => Self::NoCd,
NoExitMessage => Self::NoExitMessage,
NoQuiet => Self::NoQuiet,
Private => Self::Private,
Unix => Self::Unix,
Windows => Self::Windows,
})
}
pub(crate) fn name(&self) -> &'static str {
self.into()
}
fn argument(&self) -> Option<&StringLiteral> {
match self {
Self::Confirm(prompt) => prompt.as_ref(),
Self::Doc(doc) => doc.as_ref(),
Self::Group(group) => Some(group),
Self::Linux
| Self::Macos
| Self::NoCd
| Self::NoExitMessage
| Self::NoQuiet
| Self::Private
| Self::Unix
| Self::Windows => None,
}
}
}
impl<'src> Display for Attribute<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.name())?;
if let Some(argument) = self.argument() {
write!(f, "({argument})")?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn name() {
assert_eq!(Attribute::NoExitMessage.name(), "no-exit-message");
}
}