gofront 1.8.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 (177) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -4
  3. package/src/backend/js/expressions.js +849 -371
  4. package/src/backend/js/index.js +241 -147
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +512 -2547
  7. package/src/backend/js/statements.js +506 -103
  8. package/src/backend/js/stdlib/index.js +45 -93
  9. package/src/backend/js/templ.js +32 -45
  10. package/src/backend/js/type-info.js +177 -13
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +63 -171
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +490 -965
  15. package/src/backend/wasm/emit-builtins.js +643 -256
  16. package/src/backend/wasm/emit-exprs.js +124 -57
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-stmts.js +325 -75
  19. package/src/backend/wasm/emit.js +104 -13
  20. package/src/backend/wasm/globals.js +47 -8
  21. package/src/backend/wasm/glue.js +2 -4
  22. package/src/backend/wasm/index.js +36 -530
  23. package/src/backend/wasm/method-expr.js +12 -1
  24. package/src/backend/wasm/module-emitter.js +92 -717
  25. package/src/backend/wasm/monomorph.js +103 -6
  26. package/src/backend/wasm/natives.js +596 -0
  27. package/src/backend/wasm/prescan.js +5 -153
  28. package/src/backend/wasm/prune-funcs.js +89 -0
  29. package/src/backend/wasm/stdlib/index.js +2 -32
  30. package/src/backend/wasm/types.js +68 -20
  31. package/src/backend/wasm/variadic.js +3 -3
  32. package/src/cli/cli-core.js +5 -1
  33. package/src/cli/test-runner.js +115 -342
  34. package/src/compiler.js +108 -130
  35. package/src/lexer/lexer.js +105 -11
  36. package/src/lexer/templ-lexer.js +61 -18
  37. package/src/lexer/tokens.js +1 -0
  38. package/src/link/stdlib.js +354 -132
  39. package/src/link/type-names.js +148 -0
  40. package/src/link/wasm.js +30 -6
  41. package/src/lower/bounds.js +153 -0
  42. package/src/lower/captures.js +92 -33
  43. package/src/lower/embedding.js +32 -3
  44. package/src/lower/errors-as.js +196 -0
  45. package/src/lower/fmt-formatters.js +905 -0
  46. package/src/lower/functions.js +2 -0
  47. package/src/lower/gen-types.js +274 -0
  48. package/src/lower/index.js +7 -1
  49. package/src/lower/json-codecs.js +228 -247
  50. package/src/lower/ownership.js +25 -7
  51. package/src/lower/reachability.js +69 -51
  52. package/src/lower/walk.js +12 -0
  53. package/src/parser/declarations.js +28 -5
  54. package/src/parser/expressions.js +86 -16
  55. package/src/parser/statements.js +1 -0
  56. package/src/parser/templ.js +44 -5
  57. package/src/parser/types.js +1 -0
  58. package/src/resolver.js +1 -2
  59. package/src/typechecker/assignability.js +124 -11
  60. package/src/typechecker/const-fold.js +70 -27
  61. package/src/typechecker/constants.js +32 -6
  62. package/src/typechecker/expressions.js +326 -98
  63. package/src/typechecker/index.js +208 -33
  64. package/src/typechecker/init-order.js +136 -40
  65. package/src/typechecker/operand-text.js +40 -0
  66. package/src/typechecker/resolve.js +192 -36
  67. package/src/typechecker/statements.js +122 -11
  68. package/src/typechecker/stdlib/excluded.js +9 -5
  69. package/src/typechecker/stdlib/index.js +25 -9
  70. package/src/typechecker/termination.js +10 -1
  71. package/src/typechecker/types.js +203 -573
  72. package/stdlib/bytes/buffer.go +479 -0
  73. package/stdlib/bytes/bytes.go +1010 -0
  74. package/stdlib/bytes/reader.go +161 -0
  75. package/stdlib/context/context.go +115 -0
  76. package/stdlib/crypto/rand/rand.go +34 -0
  77. package/stdlib/crypto/sha256/sha256.go +249 -0
  78. package/stdlib/encoding/base64/base64.go +331 -0
  79. package/stdlib/encoding/binary/binary.go +332 -0
  80. package/stdlib/encoding/hex/hex.go +140 -0
  81. package/stdlib/encoding/json/json.go +62 -0
  82. package/stdlib/errors/errors.go +174 -0
  83. package/stdlib/fmt/errors.go +110 -0
  84. package/stdlib/fmt/format.go +732 -0
  85. package/stdlib/fmt/print.go +1232 -0
  86. package/stdlib/gom/gom.go +293 -0
  87. package/stdlib/html/html.go +251 -0
  88. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  89. package/stdlib/internal/jsonrt/dec.go +171 -38
  90. package/stdlib/internal/jsonrt/enc.go +186 -36
  91. package/stdlib/internal/jsonrt/scanner.go +17 -8
  92. package/stdlib/io/io.go +157 -1
  93. package/stdlib/maps/maps.go +131 -0
  94. package/stdlib/math/bits/bits.go +507 -0
  95. package/stdlib/math/extra.go +16 -14
  96. package/stdlib/math/math.go +439 -0
  97. package/stdlib/math/rand/rand.go +297 -0
  98. package/stdlib/os/os.go +93 -0
  99. package/stdlib/path/filepath/filepath.go +47 -0
  100. package/stdlib/path/path.go +394 -0
  101. package/stdlib/regexp/regexp.go +231 -0
  102. package/stdlib/slices/slices.go +526 -0
  103. package/stdlib/slices/sort.go +209 -0
  104. package/stdlib/slices/zsort_cmp.go +480 -0
  105. package/stdlib/slices/zsort_ordered.go +482 -0
  106. package/stdlib/sort/sort.go +391 -452
  107. package/stdlib/sort/zsort_func.go +480 -0
  108. package/stdlib/sort/zsort_iface.go +480 -0
  109. package/stdlib/strconv/float.go +1699 -0
  110. package/stdlib/strconv/isprint.go +752 -0
  111. package/stdlib/strconv/quote.go +235 -50
  112. package/stdlib/strconv/strconv.go +616 -0
  113. package/stdlib/strings/builder.go +95 -0
  114. package/stdlib/strings/reader.go +163 -0
  115. package/stdlib/strings/replacer.go +102 -0
  116. package/stdlib/strings/strings.go +807 -0
  117. package/stdlib/sync/sync.go +268 -0
  118. package/stdlib/testing/async_js.go +61 -0
  119. package/stdlib/testing/benchmark.go +297 -0
  120. package/stdlib/testing/testing.go +523 -0
  121. package/stdlib/time/duration.go +233 -0
  122. package/stdlib/time/format.go +745 -0
  123. package/stdlib/time/parse.go +790 -0
  124. package/stdlib/time/sleep_js.go +63 -0
  125. package/stdlib/time/time.go +834 -0
  126. package/stdlib/unicode/unicode.go +141 -3
  127. package/stdlib/unicode/utf8/utf8.go +464 -0
  128. package/src/backend/js/fmt-runtime.js +0 -573
  129. package/src/backend/js/stdlib/base64.js +0 -12
  130. package/src/backend/js/stdlib/binary.js +0 -102
  131. package/src/backend/js/stdlib/bits.js +0 -119
  132. package/src/backend/js/stdlib/builder.js +0 -98
  133. package/src/backend/js/stdlib/bytes.js +0 -368
  134. package/src/backend/js/stdlib/errors.js +0 -45
  135. package/src/backend/js/stdlib/fmt.js +0 -517
  136. package/src/backend/js/stdlib/gom.js +0 -155
  137. package/src/backend/js/stdlib/hex.js +0 -17
  138. package/src/backend/js/stdlib/html.js +0 -20
  139. package/src/backend/js/stdlib/io.js +0 -137
  140. package/src/backend/js/stdlib/json.js +0 -1167
  141. package/src/backend/js/stdlib/maps.js +0 -37
  142. package/src/backend/js/stdlib/math.js +0 -85
  143. package/src/backend/js/stdlib/os.js +0 -13
  144. package/src/backend/js/stdlib/path.js +0 -48
  145. package/src/backend/js/stdlib/rand.js +0 -32
  146. package/src/backend/js/stdlib/regexp.js +0 -54
  147. package/src/backend/js/stdlib/sha256.js +0 -12
  148. package/src/backend/js/stdlib/shared.js +0 -17
  149. package/src/backend/js/stdlib/simd.js +0 -34
  150. package/src/backend/js/stdlib/slices.js +0 -107
  151. package/src/backend/js/stdlib/sort.js +0 -30
  152. package/src/backend/js/stdlib/strconv.js +0 -79
  153. package/src/backend/js/stdlib/strings.js +0 -301
  154. package/src/backend/js/stdlib/sync.js +0 -13
  155. package/src/backend/js/stdlib/testing.js +0 -41
  156. package/src/backend/js/stdlib/time.js +0 -152
  157. package/src/backend/js/stdlib/unicode.js +0 -25
  158. package/src/backend/js/stdlib/utf8.js +0 -26
  159. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  160. package/src/backend/wasm/stdlib/core.js +0 -10278
  161. package/src/backend/wasm/stdlib/io.js +0 -3578
  162. package/src/backend/wasm/stdlib/packages.js +0 -2402
  163. package/src/backend/wasm/stdlib/pure.js +0 -720
  164. package/src/backend/wasm/stdlib/time.js +0 -2229
  165. package/src/typechecker/stdlib/core.js +0 -1079
  166. package/src/typechecker/stdlib/extended.js +0 -1210
  167. package/stdlib/bytes/iter.go +0 -192
  168. package/stdlib/bytes/search.go +0 -240
  169. package/stdlib/bytes/split.go +0 -218
  170. package/stdlib/errors/overlay.go +0 -12
  171. package/stdlib/maps/iter.go +0 -65
  172. package/stdlib/slices/extra.go +0 -73
  173. package/stdlib/slices/iter.go +0 -113
  174. package/stdlib/strings/extra.go +0 -35
  175. package/stdlib/strings/iter.go +0 -122
  176. package/stdlib/sync/extra.go +0 -105
  177. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -4,45 +4,95 @@
