goscript 0.2.5 → 0.2.7
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/cmd/goscript/cmd-compile.go +7 -0
- package/cmd/goscript/cmd_compile_test.go +83 -0
- package/compiler/compile-request.go +3 -0
- package/compiler/compiler-cache.go +828 -0
- package/compiler/compiler-cache_test.go +705 -0
- package/compiler/config.go +2 -0
- package/compiler/index.test.ts +26 -1
- package/compiler/index.ts +5 -0
- package/compiler/lowered-program.go +31 -20
- package/compiler/lowering.go +349 -93
- package/compiler/lowering_bench_test.go +1 -0
- package/compiler/override-facts.go +309 -8
- package/compiler/override-parity-verifier.go +45 -1
- package/compiler/override-parity-verifier_test.go +100 -0
- package/compiler/override-registry_test.go +1 -0
- package/compiler/package-graph.go +40 -12
- package/compiler/package-graph_test.go +29 -0
- package/compiler/runtime-contract.go +8 -0
- package/compiler/service.go +98 -11
- package/compiler/skeleton_test.go +110 -14
- package/compiler/typescript-emitter.go +120 -23
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.js +3 -0
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +24 -33
- package/dist/gs/builtin/builtin.js +54 -61
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +1 -0
- package/dist/gs/builtin/hostio.js +1 -1
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/panic.d.ts +18 -0
- package/dist/gs/builtin/panic.js +98 -0
- package/dist/gs/builtin/panic.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +10 -0
- package/dist/gs/builtin/slice.js +110 -53
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +15 -3
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +1 -1
- package/dist/gs/builtin/varRef.js +3 -2
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js +51 -38
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.d.ts +1 -1
- package/dist/gs/bytes/reader.gs.js +6 -7
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/cmp/index.d.ts +1 -1
- package/dist/gs/cmp/index.js +43 -10
- package/dist/gs/cmp/index.js.map +1 -1
- package/dist/gs/context/context.d.ts +2 -2
- package/dist/gs/context/context.js +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/embed/index.js +1 -1
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/encoding/binary/index.js +201 -8
- package/dist/gs/encoding/binary/index.js.map +1 -1
- package/dist/gs/encoding/json/index.d.ts +5 -0
- package/dist/gs/encoding/json/index.js +388 -25
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.js +17 -24
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.js +129 -35
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -1
- package/dist/gs/internal/bytealg/index.js +43 -8
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +2 -2
- package/dist/gs/internal/byteorder/index.js +2 -2
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/io/fs/format.js +2 -2
- package/dist/gs/io/fs/format.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +1 -1
- package/dist/gs/io/fs/fs.js +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/io.d.ts +21 -21
- package/dist/gs/io/io.js +49 -50
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.js +26 -8
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/math/copysign.gs.js +10 -17
- package/dist/gs/math/copysign.gs.js.map +1 -1
- package/dist/gs/math/pow.gs.js +5 -0
- package/dist/gs/math/pow.gs.js.map +1 -1
- package/dist/gs/math/signbit.gs.js +6 -2
- package/dist/gs/math/signbit.gs.js.map +1 -1
- package/dist/gs/mime/index.js +1 -0
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +6 -6
- package/dist/gs/net/http/index.js +507 -43
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/stat.gs.d.ts +2 -2
- package/dist/gs/os/types.gs.d.ts +1 -1
- package/dist/gs/os/types.gs.js +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -1
- package/dist/gs/os/types_js.gs.js +7 -7
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.d.ts +1 -1
- package/dist/gs/os/types_unix.gs.js +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/os/zero_copy_posix.gs.d.ts +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js +8 -4
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.js +216 -42
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/path/match.js +6 -3
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +5 -4
- package/dist/gs/reflect/type.js +29 -11
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/slices/slices.js +11 -11
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/strconv/atof.gs.js +156 -43
- package/dist/gs/strconv/atof.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.d.ts +3 -2
- package/dist/gs/strconv/atoi.gs.js +86 -67
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/ftoa.gs.js +73 -3
- package/dist/gs/strconv/ftoa.gs.js.map +1 -1
- package/dist/gs/strconv/itoa.gs.d.ts +4 -4
- package/dist/gs/strconv/itoa.gs.js +5 -4
- package/dist/gs/strconv/itoa.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.d.ts +1 -1
- package/dist/gs/strconv/quote.gs.js +311 -103
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js +8 -8
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/strings.js +87 -61
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/atomic/doc_64.gs.d.ts +14 -14
- package/dist/gs/sync/atomic/doc_64.gs.js +10 -10
- package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +22 -22
- package/dist/gs/sync/atomic/type.gs.js +4 -4
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/sync.js +50 -12
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +6 -6
- package/dist/gs/syscall/fs.js +1 -1
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/time/time.d.ts +18 -18
- package/dist/gs/time/time.js +58 -55
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/tables.d.ts +11 -0
- package/dist/gs/unicode/tables.js +635 -0
- package/dist/gs/unicode/tables.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +58 -38
- package/dist/gs/unicode/unicode.js +362 -278
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.sum +13 -0
- package/gs/builtin/builtin.ts +83 -93
- package/gs/builtin/hostio.ts +1 -1
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/panic.test.ts +189 -0
- package/gs/builtin/panic.ts +107 -0
- package/gs/builtin/runtime-contract.test.ts +5 -5
- package/gs/builtin/slice.test.ts +23 -0
- package/gs/builtin/slice.ts +133 -95
- package/gs/builtin/type.ts +16 -3
- package/gs/builtin/varRef.ts +4 -2
- package/gs/builtin/wide-int.test.ts +41 -0
- package/gs/bytes/bytes.gs.ts +54 -41
- package/gs/bytes/bytes.test.ts +18 -1
- package/gs/bytes/reader.gs.ts +7 -8
- package/gs/cmp/index.test.ts +55 -0
- package/gs/cmp/index.ts +45 -9
- package/gs/context/context.ts +3 -3
- package/gs/embed/index.ts +2 -2
- package/gs/encoding/binary/index.test.ts +104 -0
- package/gs/encoding/binary/index.ts +259 -11
- package/gs/encoding/json/index.test.ts +107 -0
- package/gs/encoding/json/index.ts +400 -29
- package/gs/errors/errors.test.ts +44 -1
- package/gs/errors/errors.ts +15 -31
- package/gs/fmt/fmt.test.ts +70 -2
- package/gs/fmt/fmt.ts +128 -34
- package/gs/golang.org/x/crypto/cryptobyte/index.ts +1 -1
- package/gs/internal/bytealg/index.test.ts +26 -1
- package/gs/internal/bytealg/index.ts +44 -8
- package/gs/internal/byteorder/index.ts +6 -4
- package/gs/io/fs/format.ts +2 -2
- package/gs/io/fs/fs.ts +2 -2
- package/gs/io/fs/stat.test.ts +2 -2
- package/gs/io/fs/sub.test.ts +2 -2
- package/gs/io/fs/walk.test.ts +2 -2
- package/gs/io/io.test.ts +47 -5
- package/gs/io/io.ts +73 -73
- package/gs/io/limit.test.ts +103 -0
- package/gs/math/bits/index.test.ts +128 -0
- package/gs/math/bits/index.ts +26 -8
- package/gs/math/copysign.gs.test.ts +3 -1
- package/gs/math/copysign.gs.ts +10 -22
- package/gs/math/pow.gs.test.ts +4 -5
- package/gs/math/pow.gs.ts +5 -0
- package/gs/math/signbit.gs.test.ts +2 -1
- package/gs/math/signbit.gs.ts +6 -3
- package/gs/mime/index.ts +1 -0
- package/gs/net/http/index.test.ts +683 -2
- package/gs/net/http/index.ts +598 -57
- package/gs/net/http/meta.json +3 -0
- package/gs/os/stat.gs.ts +2 -2
- package/gs/os/types.gs.ts +2 -2
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/os/types_unix.gs.ts +2 -2
- package/gs/os/zero_copy_posix.gs.ts +2 -2
- package/gs/path/filepath/match.test.ts +16 -0
- package/gs/path/filepath/match.ts +8 -4
- package/gs/path/filepath/path.test.ts +91 -9
- package/gs/path/filepath/path.ts +223 -49
- package/gs/path/match.test.ts +32 -0
- package/gs/path/match.ts +6 -3
- package/gs/reflect/deepequal.test.ts +1 -1
- package/gs/reflect/field.test.ts +1 -1
- package/gs/reflect/function-types.test.ts +6 -6
- package/gs/reflect/sliceat.test.ts +13 -13
- package/gs/reflect/structof.test.ts +4 -4
- package/gs/reflect/type.ts +34 -14
- package/gs/reflect/typefor.test.ts +5 -5
- package/gs/runtime/pprof/index.test.ts +20 -0
- package/gs/runtime/trace/index.test.ts +3 -0
- package/gs/slices/slices.test.ts +31 -0
- package/gs/slices/slices.ts +11 -11
- package/gs/strconv/append.test.ts +99 -0
- package/gs/strconv/atof.gs.ts +156 -42
- package/gs/strconv/atof.test.ts +45 -0
- package/gs/strconv/atoi.gs.ts +87 -69
- package/gs/strconv/atoi.test.ts +49 -0
- package/gs/strconv/ftoa.gs.ts +85 -10
- package/gs/strconv/ftoa.test.ts +43 -0
- package/gs/strconv/itoa.gs.ts +10 -9
- package/gs/strconv/quote.gs.ts +335 -108
- package/gs/strconv/quote.test.ts +111 -0
- package/gs/strings/reader.test.ts +10 -10
- package/gs/strings/reader.ts +9 -9
- package/gs/strings/strings.test.ts +18 -5
- package/gs/strings/strings.ts +81 -68
- package/gs/sync/atomic/doc_64.gs.ts +24 -24
- package/gs/sync/atomic/doc_64.test.ts +5 -5
- package/gs/sync/atomic/type.gs.ts +28 -28
- package/gs/sync/sync.test.ts +109 -1
- package/gs/sync/sync.ts +46 -12
- package/gs/syscall/fs.ts +8 -8
- package/gs/syscall/net.test.ts +1 -1
- package/gs/time/parse.test.ts +45 -0
- package/gs/time/time.test.ts +46 -23
- package/gs/time/time.ts +69 -66
- package/gs/unicode/gen.go +198 -0
- package/gs/unicode/tables.ts +646 -0
- package/gs/unicode/unicode.test.ts +69 -0
- package/gs/unicode/unicode.ts +396 -312
- package/package.json +2 -2
- package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +0 -20
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js +0 -134
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +0 -1
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +0 -30
- package/gs/github.com/aperturerobotics/util/conc/index.ts +0 -172
- package/gs/github.com/aperturerobotics/util/conc/meta.json +0 -9
|
@@ -48,8 +48,17 @@ type boxedValue = {
|
|
|
48
48
|
__goValue?: unknown
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// binShape recursively describes a fixed-size value for the struct and complex
|
|
52
|
+
// paths that the flat fixedKind union cannot express.
|
|
53
|
+
type binShape =
|
|
54
|
+
| { tag: 'scalar'; kind: fixedKind }
|
|
55
|
+
| { tag: 'complex'; elem: 'float32' | 'float64' }
|
|
56
|
+
| { tag: 'array'; elem: binShape; count: number }
|
|
57
|
+
| { tag: 'struct'; fields: { key: string; shape: binShape }[] }
|
|
58
|
+
|
|
51
59
|
type decodedTarget = {
|
|
52
|
-
kind: fixedKind
|
|
60
|
+
kind: fixedKind | null
|
|
61
|
+
shape?: binShape
|
|
53
62
|
value: unknown
|
|
54
63
|
settable: ((value: unknown) => void) | null
|
|
55
64
|
}
|
|
@@ -391,7 +400,7 @@ export async function Read(
|
|
|
391
400
|
if (target === null) {
|
|
392
401
|
return unsupportedError('Read', data)
|
|
393
402
|
}
|
|
394
|
-
const size =
|
|
403
|
+
const size = targetSize(target)
|
|
395
404
|
if (size < 0) {
|
|
396
405
|
return unsupportedError('Read', data)
|
|
397
406
|
}
|
|
@@ -414,7 +423,7 @@ export function Decode(
|
|
|
414
423
|
if (target === null) {
|
|
415
424
|
return [0, unsupportedError('Decode', data)]
|
|
416
425
|
}
|
|
417
|
-
const size =
|
|
426
|
+
const size = targetSize(target)
|
|
418
427
|
if (size < 0) {
|
|
419
428
|
return [0, unsupportedError('Decode', data)]
|
|
420
429
|
}
|
|
@@ -471,7 +480,14 @@ export function Size(v: unknown): number {
|
|
|
471
480
|
if (target === null) {
|
|
472
481
|
return -1
|
|
473
482
|
}
|
|
474
|
-
return
|
|
483
|
+
return targetSize(target)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function targetSize(target: decodedTarget): number {
|
|
487
|
+
if (target.shape !== undefined) {
|
|
488
|
+
return shapeSize(target.shape)
|
|
489
|
+
}
|
|
490
|
+
return fixedSize(target.kind as fixedKind, target.value)
|
|
475
491
|
}
|
|
476
492
|
|
|
477
493
|
function requireByteOrder(order: ByteOrder | null): ByteOrder {
|
|
@@ -488,14 +504,36 @@ function decodeFixed(
|
|
|
488
504
|
order: ByteOrder,
|
|
489
505
|
target: decodedTarget,
|
|
490
506
|
): void {
|
|
491
|
-
if (target.
|
|
492
|
-
|
|
507
|
+
if (target.shape !== undefined) {
|
|
508
|
+
decodeShapeTarget(buf, order, target)
|
|
509
|
+
return
|
|
510
|
+
}
|
|
511
|
+
const kind = target.kind as fixedKind
|
|
512
|
+
if (kind.startsWith('[]')) {
|
|
513
|
+
decodeFixedSlice(buf, order, kind, target.value)
|
|
493
514
|
return
|
|
494
515
|
}
|
|
495
516
|
if (target.settable === null) {
|
|
496
517
|
return
|
|
497
518
|
}
|
|
498
|
-
target.settable(decodeScalar(buf, order,
|
|
519
|
+
target.settable(decodeScalar(buf, order, kind))
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function decodeShapeTarget(
|
|
523
|
+
buf: $.Slice<number>,
|
|
524
|
+
order: ByteOrder,
|
|
525
|
+
target: decodedTarget,
|
|
526
|
+
): void {
|
|
527
|
+
const shape = target.shape!
|
|
528
|
+
if (shape.tag === 'struct') {
|
|
529
|
+
// Populate the existing struct instance's fields in place.
|
|
530
|
+
shapeDecodeInto(buf, order, shape, target.value)
|
|
531
|
+
return
|
|
532
|
+
}
|
|
533
|
+
if (target.settable === null) {
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
target.settable(shapeDecodeValue(buf, order, shape))
|
|
499
537
|
}
|
|
500
538
|
|
|
501
539
|
function decodeFixedSlice(
|
|
@@ -521,12 +559,16 @@ function encodeData(order: ByteOrder, data: unknown): $.Slice<number> | null {
|
|
|
521
559
|
if (target === null) {
|
|
522
560
|
return null
|
|
523
561
|
}
|
|
524
|
-
const size =
|
|
562
|
+
const size = targetSize(target)
|
|
525
563
|
if (size < 0) {
|
|
526
564
|
return null
|
|
527
565
|
}
|
|
528
566
|
const out = $.makeSlice<number>(size, undefined, 'byte')
|
|
529
|
-
|
|
567
|
+
if (target.shape !== undefined) {
|
|
568
|
+
shapeEncode(out, order, target.shape, target.value)
|
|
569
|
+
} else {
|
|
570
|
+
encodeFixed(out, order, target.kind as fixedKind, target.value)
|
|
571
|
+
}
|
|
530
572
|
return out
|
|
531
573
|
}
|
|
532
574
|
|
|
@@ -625,8 +667,8 @@ function decodeTarget(data: unknown): decodedTarget | null {
|
|
|
625
667
|
const typeName = goTypeName(data)
|
|
626
668
|
const value = goValue(data)
|
|
627
669
|
if (typeName !== '') {
|
|
628
|
-
const
|
|
629
|
-
|
|
670
|
+
const info = goTypeInfo(data)
|
|
671
|
+
const kind = fixedKindFromType(typeName) ?? fixedKindFromTypeInfo(info)
|
|
630
672
|
if (kind !== null) {
|
|
631
673
|
return {
|
|
632
674
|
kind,
|
|
@@ -634,6 +676,17 @@ function decodeTarget(data: unknown): decodedTarget | null {
|
|
|
634
676
|
settable: setterFor(typeName, value),
|
|
635
677
|
}
|
|
636
678
|
}
|
|
679
|
+
// Struct and complex types cannot be named by a flat fixedKind; describe
|
|
680
|
+
// them recursively so Size/Append/Read/Decode handle them like Go.
|
|
681
|
+
const shape = shapeFromType(info ?? typeName)
|
|
682
|
+
if (shape !== null && shape.tag !== 'scalar') {
|
|
683
|
+
return {
|
|
684
|
+
kind: null,
|
|
685
|
+
shape,
|
|
686
|
+
value: pointerValueForKind(typeName, value),
|
|
687
|
+
settable: setterFor(typeName, value),
|
|
688
|
+
}
|
|
689
|
+
}
|
|
637
690
|
return null
|
|
638
691
|
}
|
|
639
692
|
if (value instanceof Uint8Array) {
|
|
@@ -802,6 +855,201 @@ function fixedSize(kind: fixedKind, value: unknown): number {
|
|
|
802
855
|
return -1
|
|
803
856
|
}
|
|
804
857
|
|
|
858
|
+
// shapeFromType builds a recursive fixed-size description from type info, or
|
|
859
|
+
// null when any element is variable-size or otherwise unsupported (which makes
|
|
860
|
+
// the whole struct unsupported, as in Go's dataSize).
|
|
861
|
+
function shapeFromType(info: $.TypeInfo | string | undefined): binShape | null {
|
|
862
|
+
if (info === undefined) {
|
|
863
|
+
return null
|
|
864
|
+
}
|
|
865
|
+
if (typeof info === 'string') {
|
|
866
|
+
if (info === 'complex64') {
|
|
867
|
+
return { tag: 'complex', elem: 'float32' }
|
|
868
|
+
}
|
|
869
|
+
if (info === 'complex128') {
|
|
870
|
+
return { tag: 'complex', elem: 'float64' }
|
|
871
|
+
}
|
|
872
|
+
const kind = fixedKindFromType(info)
|
|
873
|
+
return kind !== null && !kind.startsWith('[]') ?
|
|
874
|
+
{ tag: 'scalar', kind }
|
|
875
|
+
: null
|
|
876
|
+
}
|
|
877
|
+
switch (info.kind) {
|
|
878
|
+
case $.TypeKind.Pointer:
|
|
879
|
+
return shapeFromType(info.elemType)
|
|
880
|
+
case $.TypeKind.Basic: {
|
|
881
|
+
if (info.name === 'complex64') {
|
|
882
|
+
return { tag: 'complex', elem: 'float32' }
|
|
883
|
+
}
|
|
884
|
+
if (info.name === 'complex128') {
|
|
885
|
+
return { tag: 'complex', elem: 'float64' }
|
|
886
|
+
}
|
|
887
|
+
const kind = fixedKindFromBasicName(info.name)
|
|
888
|
+
return kind !== null ? { tag: 'scalar', kind } : null
|
|
889
|
+
}
|
|
890
|
+
case $.TypeKind.Array: {
|
|
891
|
+
const elem = shapeFromType(info.elemType)
|
|
892
|
+
return elem === null ? null : (
|
|
893
|
+
{ tag: 'array', elem, count: (info as $.ArrayTypeInfo).length }
|
|
894
|
+
)
|
|
895
|
+
}
|
|
896
|
+
case $.TypeKind.Struct: {
|
|
897
|
+
const fields: { key: string; shape: binShape }[] = []
|
|
898
|
+
for (const field of (info as $.StructTypeInfo).fields) {
|
|
899
|
+
const shape = shapeFromType(field.type)
|
|
900
|
+
if (shape === null) {
|
|
901
|
+
return null
|
|
902
|
+
}
|
|
903
|
+
fields.push({ key: field.key ?? field.name, shape })
|
|
904
|
+
}
|
|
905
|
+
return { tag: 'struct', fields }
|
|
906
|
+
}
|
|
907
|
+
default:
|
|
908
|
+
return null
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function shapeSize(shape: binShape): number {
|
|
913
|
+
switch (shape.tag) {
|
|
914
|
+
case 'scalar':
|
|
915
|
+
return fixedSize(shape.kind, 0)
|
|
916
|
+
case 'complex':
|
|
917
|
+
return shape.elem === 'float32' ? 8 : 16
|
|
918
|
+
case 'array':
|
|
919
|
+
return shapeSize(shape.elem) * shape.count
|
|
920
|
+
case 'struct': {
|
|
921
|
+
let total = 0
|
|
922
|
+
for (const field of shape.fields) {
|
|
923
|
+
total += shapeSize(field.shape)
|
|
924
|
+
}
|
|
925
|
+
return total
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function structFieldValue(instance: unknown, key: string): unknown {
|
|
931
|
+
const ref = (instance as { _fields: Record<string, $.VarRef<unknown>> })
|
|
932
|
+
._fields[key]
|
|
933
|
+
return ref.value
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
function shapeEncode(
|
|
937
|
+
buf: $.Slice<number>,
|
|
938
|
+
order: ByteOrder,
|
|
939
|
+
shape: binShape,
|
|
940
|
+
value: unknown,
|
|
941
|
+
): void {
|
|
942
|
+
switch (shape.tag) {
|
|
943
|
+
case 'scalar':
|
|
944
|
+
encodeScalar(buf, order, shape.kind, value)
|
|
945
|
+
return
|
|
946
|
+
case 'complex': {
|
|
947
|
+
const c = value as { real: number; imag: number }
|
|
948
|
+
if (shape.elem === 'float32') {
|
|
949
|
+
order.PutUint32($.goSlice(buf, 0, 4), float32Bits(c.real))
|
|
950
|
+
order.PutUint32($.goSlice(buf, 4, 8), float32Bits(c.imag))
|
|
951
|
+
} else {
|
|
952
|
+
order.PutUint64(
|
|
953
|
+
$.goSlice(buf, 0, 8),
|
|
954
|
+
float64Bits(c.real) as unknown as number,
|
|
955
|
+
)
|
|
956
|
+
order.PutUint64(
|
|
957
|
+
$.goSlice(buf, 8, 16),
|
|
958
|
+
float64Bits(c.imag) as unknown as number,
|
|
959
|
+
)
|
|
960
|
+
}
|
|
961
|
+
return
|
|
962
|
+
}
|
|
963
|
+
case 'array': {
|
|
964
|
+
const width = shapeSize(shape.elem)
|
|
965
|
+
for (let i = 0; i < shape.count; i++) {
|
|
966
|
+
shapeEncode(
|
|
967
|
+
$.goSlice(buf, i * width, i * width + width),
|
|
968
|
+
order,
|
|
969
|
+
shape.elem,
|
|
970
|
+
(value as $.Slice<unknown>)![i],
|
|
971
|
+
)
|
|
972
|
+
}
|
|
973
|
+
return
|
|
974
|
+
}
|
|
975
|
+
case 'struct': {
|
|
976
|
+
let offset = 0
|
|
977
|
+
for (const field of shape.fields) {
|
|
978
|
+
const width = shapeSize(field.shape)
|
|
979
|
+
shapeEncode(
|
|
980
|
+
$.goSlice(buf, offset, offset + width),
|
|
981
|
+
order,
|
|
982
|
+
field.shape,
|
|
983
|
+
structFieldValue(value, field.key),
|
|
984
|
+
)
|
|
985
|
+
offset += width
|
|
986
|
+
}
|
|
987
|
+
return
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function shapeDecodeValue(
|
|
993
|
+
buf: $.Slice<number>,
|
|
994
|
+
order: ByteOrder,
|
|
995
|
+
shape: binShape,
|
|
996
|
+
): unknown {
|
|
997
|
+
switch (shape.tag) {
|
|
998
|
+
case 'scalar':
|
|
999
|
+
return decodeScalar(buf, order, shape.kind)
|
|
1000
|
+
case 'complex':
|
|
1001
|
+
if (shape.elem === 'float32') {
|
|
1002
|
+
return {
|
|
1003
|
+
real: float32FromBits(order.Uint32($.goSlice(buf, 0, 4))),
|
|
1004
|
+
imag: float32FromBits(order.Uint32($.goSlice(buf, 4, 8))),
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return {
|
|
1008
|
+
real: float64FromBits(order.Uint64($.goSlice(buf, 0, 8))),
|
|
1009
|
+
imag: float64FromBits(order.Uint64($.goSlice(buf, 8, 16))),
|
|
1010
|
+
}
|
|
1011
|
+
case 'array': {
|
|
1012
|
+
const width = shapeSize(shape.elem)
|
|
1013
|
+
const out: unknown[] = []
|
|
1014
|
+
for (let i = 0; i < shape.count; i++) {
|
|
1015
|
+
out.push(
|
|
1016
|
+
shapeDecodeValue(
|
|
1017
|
+
$.goSlice(buf, i * width, i * width + width),
|
|
1018
|
+
order,
|
|
1019
|
+
shape.elem,
|
|
1020
|
+
),
|
|
1021
|
+
)
|
|
1022
|
+
}
|
|
1023
|
+
return out
|
|
1024
|
+
}
|
|
1025
|
+
case 'struct':
|
|
1026
|
+
// Nested structs are populated in place by shapeDecodeInto.
|
|
1027
|
+
return null
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function shapeDecodeInto(
|
|
1032
|
+
buf: $.Slice<number>,
|
|
1033
|
+
order: ByteOrder,
|
|
1034
|
+
shape: { tag: 'struct'; fields: { key: string; shape: binShape }[] },
|
|
1035
|
+
instance: unknown,
|
|
1036
|
+
): void {
|
|
1037
|
+
const fields = (instance as { _fields: Record<string, $.VarRef<unknown>> })
|
|
1038
|
+
._fields
|
|
1039
|
+
let offset = 0
|
|
1040
|
+
for (const field of shape.fields) {
|
|
1041
|
+
const width = shapeSize(field.shape)
|
|
1042
|
+
const slice = $.goSlice(buf, offset, offset + width)
|
|
1043
|
+
const ref = fields[field.key]
|
|
1044
|
+
if (field.shape.tag === 'struct') {
|
|
1045
|
+
shapeDecodeInto(slice, order, field.shape, ref.value)
|
|
1046
|
+
} else {
|
|
1047
|
+
ref.value = shapeDecodeValue(slice, order, field.shape)
|
|
1048
|
+
}
|
|
1049
|
+
offset += width
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
805
1053
|
function unsupportedError(fn: string, data: unknown): $.GoError {
|
|
806
1054
|
return $.newError(
|
|
807
1055
|
`encoding/binary: ${fn} of ${unsupportedKind(data)} is not supported in the GoScript browser build`,
|
|
@@ -401,6 +401,113 @@ describe('encoding/json override', () => {
|
|
|
401
401
|
expect(escaped.String()).toBe('"\\u003ctag\\u003e\\u0026"')
|
|
402
402
|
})
|
|
403
403
|
|
|
404
|
+
it('preserves number and string literal spelling through Compact and Indent', () => {
|
|
405
|
+
const compact = new bytes.Buffer()
|
|
406
|
+
expect(
|
|
407
|
+
Compact(
|
|
408
|
+
compact,
|
|
409
|
+
$.stringToBytes('{"n": 1e+00, "big": 9007199254740993, "s": "abc"}'),
|
|
410
|
+
),
|
|
411
|
+
).toBeNull()
|
|
412
|
+
expect(compact.String()).toBe(
|
|
413
|
+
'{"n":1e+00,"big":9007199254740993,"s":"abc"}',
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
const compact2 = new bytes.Buffer()
|
|
417
|
+
expect(Compact(compact2, $.stringToBytes('{"n":1e+00}'))).toBeNull()
|
|
418
|
+
expect(compact2.String()).toBe('{"n":1e+00}')
|
|
419
|
+
|
|
420
|
+
const indented = new bytes.Buffer()
|
|
421
|
+
expect(
|
|
422
|
+
Indent(indented, $.stringToBytes('{"a":1,"b":[2,3],"e":{}}'), '', ' '),
|
|
423
|
+
).toBeNull()
|
|
424
|
+
expect(indented.String()).toBe(
|
|
425
|
+
'{\n "a": 1,\n "b": [\n 2,\n 3\n ],\n "e": {}\n}',
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
// Go's Indent copies trailing whitespace after the value verbatim.
|
|
429
|
+
const trailing = new bytes.Buffer()
|
|
430
|
+
expect(
|
|
431
|
+
Indent(trailing, $.stringToBytes('{"a":1}\n'), '', ' '),
|
|
432
|
+
).toBeNull()
|
|
433
|
+
expect(trailing.String()).toBe('{\n "a": 1\n}\n')
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
it('keeps exact source literals for UseNumber beyond float64 precision', () => {
|
|
437
|
+
const reader = bytes.NewBufferString('{"big":9007199254740993,"f":1e+00}')!
|
|
438
|
+
const decoder = NewDecoder(reader)
|
|
439
|
+
decoder.UseNumber()
|
|
440
|
+
const target = $.varRef<Map<string, unknown> | null>(null)
|
|
441
|
+
|
|
442
|
+
expect(decoder.Decode(target)).toBeNull()
|
|
443
|
+
expect(target.value?.get('big')).toBe('9007199254740993')
|
|
444
|
+
expect(target.value?.get('f')).toBe('1e+00')
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('returns a SyntaxError with the Go byte offset for malformed input', () => {
|
|
448
|
+
const cases: Array<[string, number]> = [
|
|
449
|
+
['[1,]', 4],
|
|
450
|
+
['{"a":}', 6],
|
|
451
|
+
['[1 2]', 4],
|
|
452
|
+
['truex', 5],
|
|
453
|
+
['123abc', 4],
|
|
454
|
+
]
|
|
455
|
+
for (const [input, offset] of cases) {
|
|
456
|
+
const target = $.varRef<unknown>(null)
|
|
457
|
+
const err = Unmarshal($.stringToBytes(input), target)
|
|
458
|
+
expect(err).toBeInstanceOf(JSONSyntaxError)
|
|
459
|
+
expect((err as InstanceType<typeof JSONSyntaxError>).Offset).toBe(offset)
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
it('decodes one value per Decode and buffers the rest of the stream', () => {
|
|
464
|
+
const decoder = NewDecoder(bytes.NewBufferString('1 2')!)
|
|
465
|
+
const first = $.varRef<unknown>(null)
|
|
466
|
+
const second = $.varRef<unknown>(null)
|
|
467
|
+
|
|
468
|
+
expect(decoder.Decode(first)).toBeNull()
|
|
469
|
+
expect(first.value).toBe(1)
|
|
470
|
+
expect(decoder.Decode(second)).toBeNull()
|
|
471
|
+
expect(second.value).toBe(2)
|
|
472
|
+
expect(decoder.Decode($.varRef<unknown>(null))?.Error()).toBe('EOF')
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
it('streams delimiters and values through Token and reports More', () => {
|
|
476
|
+
const tokens = NewDecoder(bytes.NewBufferString('[1]')!)
|
|
477
|
+
expect(tokens.Token()).toEqual(['['.charCodeAt(0), null])
|
|
478
|
+
expect(tokens.Token()).toEqual([1, null])
|
|
479
|
+
expect(tokens.Token()).toEqual([']'.charCodeAt(0), null])
|
|
480
|
+
expect(tokens.Token()[1]?.Error()).toBe('EOF')
|
|
481
|
+
|
|
482
|
+
const more = NewDecoder(bytes.NewBufferString('[1,2]')!)
|
|
483
|
+
more.Token() // consume [
|
|
484
|
+
expect(more.More()).toBe(true)
|
|
485
|
+
more.Token() // 1
|
|
486
|
+
expect(more.More()).toBe(true)
|
|
487
|
+
more.Token() // 2
|
|
488
|
+
expect(more.More()).toBe(false)
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
it('marshals a RawMessage field without normalizing its token spelling', () => {
|
|
492
|
+
class RawHolder {
|
|
493
|
+
public _fields = {
|
|
494
|
+
R: $.varRef($.stringToBytes('1e+00')),
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
static __typeInfo = $.registerStructType(
|
|
498
|
+
'test.RawHolder',
|
|
499
|
+
new RawHolder(),
|
|
500
|
+
[],
|
|
501
|
+
RawHolder,
|
|
502
|
+
[{ name: 'R', key: 'R', type: 'json.RawMessage', tag: 'json:"r"' }],
|
|
503
|
+
)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const [data, err] = Marshal(new RawHolder())
|
|
507
|
+
expect(err).toBeNull()
|
|
508
|
+
expect($.bytesToString(data)).toBe('{"r":1e+00}')
|
|
509
|
+
})
|
|
510
|
+
|
|
404
511
|
it('decodes from readers and exposes raw message and number helpers', () => {
|
|
405
512
|
const reader = bytes.NewBufferString('{"name":"Dana","age":28}')!
|
|
406
513
|
const decoder = NewDecoder(reader)
|