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.
- package/README.md +3 -3
- package/package.json +5 -4
- package/src/backend/js/expressions.js +849 -371
- package/src/backend/js/index.js +241 -147
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +512 -2547
- package/src/backend/js/statements.js +506 -103
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +177 -13
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +63 -171
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +643 -256
- package/src/backend/wasm/emit-exprs.js +124 -57
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-stmts.js +325 -75
- package/src/backend/wasm/emit.js +104 -13
- package/src/backend/wasm/globals.js +47 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +36 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +92 -717
- package/src/backend/wasm/monomorph.js +103 -6
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +68 -20
- package/src/backend/wasm/variadic.js +3 -3
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +108 -130
- package/src/lexer/lexer.js +105 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +354 -132
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- 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 +7 -1
- package/src/lower/json-codecs.js +228 -247
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +28 -5
- package/src/parser/expressions.js +86 -16
- package/src/parser/statements.js +1 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +1 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +124 -11
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +32 -6
- package/src/typechecker/expressions.js +326 -98
- package/src/typechecker/index.js +208 -33
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +192 -36
- package/src/typechecker/statements.js +122 -11
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +203 -573
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -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/json.go +62 -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/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- 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 +391 -452
- 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 +235 -50
- 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 +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- 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 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- 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 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- 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 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
|
@@ -51,12 +51,6 @@ func (e *InvalidUnmarshalError) Error() string {
|
|
|
51
51
|
return "json: Unmarshal(nil " + e.Type + ")"
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
var (
|
|
55
|
-
OptEscapeHTML = true
|
|
56
|
-
OptUseNumber bool
|
|
57
|
-
OptDisallowUnknownFields bool
|
|
58
|
-
)
|
|
59
|
-
|
|
60
54
|
// Dec is the state of one Unmarshal call. The input has been checked to be
|
|
61
55
|
// valid JSON, so the readers below do not look for syntax errors.
|
|
62
56
|
type Dec struct {
|
|
@@ -64,8 +58,9 @@ type Dec struct {
|
|
|
64
58
|
pos int
|
|
65
59
|
Err error
|
|
66
60
|
fatal bool
|
|
67
|
-
structs []string
|
|
68
|
-
fields []string
|
|
61
|
+
structs []string // stack of struct names, depth entries live
|
|
62
|
+
fields []string // stack of field names, depth entries live
|
|
63
|
+
depth int
|
|
69
64
|
key string
|
|
70
65
|
UseNumber bool
|
|
71
66
|
DisallowUnknownFields bool
|
|
@@ -77,11 +72,7 @@ func NewDec(data []byte) (*Dec, error) {
|
|
|
77
72
|
if err := CheckValid(data); err != nil {
|
|
78
73
|
return nil, err
|
|
79
74
|
}
|
|
80
|
-
return &Dec{
|
|
81
|
-
data: data,
|
|
82
|
-
UseNumber: OptUseNumber,
|
|
83
|
-
DisallowUnknownFields: OptDisallowUnknownFields,
|
|
84
|
-
}, nil
|
|
75
|
+
return &Dec{data: data}, nil
|
|
85
76
|
}
|
|
86
77
|
|
|
87
78
|
// UnknownField records an error when an unknown struct field is encountered with DisallowUnknownFields.
|
|
@@ -117,15 +108,21 @@ func (d *Dec) Failed() bool {
|
|
|
117
108
|
}
|
|
118
109
|
|
|
119
110
|
// Enter and Leave track the struct field being decoded for error messages.
|
|
111
|
+
// The stacks keep their entries and move an index, so no slice is resliced
|
|
112
|
+
// or copied per struct.
|
|
120
113
|
func (d *Dec) Enter(structName, field string) {
|
|
121
|
-
d.
|
|
122
|
-
|
|
114
|
+
if d.depth < len(d.fields) {
|
|
115
|
+
d.structs[d.depth] = structName
|
|
116
|
+
d.fields[d.depth] = field
|
|
117
|
+
} else {
|
|
118
|
+
d.structs = append(d.structs, structName)
|
|
119
|
+
d.fields = append(d.fields, field)
|
|
120
|
+
}
|
|
121
|
+
d.depth++
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
func (d *Dec) Leave() {
|
|
126
|
-
|
|
127
|
-
d.structs = d.structs[:n]
|
|
128
|
-
d.fields = d.fields[:n]
|
|
125
|
+
d.depth--
|
|
129
126
|
}
|
|
130
127
|
|
|
131
128
|
func (d *Dec) ws() {
|
|
@@ -169,9 +166,9 @@ func (d *Dec) typeErr(value, typ string) {
|
|
|
169
166
|
return
|
|
170
167
|
}
|
|
171
168
|
e := &UnmarshalTypeError{Value: value, Type: typ, Offset: int64(d.pos)}
|
|
172
|
-
if
|
|
173
|
-
e.Struct = d.structs[
|
|
174
|
-
e.Field = strings.Join(d.fields, ".")
|
|
169
|
+
if d.depth > 0 {
|
|
170
|
+
e.Struct = d.structs[d.depth-1]
|
|
171
|
+
e.Field = strings.Join(d.fields[:d.depth], ".")
|
|
175
172
|
}
|
|
176
173
|
d.Err = e
|
|
177
174
|
}
|
|
@@ -239,12 +236,18 @@ func (d *Dec) Unquote(typ, kind string) *Dec {
|
|
|
239
236
|
d.Skip()
|
|
240
237
|
return nil
|
|
241
238
|
}
|
|
242
|
-
s := d
|
|
239
|
+
s := readStr(d)
|
|
243
240
|
b := []byte(s)
|
|
244
241
|
if s == "null" {
|
|
245
242
|
return nil
|
|
246
243
|
}
|
|
247
244
|
ok := len(b) > 0 && CheckValid(b) == nil
|
|
245
|
+
// A number that starts like one but is not valid fails like any other
|
|
246
|
+
// malformed number.
|
|
247
|
+
if !ok && kind == "number" && len(b) > 0 && (b[0] == '-' || (b[0] >= '0' && b[0] <= '9')) {
|
|
248
|
+
d.typeErr("number "+s, typ)
|
|
249
|
+
return nil
|
|
250
|
+
}
|
|
248
251
|
if ok {
|
|
249
252
|
c := b[0]
|
|
250
253
|
switch kind {
|
|
@@ -260,7 +263,7 @@ func (d *Dec) Unquote(typ, kind string) *Dec {
|
|
|
260
263
|
d.Save(errors.New("json: invalid use of ,string struct tag, trying to unmarshal " + strconv.Quote(s) + " into " + typ))
|
|
261
264
|
return nil
|
|
262
265
|
}
|
|
263
|
-
return &Dec{data: b, structs: d.structs, fields: d.fields}
|
|
266
|
+
return &Dec{data: b, structs: d.structs, fields: d.fields, depth: d.depth}
|
|
264
267
|
}
|
|
265
268
|
|
|
266
269
|
// Merge takes over the first error of a decoder made by Unquote.
|
|
@@ -364,7 +367,10 @@ func (d *Dec) Offset() int {
|
|
|
364
367
|
return d.pos
|
|
365
368
|
}
|
|
366
369
|
|
|
367
|
-
|
|
370
|
+
// readNum consumes the number literal at the current position.
|
|
371
|
+
//
|
|
372
|
+
//gofront:native jsonrt.readNum
|
|
373
|
+
func readNum(d *Dec) string {
|
|
368
374
|
start := d.pos
|
|
369
375
|
for d.pos < len(d.data) {
|
|
370
376
|
c := d.data[d.pos]
|
|
@@ -383,18 +389,20 @@ func (d *Dec) Number(typ string) (string, bool) {
|
|
|
383
389
|
return "", false
|
|
384
390
|
}
|
|
385
391
|
if d.peek() == '"' {
|
|
392
|
+
start := d.pos
|
|
386
393
|
s, ok := d.String(typ)
|
|
387
394
|
if !ok {
|
|
388
395
|
return "", false
|
|
389
396
|
}
|
|
390
397
|
if !isValidNumber(s) {
|
|
391
|
-
|
|
398
|
+
// Go quotes the whole JSON literal and stops decoding.
|
|
399
|
+
d.Fatal(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", string(d.data[start:d.pos])))
|
|
392
400
|
return "", false
|
|
393
401
|
}
|
|
394
402
|
return s, true
|
|
395
403
|
}
|
|
396
404
|
if d.kind() == "number" {
|
|
397
|
-
return d
|
|
405
|
+
return readNum(d), true
|
|
398
406
|
}
|
|
399
407
|
d.Mismatch(typ)
|
|
400
408
|
return "", false
|
|
@@ -432,7 +440,119 @@ func (d *Dec) String(typ string) (v string, ok bool) {
|
|
|
432
440
|
d.typeErr(k, typ)
|
|
433
441
|
return "", false
|
|
434
442
|
}
|
|
435
|
-
return d
|
|
443
|
+
return readStr(d), true
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// plainInt consumes a decimal integer of at most 15 digits, with no fraction
|
|
447
|
+
// or exponent, that fits in bits bits (and is not negative unless signed), and
|
|
448
|
+
// returns it. It leaves the input alone and reports false for anything else,
|
|
449
|
+
// which the caller then parses and reports from its text. The value stays in
|
|
450
|
+
// an int, which is a plain number in JavaScript.
|
|
451
|
+
func (d *Dec) plainInt(bits int, signed bool) (int, bool) {
|
|
452
|
+
data := d.data
|
|
453
|
+
end := len(data)
|
|
454
|
+
i := d.pos
|
|
455
|
+
neg := false
|
|
456
|
+
if i < end && data[i] == '-' {
|
|
457
|
+
if !signed {
|
|
458
|
+
return 0, false
|
|
459
|
+
}
|
|
460
|
+
neg = true
|
|
461
|
+
i++
|
|
462
|
+
}
|
|
463
|
+
start := i
|
|
464
|
+
v := 0
|
|
465
|
+
for i < end {
|
|
466
|
+
c := data[i]
|
|
467
|
+
if c < '0' || c > '9' {
|
|
468
|
+
break
|
|
469
|
+
}
|
|
470
|
+
if i-start == 15 {
|
|
471
|
+
return 0, false
|
|
472
|
+
}
|
|
473
|
+
v = v*10 + int(c-'0')
|
|
474
|
+
i++
|
|
475
|
+
}
|
|
476
|
+
if i == start {
|
|
477
|
+
return 0, false
|
|
478
|
+
}
|
|
479
|
+
if i < end {
|
|
480
|
+
if c := data[i]; c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-' {
|
|
481
|
+
return 0, false
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if neg {
|
|
485
|
+
v = -v
|
|
486
|
+
}
|
|
487
|
+
if bits < 53 {
|
|
488
|
+
lim := 1 << (bits - 1)
|
|
489
|
+
if !signed {
|
|
490
|
+
lim = 1 << bits
|
|
491
|
+
if v >= lim {
|
|
492
|
+
return 0, false
|
|
493
|
+
}
|
|
494
|
+
} else if v >= lim || v < -lim {
|
|
495
|
+
return 0, false
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
d.pos = i
|
|
499
|
+
return v, true
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
var pow10 = [...]float64{1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15}
|
|
503
|
+
|
|
504
|
+
// plainFloat consumes a decimal number of at most 15 digits with no exponent.
|
|
505
|
+
// Such a number is a mantissa that a float64 holds exactly divided by a power
|
|
506
|
+
// of ten that it holds exactly, so one division rounds it correctly. It
|
|
507
|
+
// leaves the input alone and reports false for anything else.
|
|
508
|
+
func (d *Dec) plainFloat() (float64, bool) {
|
|
509
|
+
data := d.data
|
|
510
|
+
end := len(data)
|
|
511
|
+
i := d.pos
|
|
512
|
+
neg := false
|
|
513
|
+
if i < end && data[i] == '-' {
|
|
514
|
+
neg = true
|
|
515
|
+
i++
|
|
516
|
+
}
|
|
517
|
+
start := i
|
|
518
|
+
digits := 0
|
|
519
|
+
frac := 0
|
|
520
|
+
v := 0
|
|
521
|
+
seenDot := false
|
|
522
|
+
for i < end {
|
|
523
|
+
c := data[i]
|
|
524
|
+
if c == '.' && !seenDot {
|
|
525
|
+
seenDot = true
|
|
526
|
+
i++
|
|
527
|
+
continue
|
|
528
|
+
}
|
|
529
|
+
if c < '0' || c > '9' {
|
|
530
|
+
break
|
|
531
|
+
}
|
|
532
|
+
if digits == 15 {
|
|
533
|
+
return 0, false
|
|
534
|
+
}
|
|
535
|
+
v = v*10 + int(c-'0')
|
|
536
|
+
digits++
|
|
537
|
+
if seenDot {
|
|
538
|
+
frac++
|
|
539
|
+
}
|
|
540
|
+
i++
|
|
541
|
+
}
|
|
542
|
+
if digits == 0 || i-start == 0 {
|
|
543
|
+
return 0, false
|
|
544
|
+
}
|
|
545
|
+
if i < end {
|
|
546
|
+
if c := data[i]; c == 'e' || c == 'E' || c == '+' || c == '-' {
|
|
547
|
+
return 0, false
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
f := float64(v) / pow10[frac]
|
|
551
|
+
if neg {
|
|
552
|
+
f = -f
|
|
553
|
+
}
|
|
554
|
+
d.pos = i
|
|
555
|
+
return f, true
|
|
436
556
|
}
|
|
437
557
|
|
|
438
558
|
// Int decodes an integer that must fit in bits bits.
|
|
@@ -440,13 +560,16 @@ func (d *Dec) Int(bits int, typ string) (v int64, ok bool) {
|
|
|
440
560
|
if d.fatal || d.Null() {
|
|
441
561
|
return 0, false
|
|
442
562
|
}
|
|
443
|
-
if d.peek() == '"' ||
|
|
563
|
+
if c := d.peek(); c == '"' || c == '{' || c == '[' || c == 't' || c == 'f' {
|
|
444
564
|
k := d.kind()
|
|
445
565
|
d.Skip()
|
|
446
566
|
d.typeErr(k, typ)
|
|
447
567
|
return 0, false
|
|
448
568
|
}
|
|
449
|
-
|
|
569
|
+
if n, ok := d.plainInt(bits, true); ok {
|
|
570
|
+
return int64(n), true
|
|
571
|
+
}
|
|
572
|
+
s := readNum(d)
|
|
450
573
|
n, err := strconv.ParseInt(s, 10, bits)
|
|
451
574
|
if err != nil {
|
|
452
575
|
d.typeErr("number "+s, typ)
|
|
@@ -460,13 +583,16 @@ func (d *Dec) Uint(bits int, typ string) (v uint64, ok bool) {
|
|
|
460
583
|
if d.fatal || d.Null() {
|
|
461
584
|
return 0, false
|
|
462
585
|
}
|
|
463
|
-
if d.peek() == '"' ||
|
|
586
|
+
if c := d.peek(); c == '"' || c == '{' || c == '[' || c == 't' || c == 'f' {
|
|
464
587
|
k := d.kind()
|
|
465
588
|
d.Skip()
|
|
466
589
|
d.typeErr(k, typ)
|
|
467
590
|
return 0, false
|
|
468
591
|
}
|
|
469
|
-
|
|
592
|
+
if n, ok := d.plainInt(bits, false); ok {
|
|
593
|
+
return uint64(n), true
|
|
594
|
+
}
|
|
595
|
+
s := readNum(d)
|
|
470
596
|
n, err := strconv.ParseUint(s, 10, bits)
|
|
471
597
|
if err != nil {
|
|
472
598
|
d.typeErr("number "+s, typ)
|
|
@@ -480,13 +606,18 @@ func (d *Dec) Float(bits int, typ string) (v float64, ok bool) {
|
|
|
480
606
|
if d.fatal || d.Null() {
|
|
481
607
|
return 0, false
|
|
482
608
|
}
|
|
483
|
-
if d.peek() == '"' ||
|
|
609
|
+
if c := d.peek(); c == '"' || c == '{' || c == '[' || c == 't' || c == 'f' {
|
|
484
610
|
k := d.kind()
|
|
485
611
|
d.Skip()
|
|
486
612
|
d.typeErr(k, typ)
|
|
487
613
|
return 0, false
|
|
488
614
|
}
|
|
489
|
-
|
|
615
|
+
if bits == 64 {
|
|
616
|
+
if f, ok := d.plainFloat(); ok {
|
|
617
|
+
return f, true
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
s := readNum(d)
|
|
490
621
|
n, err := strconv.ParseFloat(s, bits)
|
|
491
622
|
if bits == 32 {
|
|
492
623
|
// Round to float32 here: the number may be out of float32 range.
|
|
@@ -530,7 +661,7 @@ func (d *Dec) NextKey() bool {
|
|
|
530
661
|
d.pos++
|
|
531
662
|
}
|
|
532
663
|
d.ws()
|
|
533
|
-
d.key = d
|
|
664
|
+
d.key = readStr(d)
|
|
534
665
|
d.ws()
|
|
535
666
|
d.pos++ // the colon
|
|
536
667
|
return true
|
|
@@ -577,8 +708,10 @@ func EqualFold(a, b string) bool {
|
|
|
577
708
|
return strings.EqualFold(a, b)
|
|
578
709
|
}
|
|
579
710
|
|
|
580
|
-
//
|
|
581
|
-
|
|
711
|
+
// readStr consumes the string at the current position.
|
|
712
|
+
//
|
|
713
|
+
//gofront:native jsonrt.readStr
|
|
714
|
+
func readStr(d *Dec) string {
|
|
582
715
|
d.pos++ // opening quote
|
|
583
716
|
start := d.pos
|
|
584
717
|
plain := true
|
|
@@ -714,7 +847,7 @@ func (d *Dec) Any() any {
|
|
|
714
847
|
}
|
|
715
848
|
return a
|
|
716
849
|
case '"':
|
|
717
|
-
return d
|
|
850
|
+
return readStr(d)
|
|
718
851
|
case 't':
|
|
719
852
|
d.pos += 4
|
|
720
853
|
return true
|
|
@@ -725,7 +858,7 @@ func (d *Dec) Any() any {
|
|
|
725
858
|
d.pos += 4
|
|
726
859
|
return nil
|
|
727
860
|
}
|
|
728
|
-
s := d
|
|
861
|
+
s := readNum(d)
|
|
729
862
|
if d.UseNumber {
|
|
730
863
|
return Number(s)
|
|
731
864
|
}
|
|
@@ -56,15 +56,19 @@ func (e *MarshalerError) Unwrap() error { return e.Err }
|
|
|
56
56
|
|
|
57
57
|
// Enc is the state of one Marshal call: the output so far and the first
|
|
58
58
|
// error. After an error every method does nothing.
|
|
59
|
+
//
|
|
60
|
+
// The output is buf[:n]; the rest of buf is room to grow into, so appending
|
|
61
|
+
// a byte is an index write rather than a new slice header.
|
|
59
62
|
type Enc struct {
|
|
60
|
-
|
|
63
|
+
buf []byte
|
|
64
|
+
n int
|
|
61
65
|
Err error
|
|
62
66
|
EscapeHTML bool
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
// NewEnc returns an encoder that escapes <, > and & like json.Marshal.
|
|
66
70
|
func NewEnc() *Enc {
|
|
67
|
-
return &Enc{EscapeHTML:
|
|
71
|
+
return &Enc{buf: make([]byte, 256), EscapeHTML: true}
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
// Result returns the encoded bytes, or the first error.
|
|
@@ -72,7 +76,114 @@ func (e *Enc) Result() ([]byte, error) {
|
|
|
72
76
|
if e.Err != nil {
|
|
73
77
|
return nil, e.Err
|
|
74
78
|
}
|
|
75
|
-
return e.
|
|
79
|
+
return e.buf[:e.n], nil
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// room makes sure k more bytes fit after the output.
|
|
83
|
+
func (e *Enc) room(k int) {
|
|
84
|
+
if e.n+k <= len(e.buf) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
nb := make([]byte, 2*len(e.buf)+k)
|
|
88
|
+
copy(nb, e.buf[:e.n])
|
|
89
|
+
e.buf = nb
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// putBytes appends b to the output.
|
|
93
|
+
func (e *Enc) putBytes(b []byte) {
|
|
94
|
+
e.room(len(b))
|
|
95
|
+
copy(e.buf[e.n:], b)
|
|
96
|
+
e.n += len(b)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// putString appends the bytes of s to the output.
|
|
100
|
+
//
|
|
101
|
+
//gofront:native jsonrt.putString
|
|
102
|
+
func putString(e *Enc, s string) {
|
|
103
|
+
n := len(s)
|
|
104
|
+
e.room(n)
|
|
105
|
+
for i := 0; i < n; i++ {
|
|
106
|
+
e.buf[e.n+i] = s[i]
|
|
107
|
+
}
|
|
108
|
+
e.n += n
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// putInt appends the decimal form of v.
|
|
112
|
+
//
|
|
113
|
+
//gofront:native jsonrt.putInt
|
|
114
|
+
func putInt(e *Enc, v int64) {
|
|
115
|
+
if v < 0 {
|
|
116
|
+
e.Byte('-')
|
|
117
|
+
putUint(e, uint64(-v))
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
putUint(e, uint64(v))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// putUint appends the decimal form of v.
|
|
124
|
+
//
|
|
125
|
+
//gofront:native jsonrt.putUint
|
|
126
|
+
func putUint(e *Enc, v uint64) {
|
|
127
|
+
n := 1
|
|
128
|
+
for t := v; t >= 10; t /= 10 {
|
|
129
|
+
n++
|
|
130
|
+
}
|
|
131
|
+
e.room(n)
|
|
132
|
+
for i := e.n + n - 1; i >= e.n; i-- {
|
|
133
|
+
e.buf[i] = byte('0' + v%10)
|
|
134
|
+
v /= 10
|
|
135
|
+
}
|
|
136
|
+
e.n += n
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// putFloat appends a finite f in the format encoding/json uses: shortest
|
|
140
|
+
// digits that read back as a float of the given size, as if by ES6 number to
|
|
141
|
+
// string conversion (an exponent only below 1e-6 and from 1e21).
|
|
142
|
+
//
|
|
143
|
+
//gofront:native jsonrt.putFloat
|
|
144
|
+
func putFloat(e *Enc, f float64, bits int) {
|
|
145
|
+
var tmp [64]byte
|
|
146
|
+
b := tmp[:0]
|
|
147
|
+
format := floatFormat(f, bits)
|
|
148
|
+
if bits == 32 {
|
|
149
|
+
f = shortest32(f)
|
|
150
|
+
}
|
|
151
|
+
b = strconv.AppendFloat(b, f, format, -1, 64)
|
|
152
|
+
if format == 'e' {
|
|
153
|
+
b = cleanExponent(b)
|
|
154
|
+
}
|
|
155
|
+
e.putBytes(b)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// LooksFloat32 reports whether f, found in an interface, is more likely a
|
|
159
|
+
// float32 than a float64. Where a float32 and a float64 share one run-time
|
|
160
|
+
// representation (JavaScript numbers) a float64 that a float32 holds exactly
|
|
161
|
+
// is taken for one; elsewhere the interface tells them apart.
|
|
162
|
+
//
|
|
163
|
+
//gofront:native jsonrt.LooksFloat32
|
|
164
|
+
func LooksFloat32(f float64) bool {
|
|
165
|
+
return false
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// putQuoted appends s as a quoted JSON string.
|
|
169
|
+
//
|
|
170
|
+
//gofront:native jsonrt.putQuoted
|
|
171
|
+
func putQuoted(e *Enc, s string) {
|
|
172
|
+
n := len(s)
|
|
173
|
+
for i := 0; i < n; i++ {
|
|
174
|
+
c := s[i]
|
|
175
|
+
if c < 0x20 || c >= utf8.RuneSelf || c == '"' || c == '\\' || (e.EscapeHTML && (c == '<' || c == '>' || c == '&')) {
|
|
176
|
+
e.putBytes(AppendString(nil, []byte(s), e.EscapeHTML))
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
e.room(n + 2)
|
|
181
|
+
e.buf[e.n] = '"'
|
|
182
|
+
for i := 0; i < n; i++ {
|
|
183
|
+
e.buf[e.n+1+i] = s[i]
|
|
184
|
+
}
|
|
185
|
+
e.buf[e.n+n+1] = '"'
|
|
186
|
+
e.n += n + 2
|
|
76
187
|
}
|
|
77
188
|
|
|
78
189
|
// Fail records the first error.
|
|
@@ -87,19 +198,51 @@ func (e *Enc) FailType(typ string) {
|
|
|
87
198
|
e.Fail(&UnsupportedTypeError{typ})
|
|
88
199
|
}
|
|
89
200
|
|
|
201
|
+
// encoders are the dynamic encoders every package with generated codecs
|
|
202
|
+
// registers at start-up: each encodes the values of its own package's types
|
|
203
|
+
// and reports whether it knew the value.
|
|
204
|
+
type encoderList struct {
|
|
205
|
+
fns []func(*Enc, any) bool
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
var encoders = &encoderList{}
|
|
209
|
+
|
|
210
|
+
// RegisterEncoder adds a package's dynamic encoder. Each target fills its own
|
|
211
|
+
// list from the package initializers it runs, so the list is built through a local.
|
|
212
|
+
func RegisterEncoder(f func(*Enc, any) bool) bool {
|
|
213
|
+
list := encoders
|
|
214
|
+
list.fns = append(list.fns, f)
|
|
215
|
+
return true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// EncodeDynamic encodes v with the first registered encoder that knows its
|
|
219
|
+
// type, and fails the encoding when none does.
|
|
220
|
+
func (e *Enc) EncodeDynamic(v any) {
|
|
221
|
+
for _, f := range encoders.fns {
|
|
222
|
+
if f(e, v) {
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
e.FailType("unsupported dynamic type")
|
|
227
|
+
}
|
|
228
|
+
|
|
90
229
|
// Lit appends s, which is already valid JSON text.
|
|
91
230
|
func (e *Enc) Lit(s string) {
|
|
92
|
-
|
|
231
|
+
putString(e, s)
|
|
93
232
|
}
|
|
94
233
|
|
|
95
234
|
// Byte appends one byte of JSON punctuation.
|
|
96
235
|
func (e *Enc) Byte(c byte) {
|
|
97
|
-
e.
|
|
236
|
+
if e.n == len(e.buf) {
|
|
237
|
+
e.room(1)
|
|
238
|
+
}
|
|
239
|
+
e.buf[e.n] = c
|
|
240
|
+
e.n++
|
|
98
241
|
}
|
|
99
242
|
|
|
100
243
|
// Null appends null.
|
|
101
244
|
func (e *Enc) Null() {
|
|
102
|
-
|
|
245
|
+
putString(e, "null")
|
|
103
246
|
}
|
|
104
247
|
|
|
105
248
|
// Number appends the literal representation of a Number.
|
|
@@ -108,14 +251,14 @@ func (e *Enc) Number(v string) {
|
|
|
108
251
|
return
|
|
109
252
|
}
|
|
110
253
|
if v == "" {
|
|
111
|
-
e.
|
|
254
|
+
e.Byte('0')
|
|
112
255
|
return
|
|
113
256
|
}
|
|
114
257
|
if !isValidNumber(v) {
|
|
115
258
|
e.Fail(fmt.Errorf("json: invalid number literal %q", v))
|
|
116
259
|
return
|
|
117
260
|
}
|
|
118
|
-
|
|
261
|
+
putString(e, v)
|
|
119
262
|
}
|
|
120
263
|
|
|
121
264
|
func isValidNumber(s string) bool {
|
|
@@ -132,20 +275,20 @@ func isValidNumber(s string) bool {
|
|
|
132
275
|
// Bool appends true or false.
|
|
133
276
|
func (e *Enc) Bool(v bool) {
|
|
134
277
|
if v {
|
|
135
|
-
|
|
278
|
+
putString(e, "true")
|
|
136
279
|
} else {
|
|
137
|
-
|
|
280
|
+
putString(e, "false")
|
|
138
281
|
}
|
|
139
282
|
}
|
|
140
283
|
|
|
141
284
|
// Int appends a signed integer.
|
|
142
285
|
func (e *Enc) Int(v int64) {
|
|
143
|
-
|
|
286
|
+
putInt(e, v)
|
|
144
287
|
}
|
|
145
288
|
|
|
146
289
|
// Uint appends an unsigned integer.
|
|
147
290
|
func (e *Enc) Uint(v uint64) {
|
|
148
|
-
|
|
291
|
+
putUint(e, v)
|
|
149
292
|
}
|
|
150
293
|
|
|
151
294
|
// Float appends a floating-point number in the format encoding/json uses.
|
|
@@ -158,21 +301,14 @@ func (e *Enc) Float(f float64, bits int) {
|
|
|
158
301
|
return
|
|
159
302
|
}
|
|
160
303
|
if f == 0 && math.Signbit(f) {
|
|
161
|
-
|
|
304
|
+
putString(e, "-0")
|
|
162
305
|
return
|
|
163
306
|
}
|
|
164
|
-
|
|
165
|
-
if bits == 32 {
|
|
166
|
-
f = shortest32(f)
|
|
167
|
-
}
|
|
168
|
-
e.B = strconv.AppendFloat(e.B, f, format, -1, 64)
|
|
169
|
-
if format == 'e' {
|
|
170
|
-
e.B = cleanExponent(e.B)
|
|
171
|
-
}
|
|
307
|
+
putFloat(e, f, bits)
|
|
172
308
|
}
|
|
173
309
|
|
|
174
310
|
// floatFormat picks 'e' or 'f' as if by ES6 number to string conversion.
|
|
175
|
-
func floatFormat(f float64, bits int)
|
|
311
|
+
func floatFormat(f float64, bits int) byte {
|
|
176
312
|
abs := math.Abs(f)
|
|
177
313
|
if abs == 0 {
|
|
178
314
|
return 'f'
|
|
@@ -210,34 +346,35 @@ func shortest32(f float64) float64 {
|
|
|
210
346
|
|
|
211
347
|
// Str appends a quoted, escaped string.
|
|
212
348
|
func (e *Enc) Str(s string) {
|
|
213
|
-
|
|
349
|
+
putQuoted(e, s)
|
|
214
350
|
}
|
|
215
351
|
|
|
216
352
|
// QStr appends a string for the ,string tag option: the quoted form of the
|
|
217
353
|
// quoted form.
|
|
218
354
|
func (e *Enc) QStr(s string) {
|
|
219
355
|
inner := AppendString(nil, []byte(s), e.EscapeHTML)
|
|
220
|
-
e.
|
|
356
|
+
e.putBytes(AppendString(nil, inner, false))
|
|
221
357
|
}
|
|
222
358
|
|
|
223
359
|
// Key appends the separator for member n of an object (a comma when n > 0)
|
|
224
360
|
// and the member name, a plain name that needs no escaping.
|
|
225
361
|
func (e *Enc) Key(n int, name string) {
|
|
226
362
|
if n > 0 {
|
|
227
|
-
e.
|
|
363
|
+
e.Byte(',')
|
|
228
364
|
}
|
|
229
|
-
e.
|
|
230
|
-
|
|
231
|
-
e.
|
|
365
|
+
e.Byte('"')
|
|
366
|
+
putString(e, name)
|
|
367
|
+
e.Byte('"')
|
|
368
|
+
e.Byte(':')
|
|
232
369
|
}
|
|
233
370
|
|
|
234
371
|
// KeyStr is Key for a member name that may need escaping.
|
|
235
372
|
func (e *Enc) KeyStr(n int, name string) {
|
|
236
373
|
if n > 0 {
|
|
237
|
-
e.
|
|
374
|
+
e.Byte(',')
|
|
238
375
|
}
|
|
239
|
-
|
|
240
|
-
e.
|
|
376
|
+
putQuoted(e, name)
|
|
377
|
+
e.Byte(':')
|
|
241
378
|
}
|
|
242
379
|
|
|
243
380
|
// Bytes appends a []byte as a base64 string, or null for a nil slice.
|
|
@@ -246,9 +383,9 @@ func (e *Enc) Bytes(v []byte) {
|
|
|
246
383
|
e.Null()
|
|
247
384
|
return
|
|
248
385
|
}
|
|
249
|
-
e.
|
|
250
|
-
|
|
251
|
-
e.
|
|
386
|
+
e.Byte('"')
|
|
387
|
+
putString(e, base64.StdEncoding.EncodeToString(v))
|
|
388
|
+
e.Byte('"')
|
|
252
389
|
}
|
|
253
390
|
|
|
254
391
|
// Raw appends a json.RawMessage: validated and compacted, null when empty.
|
|
@@ -268,15 +405,28 @@ func (e *Enc) Marshaled(out []byte, err error, typ string) {
|
|
|
268
405
|
}
|
|
269
406
|
if err == nil {
|
|
270
407
|
var b []byte
|
|
271
|
-
b, err = AppendCompact(
|
|
408
|
+
b, err = AppendCompact(nil, out, e.EscapeHTML)
|
|
272
409
|
if err == nil {
|
|
273
|
-
e.
|
|
410
|
+
e.putBytes(b)
|
|
274
411
|
return
|
|
275
412
|
}
|
|
276
413
|
}
|
|
277
414
|
e.Fail(&MarshalerError{typ, err, "MarshalJSON"})
|
|
278
415
|
}
|
|
279
416
|
|
|
417
|
+
// TextMarshaled appends the result of a MarshalText call as a JSON string, or
|
|
418
|
+
// the call's error wrapped like Go does.
|
|
419
|
+
func (e *Enc) TextMarshaled(out []byte, err error, typ string) {
|
|
420
|
+
if e.Err != nil {
|
|
421
|
+
return
|
|
422
|
+
}
|
|
423
|
+
if err != nil {
|
|
424
|
+
e.Fail(&MarshalerError{typ, err, "MarshalText"})
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
e.Str(string(out))
|
|
428
|
+
}
|
|
429
|
+
|
|
280
430
|
// SortStrings sorts map keys.
|
|
281
431
|
func SortStrings(a []string) {
|
|
282
432
|
sort.Strings(a)
|