-
Notifications
You must be signed in to change notification settings - Fork 1
/
xid.go
84 lines (74 loc) · 1.77 KB
/
xid.go
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
// Package xid implements validation functions for unicode identifiers,
// as defined in UAX#31: https://unicode.org/reports/tr31/.
// The syntax for an identifier is:
//
// <identifier> := <xid_start> <xid_continue>*
//
// where <xid_start> and <xid_continue> derive from <id_start> and
// <id_continue>, respectively, and check their NFKC normalized forms.
package xid
import (
"unicode"
"golang.org/x/text/unicode/norm"
)
type set func(rune) bool
func (a set) add(rt *unicode.RangeTable) set {
b := in(rt)
return func(r rune) bool { return a(r) || b(r) }
}
func (a set) sub(rt *unicode.RangeTable) set {
b := in(rt)
return func(r rune) bool { return a(r) && !b(r) }
}
func in(rt *unicode.RangeTable) set {
return func(r rune) bool { return unicode.Is(rt, r) }
}
var id_start = set(unicode.IsLetter).
add(unicode.Nl).
add(unicode.Other_ID_Start).
sub(unicode.Pattern_Syntax).
sub(unicode.Pattern_White_Space)
var id_continue = id_start.
add(unicode.Mn).
add(unicode.Mc).
add(unicode.Nd).
add(unicode.Pc).
add(unicode.Other_ID_Continue).
sub(unicode.Pattern_Syntax).
sub(unicode.Pattern_White_Space)
// Start checks that the rune begins an identifier.
func Start(r rune) bool {
// id_start(r) && NFKC(r) in "id_start xid_continue*"
if !id_start(r) {
return false
}
s := norm.NFKC.String(string(r))
if s == "" {
return false
}
for i, r := range s {
if i == 0 {
if !id_start(r) {
return false
}
} else {
if !Continue(r) {
return false
}
}
}
return true
}
// Continue checks that the rune continues an identifier.
func Continue(r rune) bool {
// id_continue(r) && NFKC(r) in "id_continue*"
if !id_continue(r) {
return false
}
for _, r := range norm.NFKC.String(string(r)) {
if !id_continue(r) {
return false
}
}
return true
}