use super::super::lexeme::LexemeKind;
const FREEWORD: LexemeKind = LexemeKind::IdentifierFreeword;
const KEYWORD: LexemeKind = LexemeKind::IdentifierKeyword;
const STD_TYPE: LexemeKind = LexemeKind::IdentifierStdType;
const UNDETECTED: (LexemeKind, usize) = (LexemeKind::Undetected, 0);
pub fn detect_identifier(
orig: &str,
chr: usize,
) -> (
LexemeKind,
usize,
) {
let len = orig.len();
if chr >= len { return UNDETECTED }
let c0 = get_aot(orig, chr);
let c0_u = c0 == "_"; if ! c0_u && ! c0.chars().all(char::is_alphabetic) { return UNDETECTED }
if len == chr + 1 {
return if c0_u { UNDETECTED } else { (FREEWORD, len) }
}
let c1 = orig.get(chr+1..chr+2).unwrap_or("~");
if c1 != "_" && ! c1.chars().all(char::is_alphanumeric) {
return if c0_u { UNDETECTED } else { (FREEWORD, chr + 1) }
}
for i in chr+2..len {
let c = get_aot(orig, i);
if c != "_" && ! c.chars().all(char::is_alphanumeric) {
return (categorize_identifier(&orig[chr..i]), i)
}
}
(categorize_identifier(&orig[chr..len]), len)
}
fn get_aot(orig: &str, c: usize) -> &str { orig.get(c..c+1).unwrap_or("~") }
fn categorize_identifier(s: &str) -> LexemeKind {
if KEYWORDS.contains(&s) { return KEYWORD }
if PRIMATIVE_TYPES.contains(&s) { return STD_TYPE }
FREEWORD
}
const KEYWORDS: [&str; 52] = [
"abstract",
"as",
"async",
"await",
"become",
"box",
"break",
"const",
"continue",
"crate",
"do",
"dyn",
"else",
"enum",
"extern",
"false",
"final",
"fn",
"for",
"if",
"impl",
"in",
"let",
"loop",
"macro",
"match",
"mod",
"move",
"mut",
"override",
"priv",
"pub",
"ref",
"return",
"Self",
"self",
"static",
"struct",
"super",
"trait",
"true",
"try",
"type",
"typeof",
"union",
"unsafe",
"unsized",
"use",
"virtual",
"where",
"while",
"yield",
];
const PRIMATIVE_TYPES: [&str; 18] = [
"bool",
"char",
"f32",
"f64",
"i128",
"i16",
"i32",
"i64",
"i8",
"isize",
"str",
"str",
"u128",
"u16",
"u32",
"u64",
"u8",
"usize",
];
#[cfg(test)]
mod tests {
use super::detect_identifier as detect;
use super::FREEWORD as F;
use super::KEYWORD as K;
use super::STD_TYPE as S;
use super::UNDETECTED as U;
#[test]
fn detect_identifier_correct() {
let orig = "let^_def,G_h__1_; _123e+__ X2 Y Z foo!";
assert_eq!(detect(orig, 0), (K, 3)); assert_eq!(detect(orig, 1), (F, 3)); assert_eq!(detect(orig, 2), (F, 3)); assert_eq!(detect(orig, 3), U); assert_eq!(detect(orig, 4), (F, 8)); assert_eq!(detect(orig, 8), U); assert_eq!(detect(orig, 9), (F,16)); assert_eq!(detect(orig, 18), (F,23)); assert_eq!(detect(orig, 24), (F,26)); assert_eq!(detect(orig, 27), (F,29)); assert_eq!(detect(orig, 30), (F,31)); assert_eq!(detect(orig, 32), (F,33)); assert_eq!(detect(orig, 34), (F,37));
let orig = "as break const";
assert_eq!(detect(orig, 0), (K,2)); assert_eq!(detect(orig, 3), (K,8)); assert_eq!(detect(orig, 9), (K,14));
assert_eq!(detect("as", 0), (K,2));
assert_eq!(detect("do", 0), (K,2));
assert_eq!(detect("fn", 0), (K,2));
assert_eq!(detect("if", 0), (K,2));
assert_eq!(detect("in", 0), (K,2));
assert_eq!(detect("box", 0), (K,3));
assert_eq!(detect("dyn", 0), (K,3));
assert_eq!(detect("for", 0), (K,3));
assert_eq!(detect("let", 0), (K,3));
assert_eq!(detect("mod", 0), (K,3));
assert_eq!(detect("mut", 0), (K,3));
assert_eq!(detect("pub", 0), (K,3));
assert_eq!(detect("ref", 0), (K,3));
assert_eq!(detect("try", 0), (K,3));
assert_eq!(detect("use", 0), (K,3));
assert_eq!(detect("else", 0), (K,4));
assert_eq!(detect("enum", 0), (K,4));
assert_eq!(detect("impl", 0), (K,4));
assert_eq!(detect("loop", 0), (K,4));
assert_eq!(detect("move", 0), (K,4));
assert_eq!(detect("priv", 0), (K,4));
assert_eq!(detect("Self", 0), (K,4));
assert_eq!(detect("self", 0), (K,4));
assert_eq!(detect("true", 0), (K,4));
assert_eq!(detect("type", 0), (K,4));
assert_eq!(detect("await", 0), (K,5));
assert_eq!(detect("break", 0), (K,5));
assert_eq!(detect("const", 0), (K,5));
assert_eq!(detect("crate", 0), (K,5));
assert_eq!(detect("false", 0), (K,5));
assert_eq!(detect("final", 0), (K,5));
assert_eq!(detect("macro", 0), (K,5));
assert_eq!(detect("match", 0), (K,5));
assert_eq!(detect("super", 0), (K,5));
assert_eq!(detect("trait", 0), (K,5));
assert_eq!(detect("union", 0), (K,5));
assert_eq!(detect("where", 0), (K,5));
assert_eq!(detect("while", 0), (K,5));
assert_eq!(detect("yield", 0), (K,5));
assert_eq!(detect("become", 0), (K,6));
assert_eq!(detect("extern", 0), (K,6));
assert_eq!(detect("return", 0), (K,6));
assert_eq!(detect("static", 0), (K,6));
assert_eq!(detect("struct", 0), (K,6));
assert_eq!(detect("typeof", 0), (K,6));
assert_eq!(detect("unsafe", 0), (K,6));
assert_eq!(detect("unsized", 0), (K,7));
assert_eq!(detect("virtual", 0), (K,7));
assert_eq!(detect("abstract", 0), (K,8));
assert_eq!(detect("continue", 0), (K,8));
assert_eq!(detect("override", 0), (K,8));
assert_eq!(detect("'static", 0), U); assert_eq!(detect("'static", 1), (K,7));
let orig = "bool i128 isize";
assert_eq!(detect(orig, 0), (S,4)); assert_eq!(detect(orig, 5), (S,9)); assert_eq!(detect(orig, 10), (S,15));
assert_eq!(detect("i8", 0), (S,2));
assert_eq!(detect("u8", 0), (S,2));
assert_eq!(detect("f32", 0), (S,3));
assert_eq!(detect("f64", 0), (S,3));
assert_eq!(detect("i16", 0), (S,3));
assert_eq!(detect("i32", 0), (S,3));
assert_eq!(detect("i64", 0), (S,3));
assert_eq!(detect("str", 0), (S,3));
assert_eq!(detect("str", 0), (S,3));
assert_eq!(detect("u16", 0), (S,3));
assert_eq!(detect("u32", 0), (S,3));
assert_eq!(detect("u64", 0), (S,3));
assert_eq!(detect("bool", 0), (S,4));
assert_eq!(detect("char", 0), (S,4));
assert_eq!(detect("i128", 0), (S,4));
assert_eq!(detect("u128", 0), (S,4));
assert_eq!(detect("isize", 0), (S,5));
assert_eq!(detect("usize", 0), (S,5));
}
#[test]
fn detect_identifier_incorrect() {
let orig = "_ 2X _";
assert_eq!(detect(orig, 0), U); assert_eq!(detect(orig, 2), U); }
#[test]
fn detect_identifier_will_not_panic() {
assert_eq!(detect("", 0), U); assert_eq!(detect("'", 0), U); assert_eq!(detect("'a", 0), U); assert_eq!(detect("'a", 1), (F,2)); assert_eq!(detect("_", 0), U); assert_eq!(detect("abc", 2), (F,3)); assert_eq!(detect("abc", 3), U); assert_eq!(detect("abc", 4), U); assert_eq!(detect("abc", 100), U); assert_eq!(detect("€", 1), U); assert_eq!(detect("a€", 0), (F,1)); assert_eq!(detect("abcd€fg", 2), (F,4)); }
}