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
|
package highlight
import "unicode"
var jsKeywords = wordsSet(`await break case catch class const continue debugger default delete
do else export extends finally for function if import in instanceof let new return super switch
this throw try typeof var void while with yield async of as from get set static interface type
enum implements public private protected readonly`)
var jsLiterals = wordsSet(`true false null undefined NaN Infinity`)
func lexJS(code string) []Token {
rs := []rune(code)
n := len(rs)
var toks []Token
var plain []rune
flush := func() {
if len(plain) > 0 {
toks = append(toks, Token{KindPlain, string(plain)})
plain = plain[:0]
}
}
expectName := false
for i := 0; i < n; {
r := rs[i]
switch {
case r == '/' && i+1 < n && rs[i+1] == '/':
flush()
expectName = false
j := i
for j < n && rs[j] != '\n' {
j++
}
toks = append(toks, Token{KindComment, string(rs[i:j])})
i = j
case r == '/' && i+1 < n && rs[i+1] == '*':
flush()
expectName = false
j := i + 2
for j < n && !(rs[j] == '*' && j+1 < n && rs[j+1] == '/') {
j++
}
if j < n {
j += 2
} else {
j = n
}
toks = append(toks, Token{KindComment, string(rs[i:j])})
i = j
case r == '`':
flush()
expectName = false
j := i + 1
for j < n && rs[j] != '`' {
if rs[j] == '\\' && j+1 < n {
j += 2
} else {
j++
}
}
if j < n {
j++
}
toks = append(toks, Token{KindString, string(rs[i:j])})
i = j
case r == '"' || r == '\'':
flush()
expectName = false
j := scanQuoted(rs, i)
toks = append(toks, Token{KindString, string(rs[i:j])})
i = j
case isDigit(r) || (r == '.' && i+1 < n && isDigit(rs[i+1])):
flush()
expectName = false
j := scanNumber(rs, i)
toks = append(toks, Token{KindNumber, string(rs[i:j])})
i = j
case isIdentStart(r):
flush()
j := i + 1
for j < n && isIdentPart(rs[j]) {
j++
}
word := string(rs[i:j])
kind := KindPlain
switch {
case jsKeywords[word]:
kind = KindKeyword
case jsLiterals[word]:
kind = KindLiteral
case expectName:
kind = KindType
case nextNonSpaceIs(rs, j, '('):
kind = KindType
case unicode.IsUpper(rs[i]):
kind = KindType
}
expectName = (word == "function" || word == "class" || word == "new") && nextNonSpaceIsIdent(rs, j)
toks = append(toks, Token{kind, word})
i = j
case isOperator(r):
flush()
expectName = false
toks = append(toks, Token{KindOperator, string(r)})
i++
default:
plain = append(plain, r)
i++
}
}
flush()
return toks
}
|