4
4
 
5
5
  package strconv
6
6
 
7
- import (
8
- "unicode"
9
- "unicode/utf8"
10
- )
11
-
12
- // IntSize is the size in bits of an int or uint value.
13
- const IntSize = 64
7
+ import "unicode/utf8"
14
8
 
15
9
  const lowerhex = "0123456789abcdef"
16
10
 
17
- // A NumError records a failed conversion.
18
- type NumError struct {
19
- Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)
20
- Num string // the input
21
- Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
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
22
23
  }
23
24
 
24
- func (e *NumError) Error() string {
25
- return "strconv." + e.Func + ": parsing " + Quote(e.Num) + ": " + e.Err.Error()
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
26
37
  }
27
38
 
28
- func (e *NumError) Unwrap() error { return e.Err }
29
-
30
39
  // IsPrint reports whether the rune is defined as printable by Go, with
31
- // the same definition as unicode.IsPrint: letters, numbers, punctuation,
40
+ // the same definition as [unicode.IsPrint]: letters, numbers, punctuation,
32
41
  // symbols and ASCII space.
33
42
  func IsPrint(r rune) bool {
34
- if 0x20 <= r && r <= 0x7E {
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 {
35
76
  return true
36
77
  }
37
- return unicode.IsPrint(r)
78
+ r -= 0x10000
79
+ _, found := bsearch16(isNotPrint32, uint16(r))
80
+ return !found
38
81
  }
39
82
 
40
- // IsGraphic reports whether the rune is defined as a Graphic by Unicode.
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.
41
86
  func IsGraphic(r rune) bool {
42
- if 0x20 <= r && r <= 0x7E {
87
+ if IsPrint(r) {
43
88
  return true
44
89
  }
45
- return unicode.IsGraphic(r)
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
46
96
  }
47
97
 
48
98
  func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
@@ -61,7 +111,9 @@ func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly b
61
111
  buf = append(buf, quote)
62
112
  for len(s) > 0 {
63
113
  r, width := utf8.DecodeRuneInString(s)
64
- if width == 1 && r == utf8.RuneError {
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 {
65
117
  b0 := int(byte(s[0]))
66
118
  buf = append(buf, byte('\\'), byte('x'), hexDigit(b0>>4), hexDigit(b0))
67
119
  s = s[1:]
@@ -138,6 +190,13 @@ func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bo
138
190
  return buf
139
191
  }
140
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
+
141
200
  // QuoteRune returns a single-quoted Go character literal representing the rune.
142
201
  func QuoteRune(r rune) string {
143
202
  return quoteRuneWith(r, byte('\''), false, false)
@@ -178,10 +237,10 @@ func CanBackquote(s string) bool {
178
237
  for len(s) > 0 {
179
238
  r, wid := utf8.DecodeRuneInString(s)
180
239
  s = s[wid:]
240
+ if r == '\ufeff' {
241
+ return false
242
+ }
181
243
  if wid > 1 {
182
- if r == '\ufeff' {
183
- return false
184
- }
185
244
  continue
186
245
  }
187
246
  if r == utf8.RuneError {
@@ -221,6 +280,9 @@ func unquoteHex(c byte, s string) (rune, bool, string, error) {
221
280
  }
222
281
  var v rune
223
282
  for j := 0; j < n; j++ {
283
+ if s[j] >= utf8.RuneSelf {
284
+ return 0, false, "", ErrSyntax
285
+ }
224
286
  x, ok := unhex(byte(s[j]))
225
287
  if !ok {
226
288
  return 0, false, "", ErrSyntax
@@ -243,6 +305,9 @@ func unquoteOctal(c byte, s string) (rune, string, error) {
243
305
  return 0, "", ErrSyntax
244
306
  }
245
307
  for j := 0; j < 2; j++ {
308
+ if s[j] >= utf8.RuneSelf {
309
+ return 0, "", ErrSyntax
310
+ }
246
311
  b := byte(s[j])
247
312
  if b < byte('0') || b > byte('7') {
248
313
  return 0, "", ErrSyntax
@@ -260,20 +325,24 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
260
325
  if len(s) == 0 {
261
326
  return 0, false, "", ErrSyntax
262
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
+ }
263
333
  c := byte(s[0])
264
334
  if c == quote && (quote == byte('\'') || quote == byte('"')) {
265
335
  return 0, false, "", ErrSyntax
266
336
  }
267
- if rune(c) >= utf8.RuneSelf {
268
- r, size := utf8.DecodeRuneInString(s)
269
- return r, true, s[size:], nil
270
- }
271
337
  if c != byte('\\') {
272
338
  return rune(c), false, s[1:], nil
273
339
  }
274
340
  if len(s) <= 1 {
275
341
  return 0, false, "", ErrSyntax
276
342
  }
343
+ if s[1] >= utf8.RuneSelf {
344
+ return 0, false, "", ErrSyntax
345
+ }
277
346
  esc := byte(s[1])
278
347
  s = s[2:]
279
348
  switch esc {
@@ -309,33 +378,149 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
309
378
  }
310
379
  }
311
380
 
312
- // QuotedPrefix returns the quoted string at the prefix of s.
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.
313
383
  func QuotedPrefix(s string) (string, error) {
314
- if len(s) < 2 {
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 {
315
397
  return "", ErrSyntax
316
398
  }
317
- quote := byte(s[0])
318
- if quote != byte('"') && quote != byte('\'') && quote != byte('`') {
319
- return "", ErrSyntax
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
320
413
  }
321
- if quote == byte('`') {
322
- for i := 1; i < len(s); i++ {
323
- if byte(s[i]) == byte('`') {
324
- return s[:i+1], nil
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
+ }
325
440
  }
441
+ out += in[start : end-len("`")]
326
442
  }
327
- return "", ErrSyntax
328
- }
329
- rem := s[1:]
330
- for len(rem) > 0 {
331
- if byte(rem[0]) == quote {
332
- return s[:len(s)-len(rem)+1], nil
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
+ }
333
467
  }
334
- _, _, next, err := UnquoteChar(rem, quote)
335
- if err != nil {
336
- return "", err
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
337
519
  }
338
- rem = next
339
520
  }
340
- return "", ErrSyntax
521
+ return -1
522
+ }
523
+
524
+ func containsByte(s string, c byte) bool {
525
+ return indexByte(s, c) >= 0
341
526
  }