javascript_lexer 0.1.8

Javascript lexer
use crate::token::Token;
use internship::IStr;
use std::str;

const IDENTIFIERS: phf::Map<&'static str, Token> = phf_map! {
    "true" => Token::BoolLiteral(true),
    "false" => Token::BoolLiteral(false),
    "null" => Token::LNull,
    "undefined" => Token::LUndefined,
    "function" => Token::KFunction,
    "async" => Token::KAsync,
    "class" => Token::KClass,
    "let" => Token::KLet,
    "if" => Token::KIf,
    "else" => Token::KElse,
    "do" => Token::KDo,
    "while" => Token::KWhile,
    "for" => Token::KFor,
    "var" => Token::KVar,
    "const" => Token::KConst,
    "in" => Token::KIn,
    "of" => Token::KOf,
    "await" => Token::KAwait,
    "switch" => Token::KSwitch,
    "case" => Token::KCase,
    "default" => Token::KDefault,
    "continue" => Token::KContinue,
    "break" => Token::KBreak,
    "return" => Token::KReturn,
    "with" => Token::KWith,
    "throw" => Token::KThrow,
    "try" => Token::KTry,
    "catch" => Token::KCatch,
    "finally" => Token::KFinally,
    "debugger" => Token::KDebugger,
    "extend" => Token::KExtend,
    "static" => Token::KStatic,
    "get" => Token::KGet,
    "set" => Token::KSet,
    "this" => Token::KThis,
    "delete" => Token::KDelete,
    "void" => Token::KVoid,
    "typeof" => Token::KTypeof,
    "new" => Token::KNew,
    "import" => Token::KImport,
    "as" => Token::KAs,
    "from" => Token::KFrom,
};

#[inline]
fn is_identifier_part(cp: u8) -> bool {
    cp == 0x24
        || cp == 0x5F
        || (cp >= 0x41 && cp <= 0x5A)
        || (cp >= 0x61 && cp <= 0x7A)
        || (cp >= 0x30 && cp <= 0x39)
        || cp == 0x5C
        || cp >= 0x80
}

#[inline]
pub fn parse_identifier(input: &[u8], c_src: &mut usize) -> Token {
    let mut it = 0;
    for i in 0..input.len() - *c_src {
        if !unsafe { is_identifier_part(*input.get_unchecked(*c_src + i)) } {
            it = i;
            break;
        }
    }
    let ident = &input[*c_src - 1..*c_src + it];
    *c_src += it;
    let ident = unsafe { str::from_utf8_unchecked(ident) };
    IDENTIFIERS
        .get(ident)
        .cloned()
        .unwrap_or_else(|| Token::IdentifierName(IStr::new(ident)))
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use ::internship::IStr;

    should!(
        parsing_after_token,
        "**=a ",
        vec![
            Token::DoubleStarAssign,
            Token::IdentifierName(IStr::new("a")),
            Token::EOF
        ]
    );

    should!(
        parsing_after_token_2,
        "a( a1 ",
        vec![
            Token::IdentifierName(IStr::new("a")),
            Token::LRound,
            Token::IdentifierName(IStr::new("a1")),
            Token::EOF
        ]
    );

    should!(keyword, "var ", vec![Token::KVar, Token::EOF]);
}