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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Unicode identifier rules from [UAX #31], the `XID_Start` and `XID_Continue`
//! derived properties.
//!
//! These are the properties a lexer consults to recognise identifiers in a
//! programming language: the first scalar of an identifier must be
//! `XID_Start`, and each subsequent scalar must be `XID_Continue`. The `XID`
//! variants are the closure-stable forms — normalizing an identifier never
//! turns a valid identifier into an invalid one — which is why they, rather
//! than the older `ID_Start` / `ID_Continue`, are the recommended basis.
//!
//! [UAX #31]: https://www.unicode.org/reports/tr31/
use cratein_ranges;
use cratetables;
/// Returns `true` if `c` may begin a Unicode identifier — that is, if `c` has
/// the `XID_Start` property.
///
/// This is ASCII letters, plus the letters and letter-like marks of every
/// script. It excludes digits, whitespace, and punctuation — including the
/// underscore, which is `XID_Continue` but not `XID_Start`. A language that
/// permits leading underscores (as Rust does) must allow that separately.
///
/// # Examples
///
/// ```
/// use unicode_lang::is_xid_start;
///
/// assert!(is_xid_start('a'));
/// assert!(is_xid_start('Δ')); // Greek capital delta
/// assert!(is_xid_start('日')); // CJK ideograph
///
/// assert!(!is_xid_start('1')); // a digit may continue, not start
/// assert!(!is_xid_start('_')); // underscore continues but does not start
/// assert!(!is_xid_start(' '));
/// ```
/// Returns `true` if `c` may continue a Unicode identifier — that is, if `c`
/// has the `XID_Continue` property.
///
/// `XID_Continue` is a superset of [`is_xid_start`]: it additionally admits
/// decimal digits, the combining marks that attach to letters, and the Unicode
/// connector punctuation — which includes the ASCII underscore `_` (category
/// `Pc`). The underscore therefore continues an identifier but, per
/// [`is_xid_start`], cannot begin one.
///
/// # Examples
///
/// ```
/// use unicode_lang::is_xid_continue;
///
/// assert!(is_xid_continue('a'));
/// assert!(is_xid_continue('9')); // digits continue an identifier
/// assert!(is_xid_continue('_')); // connector punctuation continues
///
/// // A base letter followed by a combining mark is a valid continuation.
/// assert!(is_xid_continue('\u{0301}')); // COMBINING ACUTE ACCENT
/// ```
/// Returns `true` if `s` is a well-formed Unicode identifier under the default
/// [UAX #31] profile: it is non-empty, its first scalar is [`is_xid_start`],
/// and every remaining scalar is [`is_xid_continue`].
///
/// This is a convenience over iterating the scalars by hand. It applies no
/// language-specific extensions — notably it rejects a leading underscore, so
/// callers whose grammar allows `_name` should test that case themselves.
///
/// [UAX #31]: https://www.unicode.org/reports/tr31/
///
/// # Examples
///
/// ```
/// use unicode_lang::is_xid;
///
/// assert!(is_xid("total"));
/// assert!(is_xid("Δpressure"));
/// assert!(is_xid("café"));
///
/// assert!(!is_xid("")); // empty is not an identifier
/// assert!(!is_xid("1st")); // cannot start with a digit
/// assert!(!is_xid("a b")); // no interior whitespace
/// assert!(!is_xid("_name")); // underscore is not XID; opt in separately
/// ```