rascal_scanner 0.1.2

Rascal programming language scanner.
Documentation
use alloc::string::String;

/// Matches a given string to a keyword. Uses a Trie for efficient matching.
pub fn keywords(input: &str) -> Option<Token> {
    use Token::*;
    let mut chars = input.chars();
    match chars.next()? {
        'a' => check_keyword(chars.as_str(), "nd", And),
        'c' => check_keyword(chars.as_str(), "lass", Class),
        'e' => check_keyword(chars.as_str(), "lse", Else),
        'f' => match chars.next()? {
            'a' => check_keyword(chars.as_str(), "lse", False),
            'o' => check_keyword(chars.as_str(), "r", For),
            'u' => check_keyword(chars.as_str(), "n", Fun),
            _ => None,
        },
        'i' => check_keyword(chars.as_str(), "f", If),
        'n' => check_keyword(chars.as_str(), "il", Nil),
        'o' => check_keyword(chars.as_str(), "r", Or),
        'p' => check_keyword(chars.as_str(), "rint", Print),
        'r' => check_keyword(chars.as_str(), "eturn", Return),
        's' => check_keyword(chars.as_str(), "uper", Super),
        't' => match chars.next()? {
            'h' => check_keyword(chars.as_str(), "is", This),
            'r' => check_keyword(chars.as_str(), "ue", True),
            _ => None,
        },
        'v' => check_keyword(chars.as_str(), "ar", Var),
        'w' => check_keyword(chars.as_str(), "hile", While),

        _ => None,
    }
}

fn check_keyword(input: &str, search: &str, on_match: Token) -> Option<Token> {
    if input == search {
        Some(on_match)
    } else {
        None
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
    // Single character tokens
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    // One or two character
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    // Literals
    Identifier(String),
    String(String),
    Number(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,
    // Eof
    Eof,
}

impl core::fmt::Display for Token {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match &self {
            Self::LeftParen => write!(f, "("),
            Self::RightParen => write!(f, ")"),
            Self::LeftBrace => write!(f, "{{"),
            Self::RightBrace => write!(f, "}}"),
            Self::Comma => write!(f, ","),
            Self::Dot => write!(f, "."),
            Self::Minus => write!(f, "-"),
            Self::Plus => write!(f, "+"),
            Self::Semicolon => write!(f, ";"),
            Self::Slash => write!(f, "/"),
            Self::Star => write!(f, "*"),
            // One or two character
            Self::Bang => write!(f, "!"),
            Self::BangEqual => write!(f, "!="),
            Self::Equal => write!(f, "="),
            Self::EqualEqual => write!(f, "=="),
            Self::Greater => write!(f, ">"),
            Self::GreaterEqual => write!(f, ">="),
            Self::Less => write!(f, "<"),
            Self::LessEqual => write!(f, "<="),
            // Literals
            Self::Identifier(s) | Self::String(s) => write!(f, "{}", s),
            Self::Number(n) => write!(f, "{}", n),
            // Keywords
            Self::And => write!(f, "And"),
            Self::Class => write!(f, "Class"),
            Self::Else => write!(f, "Else"),
            Self::False => write!(f, "False"),
            Self::Fun => write!(f, "Fun"),
            Self::For => write!(f, "For"),
            Self::If => write!(f, "If"),
            Self::Nil => write!(f, "Nil"),
            Self::Or => write!(f, "Or"),
            Self::Print => write!(f, "Print"),
            Self::Return => write!(f, "Return"),
            Self::Super => write!(f, "Super"),
            Self::This => write!(f, "This"),
            Self::True => write!(f, "True"),
            Self::Var => write!(f, "Var"),
            Self::While => write!(f, "While"),
            Self::Eof => write!(f, "Eof"),
        }
    }
}