darklua_core/process/utils/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
mod permutator;

pub(crate) use permutator::Permutator;

pub(crate) type CharPermutator = Permutator<std::str::Chars<'static>>;

pub(crate) fn identifier_permutator() -> CharPermutator {
    Permutator::new("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789".chars())
}

pub(crate) fn generate_identifier(permutator: &mut CharPermutator) -> String {
    permutator
        .find(|identifier| is_valid_identifier(identifier))
        .expect("the permutator should always ultimately return a valid identifier")
}

pub(crate) const KEYWORDS: [&str; 21] = [
    "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local",
    "nil", "not", "or", "repeat", "return", "then", "true", "until", "while",
];

macro_rules! matches_any_keyword {
    () => {
        "and"
            | "break"
            | "do"
            | "else"
            | "elseif"
            | "end"
            | "false"
            | "for"
            | "function"
            | "if"
            | "in"
            | "local"
            | "nil"
            | "not"
            | "or"
            | "repeat"
            | "return"
            | "then"
            | "true"
            | "until"
            | "while"
    };
}

pub(crate) fn is_valid_identifier(identifier: &str) -> bool {
    !identifier.is_empty()
        && identifier.is_ascii()
        && identifier
            .char_indices()
            .all(|(i, c)| c.is_alphabetic() || c == '_' || (c.is_ascii_digit() && i > 0))
        && !matches!(identifier, matches_any_keyword!())
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn is_valid_identifier_is_true() {
        assert!(is_valid_identifier("hello"));
        assert!(is_valid_identifier("foo"));
        assert!(is_valid_identifier("bar"));
        assert!(is_valid_identifier("VAR"));
        assert!(is_valid_identifier("_VAR"));
        assert!(is_valid_identifier("_0"));
    }

    #[test]
    fn is_valid_identifier_is_false() {
        assert!(!is_valid_identifier(""));
        assert!(!is_valid_identifier("$hello"));
        assert!(!is_valid_identifier(" "));
        assert!(!is_valid_identifier("5"));
        assert!(!is_valid_identifier("1bar"));
        assert!(!is_valid_identifier("var "));
        assert!(!is_valid_identifier("sp ace"));
    }

    #[test]
    fn keywords_are_not_valid_identifiers() {
        for keyword in KEYWORDS {
            assert!(!is_valid_identifier(keyword));
        }
    }
}