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,616 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target both
4
+
5
+ // Package strconv implements conversions to and from string representations
6
+ // of basic data types, written in Go over the real package's algorithms.
7
+ // Float formatting and parsing keep a host fast path as natives.
8
+ package strconv
9
+
10
+ import (
11
+ "errors"
12
+ "math/bits"
13
+ )
14
+
15
+ // IntSize is the size in bits of an int or uint value.
16
+ const IntSize = 64
17
+
18
+ const maxUint64 = 1<<64 - 1
19
+
20
+ // ErrRange indicates that a value is out of range for the target type.
21
+ var ErrRange = errors.New("value out of range")
22
+
23
+ // ErrSyntax indicates that a value does not have the right syntax for the target type.
24
+ var ErrSyntax = errors.New("invalid syntax")
25
+
26
+ // A NumError records a failed conversion.
27
+ type NumError struct {
28
+ Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)
29
+ Num string // the input
30
+ Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
31
+ }
32
+
33
+ func (e *NumError) Error() string {
34
+ return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
35
+ }
36
+
37
+ func (e *NumError) Unwrap() error { return e.Err }
38
+
39
+ func syntaxError(fn, str string) *NumError {
40
+ return &NumError{fn, str, ErrSyntax}
41
+ }
42
+
43
+ func rangeError(fn, str string) *NumError {
44
+ return &NumError{fn, str, ErrRange}
45
+ }
46
+
47
+ func baseError(fn, str string, base int) *NumError {
48
+ return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
49
+ }
50
+
51
+ func bitSizeError(fn, str string, bitSize int) *NumError {
52
+ return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
53
+ }
54
+
55
+ // The parsers report one of these codes; toError turns it into the
56
+ // *NumError the package's API promises.
57
+ type parseCode int
58
+
59
+ const (
60
+ codeNone parseCode = iota
61
+ codeRange
62
+ codeSyntax
63
+ codeBase
64
+ codeBitSize
65
+ )
66
+
67
+ func toError(fn, s string, base, bitSize int, code parseCode) error {
68
+ switch code {
69
+ case codeNone:
70
+ return nil
71
+ case codeSyntax:
72
+ return syntaxError(fn, s)
73
+ case codeRange:
74
+ return rangeError(fn, s)
75
+ case codeBase:
76
+ return baseError(fn, s, base)
77
+ case codeBitSize:
78
+ return bitSizeError(fn, s, bitSize)
79
+ }
80
+ return nil
81
+ }
82
+
83
+ // ParseBool returns the boolean value represented by the string.
84
+ // It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
85
+ // Any other value returns an error.
86
+ func ParseBool(str string) (bool, error) {
87
+ switch str {
88
+ case "1", "t", "T", "true", "TRUE", "True":
89
+ return true, nil
90
+ case "0", "f", "F", "false", "FALSE", "False":
91
+ return false, nil
92
+ }
93
+ return false, syntaxError("ParseBool", str)
94
+ }
95
+
96
+ // FormatBool returns "true" or "false" according to the value of b.
97
+ func FormatBool(b bool) string {
98
+ if b {
99
+ return "true"
100
+ }
101
+ return "false"
102
+ }
103
+
104
+ // AppendBool appends "true" or "false", according to the value of b,
105
+ // to dst and returns the extended buffer.
106
+ func AppendBool(dst []byte, b bool) []byte {
107
+ if b {
108
+ return append(dst, "true"...)
109
+ }
110
+ return append(dst, "false"...)
111
+ }
112
+
113
+ // lower(c) is a lower-case letter if and only if
114
+ // c is either that lower-case letter or the equivalent upper-case letter.
115
+ // Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'.
116
+ // Note that lower of non-letters can produce other non-letters.
117
+ func lowerS(c byte) byte {
118
+ return c | ('x' - 'X')
119
+ }
120
+
121
+ func lower(c byte) byte {
122
+ return c | ('x' - 'X')
123
+ }
124
+
125
+ // ParseUint is like [ParseInt] but for unsigned numbers.
126
+ //
127
+ // A sign prefix is not permitted.
128
+ func ParseUint(s string, base int, bitSize int) (uint64, error) {
129
+ x, code := parseUint(s, base, bitSize)
130
+ if code != codeNone {
131
+ return x, toError("ParseUint", s, base, bitSize, code)
132
+ }
133
+ return x, nil
134
+ }
135
+
136
+ // ParseInt interprets a string s in the given base (0, 2 to 36) and
137
+ // bit size (0 to 64) and returns the corresponding value i.
138
+ //
139
+ // The string may begin with a leading sign: "+" or "-".
140
+ //
141
+ // If the base argument is 0, the true base is implied by the string's
142
+ // prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o",
143
+ // 16 for "0x", and 10 otherwise. Also, for argument base 0 only,
144
+ // underscore characters are permitted as defined by the Go syntax for
145
+ // integer literals.
146
+ //
147
+ // The bitSize argument specifies the integer type
148
+ // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
149
+ // correspond to int, int8, int16, int32, and int64.
150
+ // If bitSize is below 0 or above 64, an error is returned.
151
+ //
152
+ // The errors that ParseInt returns have concrete type [*NumError]
153
+ // and include err.Num = s. If s is empty or contains invalid
154
+ // digits, err.Err = [ErrSyntax] and the returned value is 0;
155
+ // if the value corresponding to s cannot be represented by a
156
+ // signed integer of the given size, err.Err = [ErrRange] and the
157
+ // returned value is the maximum magnitude integer of the
158
+ // appropriate bitSize and sign.
159
+ func ParseInt(s string, base int, bitSize int) (i int64, err error) {
160
+ x, code := parseInt(s, base, bitSize)
161
+ if code != codeNone {
162
+ return x, toError("ParseInt", s, base, bitSize, code)
163
+ }
164
+ return x, nil
165
+ }
166
+
167
+ // Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
168
+ func Atoi(s string) (int, error) {
169
+ x, code := atoi(s)
170
+ if code != codeNone {
171
+ return x, toError("Atoi", s, 0, 0, code)
172
+ }
173
+ return x, nil
174
+ }
175
+
176
+ func parseUint(s string, base int, bitSize int) (uint64, parseCode) {
177
+ if s == "" {
178
+ return 0, codeSyntax
179
+ }
180
+
181
+ base0 := base == 0
182
+
183
+ s0 := s
184
+ switch {
185
+ case 2 <= base && base <= 36:
186
+ // valid base; nothing to do
187
+
188
+ case base == 0:
189
+ // Look for octal, hex prefix.
190
+ base = 10
191
+ if s[0] == '0' {
192
+ switch {
193
+ case len(s) >= 3 && lowerS(s[1]) == 'b':
194
+ base = 2
195
+ s = s[2:]
196
+ case len(s) >= 3 && lowerS(s[1]) == 'o':
197
+ base = 8
198
+ s = s[2:]
199
+ case len(s) >= 3 && lowerS(s[1]) == 'x':
200
+ base = 16
201
+ s = s[2:]
202
+ default:
203
+ base = 8
204
+ s = s[1:]
205
+ }
206
+ }
207
+
208
+ default:
209
+ return 0, codeBase
210
+ }
211
+
212
+ if bitSize == 0 {
213
+ bitSize = IntSize
214
+ } else if bitSize < 0 || bitSize > 64 {
215
+ return 0, codeBitSize
216
+ }
217
+
218
+ // Cutoff is the smallest number such that cutoff*base > maxUint64.
219
+ // Use compile-time constants for common cases.
220
+ var cutoff uint64
221
+ switch base {
222
+ case 10:
223
+ cutoff = maxUint64/10 + 1
224
+ case 16:
225
+ cutoff = maxUint64/16 + 1
226
+ default:
227
+ cutoff = ^uint64(0)/uint64(base) + 1
228
+ }
229
+
230
+ maxVal := uint64(1)<<uint(bitSize) - 1
231
+
232
+ underscores := false
233
+ var n uint64
234
+ for _, c := range []byte(s) {
235
+ var d byte
236
+ switch {
237
+ case c == '_' && base0:
238
+ underscores = true
239
+ continue
240
+ case '0' <= c && c <= '9':
241
+ d = c - '0'
242
+ case 'a' <= lower(c) && lower(c) <= 'z':
243
+ d = lower(c) - 'a' + 10
244
+ default:
245
+ return 0, codeSyntax
246
+ }
247
+
248
+ if d >= byte(base) {
249
+ return 0, codeSyntax
250
+ }
251
+
252
+ if n >= cutoff {
253
+ // n*base overflows
254
+ return maxVal, codeRange
255
+ }
256
+ n *= uint64(base)
257
+
258
+ n1 := n + uint64(d)
259
+ if n1 < n || n1 > maxVal {
260
+ // n+d overflows
261
+ return maxVal, codeRange
262
+ }
263
+ n = n1
264
+ }
265
+
266
+ if underscores && !underscoreOK(s0) {
267
+ return 0, codeSyntax
268
+ }
269
+
270
+ return n, codeNone
271
+ }
272
+
273
+ func parseInt(s string, base int, bitSize int) (i int64, code parseCode) {
274
+ if s == "" {
275
+ return 0, codeSyntax
276
+ }
277
+
278
+ // Pick off leading sign.
279
+ neg := false
280
+ switch s[0] {
281
+ case '+':
282
+ s = s[1:]
283
+ case '-':
284
+ s = s[1:]
285
+ neg = true
286
+ }
287
+
288
+ // Convert unsigned and check range.
289
+ var un uint64
290
+ un, code = parseUint(s, base, bitSize)
291
+ if code != codeNone && code != codeRange {
292
+ return 0, code
293
+ }
294
+
295
+ if bitSize == 0 {
296
+ bitSize = IntSize
297
+ }
298
+
299
+ cutoff := uint64(1 << uint(bitSize-1))
300
+ if !neg && un >= cutoff {
301
+ return int64(cutoff - 1), codeRange
302
+ }
303
+ if neg && un > cutoff {
304
+ return -int64(cutoff), codeRange
305
+ }
306
+ n := int64(un)
307
+ if neg {
308
+ n = -n
309
+ }
310
+ return n, codeNone
311
+ }
312
+
313
+ func atoi(s string) (int, parseCode) {
314
+ sLen := len(s)
315
+ if 0 < sLen && sLen < 19 {
316
+ // Fast path for small integers that fit int type.
317
+ s0 := s
318
+ if s[0] == '-' || s[0] == '+' {
319
+ s = s[1:]
320
+ if len(s) < 1 {
321
+ return 0, codeSyntax
322
+ }
323
+ }
324
+
325
+ n := 0
326
+ for _, ch := range []byte(s) {
327
+ ch -= '0'
328
+ if ch > 9 {
329
+ return 0, codeSyntax
330
+ }
331
+ n = n*10 + int(ch)
332
+ }
333
+ if s0[0] == '-' {
334
+ n = -n
335
+ }
336
+ return n, codeNone
337
+ }
338
+
339
+ // Slow path for invalid, big, or underscored integers.
340
+ i64, code := parseInt(s, 10, 0)
341
+ return int(i64), code
342
+ }
343
+
344
+ // underscoreOK reports whether the underscores in s are allowed.
345
+ // Checking them in this one function lets all the parsers skip over them simply.
346
+ // Underscore must appear only between digits or between a base prefix and a digit.
347
+ func underscoreOK(s string) bool {
348
+ // saw tracks the last character (class) we saw:
349
+ // ^ for beginning of number,
350
+ // 0 for a digit or base prefix,
351
+ // _ for an underscore,
352
+ // ! for none of the above.
353
+ saw := '^'
354
+ i := 0
355
+
356
+ // Optional sign.
357
+ if len(s) >= 1 && (s[0] == '-' || s[0] == '+') {
358
+ s = s[1:]
359
+ }
360
+
361
+ // Optional base prefix.
362
+ hex := false
363
+ if len(s) >= 2 && s[0] == '0' && (lowerS(s[1]) == 'b' || lowerS(s[1]) == 'o' || lowerS(s[1]) == 'x') {
364
+ i = 2
365
+ saw = '0' // base prefix counts as a digit for "underscore as digit separator"
366
+ hex = lowerS(s[1]) == 'x'
367
+ }
368
+
369
+ // Number proper.
370
+ for ; i < len(s); i++ {
371
+ // Digits are always okay.
372
+ if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lowerS(s[i]) && lowerS(s[i]) <= 'f' {
373
+ saw = '0'
374
+ continue
375
+ }
376
+ // Underscore must follow digit.
377
+ if s[i] == '_' {
378
+ if saw != '0' {
379
+ return false
380
+ }
381
+ saw = '_'
382
+ continue
383
+ }
384
+ // Underscore must also be followed by digit.
385
+ if saw == '_' {
386
+ return false
387
+ }
388
+ // Saw non-digit, non-underscore.
389
+ saw = '!'
390
+ }
391
+ return saw != '_'
392
+ }
393
+
394
+ // FormatUint returns the string representation of i in the given base,
395
+ // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
396
+ // for digit values >= 10.
397
+ func FormatUint(i uint64, base int) string {
398
+ if base == 10 {
399
+ if i < nSmalls {
400
+ return small(int(i))
401
+ }
402
+ var a [24]byte
403
+ j := formatBase10(a[:], i)
404
+ return string(a[j:])
405
+ }
406
+ _, s := formatBits(nil, i, base, false, false)
407
+ return s
408
+ }
409
+
410
+ // FormatInt returns the string representation of i in the given base,
411
+ // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
412
+ // for digit values >= 10.
413
+ func FormatInt(i int64, base int) string {
414
+ if base == 10 {
415
+ if 0 <= i && i < nSmalls {
416
+ return small(int(i))
417
+ }
418
+ var a [24]byte
419
+ u := uint64(i)
420
+ if i < 0 {
421
+ u = -u
422
+ }
423
+ j := formatBase10(a[:], u)
424
+ if i < 0 {
425
+ j--
426
+ a[j] = '-'
427
+ }
428
+ return string(a[j:])
429
+ }
430
+ _, s := formatBits(nil, uint64(i), base, i < 0, false)
431
+ return s
432
+ }
433
+
434
+ // Itoa is equivalent to [FormatInt](int64(i), 10).
435
+ func Itoa(i int) string {
436
+ return FormatInt(int64(i), 10)
437
+ }
438
+
439
+ // AppendInt appends the string form of the integer i,
440
+ // as generated by [FormatInt], to dst and returns the extended buffer.
441
+ func AppendInt(dst []byte, i int64, base int) []byte {
442
+ u := uint64(i)
443
+ if i < 0 {
444
+ dst = append(dst, '-')
445
+ u = -u
446
+ }
447
+ return AppendUint(dst, u, base)
448
+ }
449
+
450
+ // AppendUint appends the string form of the unsigned integer i,
451
+ // as generated by [FormatUint], to dst and returns the extended buffer.
452
+ func AppendUint(dst []byte, i uint64, base int) []byte {
453
+ if base == 10 {
454
+ if i < nSmalls {
455
+ return append(dst, small(int(i))...)
456
+ }
457
+ var a [24]byte
458
+ j := formatBase10(a[:], i)
459
+ return append(dst, a[j:]...)
460
+ }
461
+ dst, _ = formatBits(dst, i, base, false, true)
462
+ return dst
463
+ }
464
+
465
+ func digitAt(i uint) byte {
466
+ return byte(digits[i])
467
+ }
468
+
469
+ const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
470
+
471
+ // formatBits computes the string representation of u in the given base.
472
+ // If neg is set, u is treated as negative int64 value. If append_ is
473
+ // set, the string is appended to dst and the resulting byte slice is
474
+ // returned as the first result value; otherwise the string is returned
475
+ // as the second result value.
476
+ // The caller is expected to have handled base 10 separately for speed.
477
+ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
478
+ if base < 2 || base == 10 || base > len(digits) {
479
+ panic("strconv: illegal AppendInt/FormatInt base")
480
+ }
481
+ // 2 <= base && base <= len(digits)
482
+
483
+ var a [64 + 1]byte // +1 for sign of 64bit value in base 2
484
+ i := len(a)
485
+ if neg {
486
+ u = -u
487
+ }
488
+
489
+ // convert bits
490
+ // We use uint values where we can because those will
491
+ // fit into a single register even on a 32bit machine.
492
+ if isPowerOfTwo(base) {
493
+ // Use shifts and masks instead of / and %.
494
+ shift := uint(bits.TrailingZeros(uint(base)))
495
+ b := uint64(base)
496
+ m := b - 1 // == 1<<shift - 1
497
+ for u >= b {
498
+ i--
499
+ a[i] = digitAt(uint(u & m))
500
+ u >>= shift
501
+ }
502
+ // u < base
503
+ i--
504
+ a[i] = digitAt(uint(u))
505
+ } else {
506
+ // general case
507
+ b := uint64(base)
508
+ for u >= b {
509
+ i--
510
+ // Avoid using r = a%b in addition to q = a/b
511
+ // since 64bit division and modulo operations
512
+ // are calculated by runtime functions on 32bit machines.
513
+ q := u / b
514
+ a[i] = digitAt(uint(u-q*b))
515
+ u = q
516
+ }
517
+ // u < base
518
+ i--
519
+ a[i] = digitAt(uint(u))
520
+ }
521
+
522
+ // add sign, if any
523
+ if neg {
524
+ i--
525
+ a[i] = '-'
526
+ }
527
+
528
+ if append_ {
529
+ d = append(dst, a[i:]...)
530
+ return
531
+ }
532
+ s = string(a[i:])
533
+ return
534
+ }
535
+
536
+ func isPowerOfTwo(x int) bool {
537
+ return x&(x-1) == 0
538
+ }
539
+
540
+ const nSmalls = 100
541
+
542
+ // smalls is the formatting of 00..99 concatenated.
543
+ // It is then padded out with 56 x's to 256 bytes,
544
+ // so that smalls[x&0xFF] has no bounds check.
545
+ const smalls = "00010203040506070809" +
546
+ "10111213141516171819" +
547
+ "20212223242526272829" +
548
+ "30313233343536373839" +
549
+ "40414243444546474849" +
550
+ "50515253545556575859" +
551
+ "60616263646566676869" +
552
+ "70717273747576777879" +
553
+ "80818283848586878889" +
554
+ "90919293949596979899"
555
+
556
+ // small returns the string for an i with 0 <= i < nSmalls.
557
+ func small(i int) string {
558
+ if i < 10 {
559
+ return digits[i : i+1]
560
+ }
561
+ return smalls[i*2 : i*2+2]
562
+ }
563
+
564
+ // formatBase10 formats the decimal representation of u into the tail of a
565
+ // and returns the offset of the first byte written to a. That is, after
566
+ //
567
+ // i := formatBase10(a, u)
568
+ //
569
+ // the decimal representation is in a[i:].
570
+ func formatBase10(a []byte, u uint64) int {
571
+ // Split into 9-digit chunks that fit in uint32s
572
+ // and convert each chunk using uint32 math instead of uint64 math.
573
+ // The obvious way to write the outer loop is "for u >= 1e9", but most numbers are small,
574
+ // so the setup for the comparison u >= 1e9 is usually pure overhead.
575
+ // Instead, we approximate it by u>>29 != 0, which is usually faster and good enough.
576
+ i := len(a)
577
+ for u>>29 != 0 {
578
+ var lo uint32
579
+ u, lo = u/1000000000, uint32(u%1000000000)
580
+
581
+ // Convert 9 digits.
582
+ for range 4 {
583
+ var dd uint32
584
+ lo, dd = lo/100, (lo%100)*2
585
+ i -= 2
586
+ a[i+0], a[i+1] = byte(smalls[dd+0]), byte(smalls[dd+1])
587
+ }
588
+ i--
589
+ a[i] = byte(smalls[lo*2+1])
590
+
591
+ // If we'd been using u >= 1e9 then we would be guaranteed that u/1e9 > 0,
592
+ // but since we used u>>29 != 0, u/1e9 might be 0, so we might be done.
593
+ // (If u is now 0, then at the start we had 2²⁹ ≤ u < 10⁹, so it was still correct
594
+ // to write 9 digits; we have not accidentally written any leading zeros.)
595
+ if u == 0 {
596
+ return i
597
+ }
598
+ }
599
+
600
+ // Convert final chunk, at most 8 digits.
601
+ lo := uint32(u)
602
+ for lo >= 100 {
603
+ var dd uint32
604
+ lo, dd = lo/100, (lo%100)*2
605
+ i -= 2
606
+ a[i+0], a[i+1] = byte(smalls[dd+0]), byte(smalls[dd+1])
607
+ }
608
+ i--
609
+ dd := lo * 2
610
+ a[i] = byte(smalls[dd+1])
611
+ if lo >= 10 {
612
+ i--
613
+ a[i] = byte(smalls[dd+0])
614
+ }
615
+ return i
616
+ }
@@ -0,0 +1,95 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target both
4
+
5
+ // Builder written in Go over the real package's algorithm. GoFront strings
6
+ // are host strings, so Len and Cap count the UTF-8 bytes the builder holds,
7
+ // the same as in Go.
8
+ package strings
9
+
10
+ import "unicode/utf8"
11
+
12
+ // A Builder is used to efficiently build a string using [Builder.Write] methods.
13
+ // It minimizes memory copying. The zero value is ready to use.
14
+ // Do not copy a non-zero Builder.
15
+ type Builder struct {
16
+ addr *Builder // of receiver, to detect copies by value
17
+
18
+ buf []byte
19
+ }
20
+
21
+ func (b *Builder) copyCheck() {
22
+ if b.addr == nil {
23
+ b.addr = b
24
+ } else if b.addr != b {
25
+ panic("strings: illegal use of non-zero Builder copied by value")
26
+ }
27
+ }
28
+
29
+ // String returns the accumulated string.
30
+ func (b *Builder) String() string {
31
+ return string(b.buf)
32
+ }
33
+
34
+ // Len returns the number of accumulated bytes; b.Len() == len(b.String()).
35
+ func (b *Builder) Len() int { return len(b.buf) }
36
+
37
+ // Cap returns the capacity of the builder's underlying byte slice. It is the
38
+ // total space allocated for the string being built and includes any bytes
39
+ // already written.
40
+ func (b *Builder) Cap() int { return cap(b.buf) }
41
+
42
+ // Reset resets the [Builder] to be empty.
43
+ func (b *Builder) Reset() {
44
+ b.addr = nil
45
+ b.buf = nil
46
+ }
47
+
48
+ // Grow grows b's capacity, if necessary, to guarantee space for
49
+ // another n bytes. After Grow(n), at least n bytes can be written to b
50
+ // without another allocation. If n is negative, Grow panics.
51
+ func (b *Builder) Grow(n int) {
52
+ b.copyCheck()
53
+ if n < 0 {
54
+ panic("strings.Builder.Grow: negative count")
55
+ }
56
+ if cap(b.buf)-len(b.buf) < n {
57
+ nb := make([]byte, len(b.buf), 2*cap(b.buf)+n)
58
+ copy(nb, b.buf)
59
+ b.buf = nb
60
+ }
61
+ }
62
+
63
+ // Write appends the contents of p to b's buffer.
64
+ // Write always returns len(p), nil.
65
+ func (b *Builder) Write(p []byte) (int, error) {
66
+ b.copyCheck()
67
+ b.buf = append(b.buf, p...)
68
+ return len(p), nil
69
+ }
70
+
71
+ // WriteByte appends the byte c to b's buffer.
72
+ // The returned error is always nil.
73
+ func (b *Builder) WriteByte(c byte) error {
74
+ b.copyCheck()
75
+ b.buf = append(b.buf, c)
76
+ return nil
77
+ }
78
+
79
+ // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
80
+ // It returns the length of r and a nil error.
81
+ func (b *Builder) WriteRune(r rune) (int, error) {
82
+ b.copyCheck()
83
+ n := len(b.buf)
84
+ b.buf = utf8.AppendRune(b.buf, r)
85
+ return len(b.buf) - n, nil
86
+ }
87
+
88
+ // WriteString appends the contents of s to b's buffer.
89
+ // It returns the length of s and a nil error.
90
+ func (b *Builder) WriteString(s string) (int, error) {
91
+ b.copyCheck()
92
+ n := len(b.buf)
93
+ b.buf = append(b.buf, s...)
94
+ return len(b.buf) - n, nil
95
+ }