Repository navigation
Expand file tree
/
Copy pathecmascript_lexer.go
More file actions
113 lines (86 loc) · 2.67 KB
/
Copy pathecmascript_lexer.go
File metadata and controls
113 lines (86 loc) · 2.67 KB
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 main
import (
"bytes"
"strings"
"unicode"
"unicode/utf8"
)
type ecmaScriptLexicalState struct {
quote byte
insideBlockComment bool
insideRegexClass bool
}
func (state *ecmaScriptLexicalState) maskLiteralsAndComments(sourceLine string) string {
if state.insideBlockComment {
commentEnd := strings.Index(sourceLine, "*/")
if commentEnd < 0 {
return ""
}
sourceLine = sourceLine[commentEnd+2:]
state.insideBlockComment = false
}
if state.quote == 0 && !strings.ContainsAny(sourceLine, "\"'`/") {
return sourceLine
}
code := []byte(sourceLine)
for characterIndex := 0; characterIndex < len(code); characterIndex++ {
character := code[characterIndex]
if state.quote != 0 {
code[characterIndex] = ' '
if character == '\\' && characterIndex+1 < len(code) {
code[characterIndex+1] = ' '
characterIndex++
} else if state.quote == '/' && character == '[' {
state.insideRegexClass = true
} else if state.quote == '/' && character == ']' {
state.insideRegexClass = false
} else if character == state.quote && !state.insideRegexClass {
state.quote = 0
}
continue
}
if character == '/' && characterIndex+1 < len(code) {
nextCharacter := code[characterIndex+1]
if nextCharacter == '/' {
return string(code[:characterIndex])
}
if nextCharacter == '*' {
code[characterIndex] = ' '
code[characterIndex+1] = ' '
for characterIndex += len("/*"); characterIndex < len(code); characterIndex++ {
character := code[characterIndex]
code[characterIndex] = ' '
if character == '*' && characterIndex+1 < len(code) && code[characterIndex+1] == '/' {
code[characterIndex+1] = ' '
characterIndex++
break
}
}
state.insideBlockComment = characterIndex >= len(code)
continue
}
}
if character == '\'' || character == '"' || character == '`' {
state.quote = character
code[characterIndex] = '0'
} else if character == '/' && ecmaScriptStartsRegex(code[:characterIndex]) {
state.quote = '/'
code[characterIndex] = '0'
}
}
return string(code)
}
func ecmaScriptStartsRegex(prefix []byte) bool {
prefix = bytes.TrimSpace(prefix)
if len(prefix) == 0 || strings.ContainsRune("=([{,:;!?&|+-*%^~<>", rune(prefix[len(prefix)-1])) {
return true
}
// Check suffixes to avoid rescanning the expression for every slash.
for _, keyword := range []string{"return", "throw", "yield", "case", "typeof", "void", "delete"} {
if bytes.HasSuffix(prefix, []byte(keyword)) {
precedingCharacter, _ := utf8.DecodeLastRune(prefix[:len(prefix)-len(keyword)])
return len(prefix) == len(keyword) || unicode.IsSpace(precedingCharacter)
}
}
return false
}