use std::fmt;
pub use crate::syn::token::Span;
mod keyword;
pub use keyword::Keyword;
pub(crate) use keyword::keyword_t;
mod mac;
pub(crate) use mac::t;
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum NumberKind {
Integer,
Hex,
Octal,
Binary,
Float,
Scientific,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum NumberSuffix {
Exact,
Float,
Double,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum TokenKind {
Keyword(Keyword),
Identifier,
SingleQuoted {
no_escape: bool,
},
DoubleQuoted {
no_escape: bool,
},
AccentQuoted {
no_escape: bool,
},
Parameter,
SubstitutedParameter,
Number {
kind: NumberKind,
suffix: Option<NumberSuffix>,
},
MultisetAlternation,
BracketRightArrow,
BracketTildeRightArrow,
Concat,
DoubleColon,
DoublePeriod,
Gte,
LeftArrow,
LeftArrowTilde,
LeftArrowBracket,
LeftArrowTildeBracket,
LeftMinusRight,
LeftMinusSlash,
LeftTildeSlash,
Lte,
MinusLeftBracket,
MinusSlash,
Neq,
RightArrow,
RightBracketMinus,
RightBracketTilde,
RightDoubleArrow,
SlashMinus,
SlashMinusRight,
SlashTilde,
SlashTildeRight,
TildeLeftBracket,
TildeRightArrow,
TildeSlash,
Ampersand,
At,
Colon,
Comma,
Eq,
Exclamation,
Gt,
Lt,
Minus,
OpenParen,
CloseParen,
OpenBracket,
CloseBracket,
OpenBrace,
CloseBrace,
Percent,
Period,
Plus,
Question,
Slash,
Star,
Tilde,
VerticalBar,
Eof,
Invalid,
}
impl TokenKind {
pub fn as_str(self) -> &'static str {
match self {
TokenKind::Keyword(x) => x.as_str(),
TokenKind::Identifier => "an identifier",
TokenKind::SingleQuoted {
..
} => "a string literal",
TokenKind::DoubleQuoted {
..
} => "a string literal or delimited identifier",
TokenKind::AccentQuoted {
..
} => "a delimited identifier",
TokenKind::Parameter => "a parameter",
TokenKind::SubstitutedParameter => "a substituted parameter",
TokenKind::Number {
..
} => "a number",
TokenKind::MultisetAlternation => "|+|",
TokenKind::BracketRightArrow => "]->",
TokenKind::BracketTildeRightArrow => "]~>",
TokenKind::Concat => "||",
TokenKind::DoubleColon => "::",
TokenKind::DoublePeriod => "..",
TokenKind::Gte => ">=",
TokenKind::LeftArrow => "<-",
TokenKind::LeftArrowTilde => "<~",
TokenKind::LeftArrowBracket => "<-[",
TokenKind::LeftArrowTildeBracket => "<~[",
TokenKind::LeftMinusRight => "<->",
TokenKind::LeftMinusSlash => "<-/",
TokenKind::LeftTildeSlash => "<~/",
TokenKind::Lte => "<=",
TokenKind::MinusLeftBracket => "-[",
TokenKind::MinusSlash => "-/",
TokenKind::Neq => "<>",
TokenKind::RightArrow => "->",
TokenKind::RightBracketMinus => "]-",
TokenKind::RightBracketTilde => "]~",
TokenKind::RightDoubleArrow => "=>",
TokenKind::SlashMinus => "/-",
TokenKind::SlashMinusRight => "/->",
TokenKind::SlashTilde => "/~",
TokenKind::SlashTildeRight => "/~>",
TokenKind::TildeLeftBracket => "~[",
TokenKind::TildeRightArrow => "~>",
TokenKind::TildeSlash => "~/",
TokenKind::Ampersand => "&",
TokenKind::At => "@",
TokenKind::Colon => ":",
TokenKind::Comma => ",",
TokenKind::Eq => "=",
TokenKind::Exclamation => "!",
TokenKind::Gt => ">",
TokenKind::Lt => "<",
TokenKind::Minus => "-",
TokenKind::OpenParen => "(",
TokenKind::CloseParen => ")",
TokenKind::OpenBracket => "[",
TokenKind::CloseBracket => "]",
TokenKind::OpenBrace => "{",
TokenKind::CloseBrace => "}",
TokenKind::Percent => "%",
TokenKind::Period => ".",
TokenKind::Plus => "+",
TokenKind::Question => "?",
TokenKind::Slash => "/",
TokenKind::Star => "*",
TokenKind::Tilde => "~",
TokenKind::VerticalBar => "|",
TokenKind::Eof => "Eof",
TokenKind::Invalid => "Invalid",
}
}
}
impl fmt::Display for TokenKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str((*self).as_str())
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
}
impl Token {
pub const fn invalid() -> Token {
Token {
kind: TokenKind::Invalid,
span: Span::empty(),
}
}
pub fn is_eof(&self) -> bool {
matches!(self.kind, TokenKind::Eof)
}
}
#[cfg(test)]
mod test {
use super::{Keyword, TokenKind, t};
#[test]
fn keyword_classification() {
assert!(Keyword::Match.is_reserved());
assert!(!Keyword::Match.is_prereserved());
assert!(!Keyword::Match.is_non_reserved());
assert!(Keyword::Abstract.is_prereserved());
assert!(!Keyword::Abstract.is_reserved());
assert!(Keyword::Node.is_non_reserved());
assert!(!Keyword::Node.is_reserved());
assert!(Keyword::True.is_reserved());
assert!(Keyword::Unknown.is_reserved());
assert_eq!(Keyword::Skip.as_str(), "SKIP");
assert_eq!(Keyword::Null.as_str(), "NULL");
assert_eq!(Keyword::AllDifferent.as_str(), "ALL_DIFFERENT");
}
#[test]
fn token_macro() {
assert_eq!(t!("MATCH"), TokenKind::Keyword(Keyword::Match));
assert_eq!(t!("NODE"), TokenKind::Keyword(Keyword::Node));
assert_eq!(t!("<-["), TokenKind::LeftArrowBracket);
assert_eq!(t!("]~>"), TokenKind::BracketTildeRightArrow);
assert_eq!(t!("<>"), TokenKind::Neq);
assert_eq!(t!("||"), TokenKind::Concat);
assert_eq!(t!("$param"), TokenKind::Parameter);
assert_eq!(t!("$$param"), TokenKind::SubstitutedParameter);
assert_eq!(
t!("@\""),
TokenKind::DoubleQuoted {
no_escape: true,
}
);
assert!(matches!(t!("RETURN"), t!("RETURN")));
assert!(matches!(t!("-["), t!("-[")));
}
}