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.
Files changed (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /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
+ }