gofront 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +500 -0
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +526 -0
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
package strconv
|
|
6
|
+
|
|
7
|
+
import "unicode/utf8"
|
|
8
|
+
|
|
9
|
+
const lowerhex = "0123456789abcdef"
|
|
10
|
+
|
|
11
|
+
func bsearch16(s []uint16, v uint16) (int, bool) {
|
|
12
|
+
n := len(s)
|
|
13
|
+
i, j := 0, n
|
|
14
|
+
for i < j {
|
|
15
|
+
h := i + (j-i)>>1
|
|
16
|
+
if s[h] < v {
|
|
17
|
+
i = h + 1
|
|
18
|
+
} else {
|
|
19
|
+
j = h
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return i, i < n && s[i] == v
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func bsearch32(s []uint32, v uint32) (int, bool) {
|
|
26
|
+
n := len(s)
|
|
27
|
+
i, j := 0, n
|
|
28
|
+
for i < j {
|
|
29
|
+
h := i + (j-i)>>1
|
|
30
|
+
if s[h] < v {
|
|
31
|
+
i = h + 1
|
|
32
|
+
} else {
|
|
33
|
+
j = h
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return i, i < n && s[i] == v
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// IsPrint reports whether the rune is defined as printable by Go, with
|
|
40
|
+
// the same definition as [unicode.IsPrint]: letters, numbers, punctuation,
|
|
41
|
+
// symbols and ASCII space.
|
|
42
|
+
func IsPrint(r rune) bool {
|
|
43
|
+
// Fast check for Latin-1
|
|
44
|
+
if r <= 0xFF {
|
|
45
|
+
if 0x20 <= r && r <= 0x7E {
|
|
46
|
+
// All the ASCII is printable from space through DEL-1.
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
if 0xA1 <= r && r <= 0xFF {
|
|
50
|
+
// Similarly for ¡ through ÿ...
|
|
51
|
+
return r != 0xAD // ...except for the bizarre soft hyphen.
|
|
52
|
+
}
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// First, find first i such that isPrint[i] >= x.
|
|
57
|
+
// This is the index of either the start or end of a pair that might span x.
|
|
58
|
+
// The start is even (isPrint[i&^1]) and the end is odd (isPrint[i|1]).
|
|
59
|
+
// If we find x in a range, make sure x is not in isNotPrint list.
|
|
60
|
+
if 0 <= r && r < 1<<16 {
|
|
61
|
+
rr := uint16(r)
|
|
62
|
+
i, _ := bsearch16(isPrint16, rr)
|
|
63
|
+
if i >= len(isPrint16) || rr < isPrint16[i&^1] || isPrint16[i|1] < rr {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
_, found := bsearch16(isNotPrint16, rr)
|
|
67
|
+
return !found
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
rr := uint32(r)
|
|
71
|
+
i, _ := bsearch32(isPrint32, rr)
|
|
72
|
+
if i >= len(isPrint32) || rr < isPrint32[i&^1] || isPrint32[i|1] < rr {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
if r >= 0x20000 {
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
r -= 0x10000
|
|
79
|
+
_, found := bsearch16(isNotPrint32, uint16(r))
|
|
80
|
+
return !found
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such
|
|
84
|
+
// characters include letters, marks, numbers, punctuation, symbols, and
|
|
85
|
+
// spaces, from categories L, M, N, P, S, and Zs.
|
|
86
|
+
func IsGraphic(r rune) bool {
|
|
87
|
+
if IsPrint(r) {
|
|
88
|
+
return true
|
|
89
|
+
}
|
|
90
|
+
// We know r must fit in 16 bits - see makeisprint.go.
|
|
91
|
+
if r > 0xFFFF {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
_, found := bsearch16(isGraphic, uint16(r))
|
|
95
|
+
return found
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
|
|
99
|
+
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string {
|
|
103
|
+
return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func hexDigit(v int) byte {
|
|
107
|
+
return byte(lowerhex[v&0xF])
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
|
|
111
|
+
buf = append(buf, quote)
|
|
112
|
+
for len(s) > 0 {
|
|
113
|
+
r, width := utf8.DecodeRuneInString(s)
|
|
114
|
+
// A U+FFFD that is in the string, not an invalid byte, has width 1 where
|
|
115
|
+
// a string is made of UTF-16 units.
|
|
116
|
+
if width == 1 && r == utf8.RuneError && rune(s[0]) != utf8.RuneError {
|
|
117
|
+
b0 := int(byte(s[0]))
|
|
118
|
+
buf = append(buf, byte('\\'), byte('x'), hexDigit(b0>>4), hexDigit(b0))
|
|
119
|
+
s = s[1:]
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly)
|
|
123
|
+
s = s[width:]
|
|
124
|
+
}
|
|
125
|
+
buf = append(buf, quote)
|
|
126
|
+
return buf
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
|
|
130
|
+
buf = append(buf, quote)
|
|
131
|
+
if !utf8.ValidRune(r) {
|
|
132
|
+
r = utf8.RuneError
|
|
133
|
+
}
|
|
134
|
+
buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly)
|
|
135
|
+
buf = append(buf, quote)
|
|
136
|
+
return buf
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
|
|
140
|
+
if r == rune(quote) || r == '\\' {
|
|
141
|
+
buf = append(buf, byte('\\'), byte(r))
|
|
142
|
+
return buf
|
|
143
|
+
}
|
|
144
|
+
if ASCIIonly {
|
|
145
|
+
if r < utf8.RuneSelf && IsPrint(r) {
|
|
146
|
+
buf = append(buf, byte(r))
|
|
147
|
+
return buf
|
|
148
|
+
}
|
|
149
|
+
} else if IsPrint(r) || (graphicOnly && IsGraphic(r)) {
|
|
150
|
+
return utf8.AppendRune(buf, r)
|
|
151
|
+
}
|
|
152
|
+
switch r {
|
|
153
|
+
case '\a':
|
|
154
|
+
buf = append(buf, byte('\\'), byte('a'))
|
|
155
|
+
case '\b':
|
|
156
|
+
buf = append(buf, byte('\\'), byte('b'))
|
|
157
|
+
case '\f':
|
|
158
|
+
buf = append(buf, byte('\\'), byte('f'))
|
|
159
|
+
case '\n':
|
|
160
|
+
buf = append(buf, byte('\\'), byte('n'))
|
|
161
|
+
case '\r':
|
|
162
|
+
buf = append(buf, byte('\\'), byte('r'))
|
|
163
|
+
case '\t':
|
|
164
|
+
buf = append(buf, byte('\\'), byte('t'))
|
|
165
|
+
case '\v':
|
|
166
|
+
buf = append(buf, byte('\\'), byte('v'))
|
|
167
|
+
default:
|
|
168
|
+
switch {
|
|
169
|
+
case r < ' ' || r == 0x7f:
|
|
170
|
+
br := int(r)
|
|
171
|
+
buf = append(buf, byte('\\'), byte('x'), hexDigit(br>>4), hexDigit(br))
|
|
172
|
+
case !utf8.ValidRune(r):
|
|
173
|
+
r = 0xFFFD
|
|
174
|
+
buf = append(buf, byte('\\'), byte('u'))
|
|
175
|
+
for s := 12; s >= 0; s -= 4 {
|
|
176
|
+
buf = append(buf, hexDigit(int(r>>uint(s))))
|
|
177
|
+
}
|
|
178
|
+
case r < 0x10000:
|
|
179
|
+
buf = append(buf, byte('\\'), byte('u'))
|
|
180
|
+
for s := 12; s >= 0; s -= 4 {
|
|
181
|
+
buf = append(buf, hexDigit(int(r>>uint(s))))
|
|
182
|
+
}
|
|
183
|
+
default:
|
|
184
|
+
buf = append(buf, byte('\\'), byte('U'))
|
|
185
|
+
for s := 28; s >= 0; s -= 4 {
|
|
186
|
+
buf = append(buf, hexDigit(int(r>>uint(s))))
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return buf
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Quote returns a double-quoted Go string literal representing s. The
|
|
194
|
+
// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
|
|
195
|
+
// control characters and non-printable characters as defined by [IsPrint].
|
|
196
|
+
func Quote(s string) string {
|
|
197
|
+
return quoteWith(s, byte('"'), false, false)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// QuoteRune returns a single-quoted Go character literal representing the rune.
|
|
201
|
+
func QuoteRune(r rune) string {
|
|
202
|
+
return quoteRuneWith(r, byte('\''), false, false)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// QuoteToASCII returns a double-quoted Go string literal representing s using ASCII escapes.
|
|
206
|
+
func QuoteToASCII(s string) string {
|
|
207
|
+
return quoteWith(s, byte('"'), true, false)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// QuoteRuneToASCII returns a single-quoted Go character literal representing the rune using ASCII escapes.
|
|
211
|
+
func QuoteRuneToASCII(r rune) string {
|
|
212
|
+
return quoteRuneWith(r, byte('\''), true, false)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// AppendQuote appends a double-quoted Go string literal representing s to dst.
|
|
216
|
+
func AppendQuote(dst []byte, s string) []byte {
|
|
217
|
+
return appendQuotedWith(dst, s, byte('"'), false, false)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// AppendQuoteToASCII appends a double-quoted Go string literal representing s using ASCII escapes to dst.
|
|
221
|
+
func AppendQuoteToASCII(dst []byte, s string) []byte {
|
|
222
|
+
return appendQuotedWith(dst, s, byte('"'), true, false)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// AppendQuoteRune appends a single-quoted Go character literal representing the rune to dst.
|
|
226
|
+
func AppendQuoteRune(dst []byte, r rune) []byte {
|
|
227
|
+
return appendQuotedRuneWith(dst, r, byte('\''), false, false)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune using ASCII escapes to dst.
|
|
231
|
+
func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
|
|
232
|
+
return appendQuotedRuneWith(dst, r, byte('\''), true, false)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// CanBackquote reports whether the string s can be represented unchanged as a single-line backquoted string.
|
|
236
|
+
func CanBackquote(s string) bool {
|
|
237
|
+
for len(s) > 0 {
|
|
238
|
+
r, wid := utf8.DecodeRuneInString(s)
|
|
239
|
+
s = s[wid:]
|
|
240
|
+
if r == '\ufeff' {
|
|
241
|
+
return false
|
|
242
|
+
}
|
|
243
|
+
if wid > 1 {
|
|
244
|
+
continue
|
|
245
|
+
}
|
|
246
|
+
if r == utf8.RuneError {
|
|
247
|
+
return false
|
|
248
|
+
}
|
|
249
|
+
if (r < ' ' && r != '\t') || r == '`' || r == '\u007F' {
|
|
250
|
+
return false
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return true
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
func unhex(b byte) (rune, bool) {
|
|
257
|
+
switch {
|
|
258
|
+
case byte('0') <= b && b <= byte('9'):
|
|
259
|
+
return rune(b - byte('0')), true
|
|
260
|
+
case byte('a') <= b && b <= byte('f'):
|
|
261
|
+
return rune(b - byte('a') + 10), true
|
|
262
|
+
case byte('A') <= b && b <= byte('F'):
|
|
263
|
+
return rune(b - byte('A') + 10), true
|
|
264
|
+
}
|
|
265
|
+
return 0, false
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
func unquoteHex(c byte, s string) (rune, bool, string, error) {
|
|
269
|
+
n := 0
|
|
270
|
+
switch c {
|
|
271
|
+
case byte('x'):
|
|
272
|
+
n = 2
|
|
273
|
+
case byte('u'):
|
|
274
|
+
n = 4
|
|
275
|
+
case byte('U'):
|
|
276
|
+
n = 8
|
|
277
|
+
}
|
|
278
|
+
if len(s) < n {
|
|
279
|
+
return 0, false, "", ErrSyntax
|
|
280
|
+
}
|
|
281
|
+
var v rune
|
|
282
|
+
for j := 0; j < n; j++ {
|
|
283
|
+
if s[j] >= utf8.RuneSelf {
|
|
284
|
+
return 0, false, "", ErrSyntax
|
|
285
|
+
}
|
|
286
|
+
x, ok := unhex(byte(s[j]))
|
|
287
|
+
if !ok {
|
|
288
|
+
return 0, false, "", ErrSyntax
|
|
289
|
+
}
|
|
290
|
+
v = v<<4 | x
|
|
291
|
+
}
|
|
292
|
+
s = s[n:]
|
|
293
|
+
if c == byte('x') {
|
|
294
|
+
return v, false, s, nil
|
|
295
|
+
}
|
|
296
|
+
if !utf8.ValidRune(v) {
|
|
297
|
+
return 0, false, "", ErrSyntax
|
|
298
|
+
}
|
|
299
|
+
return v, true, s, nil
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
func unquoteOctal(c byte, s string) (rune, string, error) {
|
|
303
|
+
v := rune(c - byte('0'))
|
|
304
|
+
if len(s) < 2 {
|
|
305
|
+
return 0, "", ErrSyntax
|
|
306
|
+
}
|
|
307
|
+
for j := 0; j < 2; j++ {
|
|
308
|
+
if s[j] >= utf8.RuneSelf {
|
|
309
|
+
return 0, "", ErrSyntax
|
|
310
|
+
}
|
|
311
|
+
b := byte(s[j])
|
|
312
|
+
if b < byte('0') || b > byte('7') {
|
|
313
|
+
return 0, "", ErrSyntax
|
|
314
|
+
}
|
|
315
|
+
v = (v << 3) | rune(b-byte('0'))
|
|
316
|
+
}
|
|
317
|
+
if v > 255 {
|
|
318
|
+
return 0, "", ErrSyntax
|
|
319
|
+
}
|
|
320
|
+
return v, s[2:], nil
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// UnquoteChar decodes the first character or byte in the escaped string or character literal represented by s.
|
|
324
|
+
func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
|
|
325
|
+
if len(s) == 0 {
|
|
326
|
+
return 0, false, "", ErrSyntax
|
|
327
|
+
}
|
|
328
|
+
// A string index is a UTF-16 unit: decide on it before narrowing to a byte.
|
|
329
|
+
if s[0] >= utf8.RuneSelf {
|
|
330
|
+
r, size := utf8.DecodeRuneInString(s)
|
|
331
|
+
return r, true, s[size:], nil
|
|
332
|
+
}
|
|
333
|
+
c := byte(s[0])
|
|
334
|
+
if c == quote && (quote == byte('\'') || quote == byte('"')) {
|
|
335
|
+
return 0, false, "", ErrSyntax
|
|
336
|
+
}
|
|
337
|
+
if c != byte('\\') {
|
|
338
|
+
return rune(c), false, s[1:], nil
|
|
339
|
+
}
|
|
340
|
+
if len(s) <= 1 {
|
|
341
|
+
return 0, false, "", ErrSyntax
|
|
342
|
+
}
|
|
343
|
+
if s[1] >= utf8.RuneSelf {
|
|
344
|
+
return 0, false, "", ErrSyntax
|
|
345
|
+
}
|
|
346
|
+
esc := byte(s[1])
|
|
347
|
+
s = s[2:]
|
|
348
|
+
switch esc {
|
|
349
|
+
case byte('a'):
|
|
350
|
+
return '\a', false, s, nil
|
|
351
|
+
case byte('b'):
|
|
352
|
+
return '\b', false, s, nil
|
|
353
|
+
case byte('f'):
|
|
354
|
+
return '\f', false, s, nil
|
|
355
|
+
case byte('n'):
|
|
356
|
+
return '\n', false, s, nil
|
|
357
|
+
case byte('r'):
|
|
358
|
+
return '\r', false, s, nil
|
|
359
|
+
case byte('t'):
|
|
360
|
+
return '\t', false, s, nil
|
|
361
|
+
case byte('v'):
|
|
362
|
+
return '\v', false, s, nil
|
|
363
|
+
case byte('x'), byte('u'), byte('U'):
|
|
364
|
+
v, mb, rem, err := unquoteHex(esc, s)
|
|
365
|
+
return v, mb, rem, err
|
|
366
|
+
case byte('0'), byte('1'), byte('2'), byte('3'), byte('4'), byte('5'), byte('6'), byte('7'):
|
|
367
|
+
v, rem, err := unquoteOctal(esc, s)
|
|
368
|
+
return v, false, rem, err
|
|
369
|
+
case byte('\\'):
|
|
370
|
+
return '\\', false, s, nil
|
|
371
|
+
case byte('\''), byte('"'):
|
|
372
|
+
if esc != quote {
|
|
373
|
+
return 0, false, "", ErrSyntax
|
|
374
|
+
}
|
|
375
|
+
return rune(esc), false, s, nil
|
|
376
|
+
default:
|
|
377
|
+
return 0, false, "", ErrSyntax
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// QuotedPrefix returns the quoted string (as understood by [Unquote]) at the prefix of s.
|
|
382
|
+
// If s does not start with a valid quoted string, QuotedPrefix returns an error.
|
|
383
|
+
func QuotedPrefix(s string) (string, error) {
|
|
384
|
+
out, _, err := unquote(s, false)
|
|
385
|
+
return out, err
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Unquote interprets s as a single-quoted, double-quoted,
|
|
389
|
+
// or backquoted Go string literal, returning the string value
|
|
390
|
+
// that s quotes. (If s is single-quoted, it would be a Go
|
|
391
|
+
// character literal; Unquote returns the corresponding
|
|
392
|
+
// one-character string. For an empty character literal
|
|
393
|
+
// Unquote returns the empty string.)
|
|
394
|
+
func Unquote(s string) (string, error) {
|
|
395
|
+
out, rem, err := unquote(s, true)
|
|
396
|
+
if len(rem) > 0 {
|
|
397
|
+
return "", ErrSyntax
|
|
398
|
+
}
|
|
399
|
+
return out, err
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// unquote parses a quoted string at the start of the input,
|
|
403
|
+
// returning the parsed prefix, the remaining suffix, and any parse errors.
|
|
404
|
+
// If unescape is true, the parsed prefix is unescaped,
|
|
405
|
+
// otherwise the input prefix is provided verbatim.
|
|
406
|
+
func unquote(in string, unescape bool) (out, rem string, err error) {
|
|
407
|
+
// Determine the quote form and optimistically find the terminating quote.
|
|
408
|
+
if len(in) < 2 {
|
|
409
|
+
return "", in, ErrSyntax
|
|
410
|
+
}
|
|
411
|
+
if in[0] > 0x7F {
|
|
412
|
+
return "", in, ErrSyntax
|
|
413
|
+
}
|
|
414
|
+
quote := byte(in[0])
|
|
415
|
+
end := indexByte(in[1:], quote)
|
|
416
|
+
if end < 0 {
|
|
417
|
+
return "", in, ErrSyntax
|
|
418
|
+
}
|
|
419
|
+
end += 2 // position after terminating quote; may be wrong if escape sequences are present
|
|
420
|
+
|
|
421
|
+
switch quote {
|
|
422
|
+
case '`':
|
|
423
|
+
switch {
|
|
424
|
+
case !unescape:
|
|
425
|
+
out = in[:end] // include quotes
|
|
426
|
+
case !containsByte(in[:end], '\r'):
|
|
427
|
+
out = in[len("`") : end-len("`")] // exclude quotes
|
|
428
|
+
default:
|
|
429
|
+
// Carriage return characters ('\r') inside raw string literals
|
|
430
|
+
// are discarded from the raw string value.
|
|
431
|
+
// Built as a string: GoFront strings are indexed by UTF-16 unit, so
|
|
432
|
+
// a byte buffer would split multi-byte text.
|
|
433
|
+
out = ""
|
|
434
|
+
start := len("`")
|
|
435
|
+
for i := len("`"); i < end-len("`"); i++ {
|
|
436
|
+
if in[i] == '\r' {
|
|
437
|
+
out += in[start:i]
|
|
438
|
+
start = i + 1
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
out += in[start : end-len("`")]
|
|
442
|
+
}
|
|
443
|
+
// NOTE: Prior implementations did not verify that raw strings consist
|
|
444
|
+
// of valid UTF-8 characters and we continue to not verify it as such.
|
|
445
|
+
// The Go specification does not explicitly require valid UTF-8,
|
|
446
|
+
// but only mention that it is implicitly valid for Go source code
|
|
447
|
+
// (which must be valid UTF-8).
|
|
448
|
+
return out, in[end:], nil
|
|
449
|
+
case '"', '\'':
|
|
450
|
+
// Handle quoted strings without any escape sequences.
|
|
451
|
+
if !containsByte(in[:end], '\\') && !containsByte(in[:end], '\n') {
|
|
452
|
+
var valid bool
|
|
453
|
+
switch quote {
|
|
454
|
+
case '"':
|
|
455
|
+
valid = utf8.ValidString(in[len(`"`) : end-len(`"`)])
|
|
456
|
+
case '\'':
|
|
457
|
+
r, n := utf8.DecodeRuneInString(in[len("'") : end-len("'")])
|
|
458
|
+
valid = len("'")+n+len("'") == end && (r != utf8.RuneError || n != 1)
|
|
459
|
+
}
|
|
460
|
+
if valid {
|
|
461
|
+
out = in[:end]
|
|
462
|
+
if unescape {
|
|
463
|
+
out = out[1 : end-1] // exclude quotes
|
|
464
|
+
}
|
|
465
|
+
return out, in[end:], nil
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Handle quoted strings with escape sequences.
|
|
470
|
+
var buf []byte
|
|
471
|
+
in0 := in
|
|
472
|
+
in = in[1:] // skip starting quote
|
|
473
|
+
if unescape {
|
|
474
|
+
buf = make([]byte, 0, 3*end/2) // try to avoid more allocations
|
|
475
|
+
}
|
|
476
|
+
for len(in) > 0 && in[0] != quote {
|
|
477
|
+
// Process the next character,
|
|
478
|
+
// rejecting any unescaped newline characters which are invalid.
|
|
479
|
+
r, multibyte, rem, err := UnquoteChar(in, quote)
|
|
480
|
+
if in[0] == '\n' || err != nil {
|
|
481
|
+
return "", in0, ErrSyntax
|
|
482
|
+
}
|
|
483
|
+
in = rem
|
|
484
|
+
|
|
485
|
+
// Append the character if unescaping the input.
|
|
486
|
+
if unescape {
|
|
487
|
+
if r < utf8.RuneSelf || !multibyte {
|
|
488
|
+
buf = append(buf, byte(r))
|
|
489
|
+
} else {
|
|
490
|
+
buf = utf8.AppendRune(buf, r)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Single quoted strings must be a single character.
|
|
495
|
+
if quote == '\'' {
|
|
496
|
+
break
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Verify that the string ends with a terminating quote.
|
|
501
|
+
if !(len(in) > 0 && in[0] == quote) {
|
|
502
|
+
return "", in0, ErrSyntax
|
|
503
|
+
}
|
|
504
|
+
in = in[1:] // skip terminating quote
|
|
505
|
+
|
|
506
|
+
if unescape {
|
|
507
|
+
return string(buf), in, nil
|
|
508
|
+
}
|
|
509
|
+
return in0[:len(in0)-len(in)], in, nil
|
|
510
|
+
default:
|
|
511
|
+
return "", in, ErrSyntax
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
func indexByte(s string, c byte) int {
|
|
516
|
+
for i := 0; i < len(s); i++ {
|
|
517
|
+
if s[i] == c {
|
|
518
|
+
return i
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return -1
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
func containsByte(s string, c byte) bool {
|
|
525
|
+
return indexByte(s, c) >= 0
|
|
526
|
+
}
|