goscript 0.0.84 → 0.1.1
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 +267 -243
- package/cmd/goscript/cmd-test.go +193 -0
- package/cmd/goscript/cmd-test_test.go +76 -0
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +11 -5
- package/compiler/build-flags.go +38 -0
- package/compiler/compile-request.go +220 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +188 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/gotest/owner.go +24 -0
- package/compiler/gotest/package-result.go +67 -0
- package/compiler/gotest/request.go +145 -0
- package/compiler/gotest/result.go +28 -0
- package/compiler/gotest/runner.go +588 -0
- package/compiler/gotest/runner_test.go +627 -0
- package/compiler/gotest/test.go +9 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +184 -0
- package/compiler/lowering.go +8072 -0
- package/compiler/override-facts.go +307 -0
- package/compiler/override-registry.go +283 -0
- package/compiler/override-registry_test.go +254 -0
- package/compiler/package-graph.go +254 -0
- package/compiler/package-graph_test.go +316 -0
- package/compiler/package-test-function.go +9 -0
- package/compiler/package-test-graph-package.go +40 -0
- package/compiler/package-test-graph-variant.go +105 -0
- package/compiler/package-test-graph.go +117 -0
- package/compiler/package-test-graph_test.go +144 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +439 -0
- package/compiler/runtime-contract_test.go +104 -0
- package/compiler/semantic-model-types.go +113 -0
- package/compiler/semantic-model.go +1422 -0
- package/compiler/semantic-model_test.go +471 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1775 -0
- package/compiler/tsworkspace/owner.go +334 -0
- package/compiler/tsworkspace/owner_test.go +93 -0
- package/compiler/tsworkspace/result.go +17 -0
- package/compiler/typescript-emitter.go +1040 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +79 -0
- package/compiler/wasm_api.go +140 -124
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +33 -2
- package/dist/gs/builtin/builtin.js +217 -6
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +11 -3
- package/dist/gs/builtin/channel.js +12 -0
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +15 -1
- package/dist/gs/builtin/hostio.js +134 -49
- 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/slice.d.ts +23 -3
- package/dist/gs/builtin/slice.js +216 -44
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +16 -2
- package/dist/gs/builtin/type.js +134 -21
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +5 -0
- package/dist/gs/builtin/varRef.js +23 -0
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +48 -44
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js +20 -18
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.d.ts +5 -4
- package/dist/gs/context/context.js +10 -10
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/internal/fips140deps/byteorder/index.d.ts +1 -0
- package/dist/gs/crypto/internal/fips140deps/byteorder/index.js +2 -0
- package/dist/gs/crypto/internal/fips140deps/byteorder/index.js.map +1 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/index.d.ts +1 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/index.js +2 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/index.js.map +1 -0
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/embed/index.d.ts +7 -0
- package/dist/gs/embed/index.js +16 -0
- package/dist/gs/embed/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +4 -0
- package/dist/gs/encoding/json/index.js +178 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/errors/errors.d.ts +4 -0
- package/dist/gs/errors/errors.js +81 -0
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +4 -4
- package/dist/gs/fmt/fmt.js +42 -11
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +36 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +212 -2
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +189 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +825 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +163 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +449 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/klauspost/compress/internal/le/index.d.ts +9 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js +71 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/internal/scannerhooks/index.d.ts +3 -0
- package/dist/gs/go/internal/scannerhooks/index.js +5 -0
- package/dist/gs/go/internal/scannerhooks/index.js.map +1 -0
- package/dist/gs/go/scanner/index.d.ts +42 -0
- package/dist/gs/go/scanner/index.js +155 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +187 -0
- package/dist/gs/go/token/index.js +578 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.d.ts +4 -0
- package/dist/gs/internal/abi/index.js +10 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/internal/bytealg/index.d.ts +2 -0
- package/dist/gs/internal/bytealg/index.js +14 -0
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +8 -2
- package/dist/gs/internal/byteorder/index.js +56 -25
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/internal/godebug/index.d.ts +12 -0
- package/dist/gs/internal/godebug/index.js +30 -0
- package/dist/gs/internal/godebug/index.js.map +1 -0
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/index.d.ts +1 -0
- package/dist/gs/io/fs/index.js +1 -0
- package/dist/gs/io/fs/index.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/readlink.d.ts +8 -0
- package/dist/gs/io/fs/readlink.js +64 -0
- package/dist/gs/io/fs/readlink.js.map +1 -0
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.d.ts +3 -3
- package/dist/gs/io/fs/walk.js +7 -7
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.d.ts +40 -6
- package/dist/gs/io/io.js +151 -26
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/maps/iter.d.ts +3 -3
- package/dist/gs/maps/iter.js +3 -3
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.d.ts +2 -2
- package/dist/gs/maps/maps.js +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/math/bits/index.d.ts +13 -4
- package/dist/gs/math/bits/index.js +66 -34
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/math/const.gs.d.ts +5 -5
- package/dist/gs/math/const.gs.js +4 -4
- package/dist/gs/math/const.gs.js.map +1 -1
- package/dist/gs/mime/index.d.ts +1 -0
- package/dist/gs/mime/index.js +50 -0
- package/dist/gs/mime/index.js.map +1 -0
- package/dist/gs/net/http/httptest/index.d.ts +11 -0
- package/dist/gs/net/http/httptest/index.js +21 -0
- package/dist/gs/net/http/httptest/index.js.map +1 -0
- package/dist/gs/net/http/index.d.ts +27 -0
- package/dist/gs/net/http/index.js +61 -0
- package/dist/gs/net/http/index.js.map +1 -0
- package/dist/gs/os/dir_unix.gs.js +2 -2
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +9 -9
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js +165 -3
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +3 -1
- package/dist/gs/path/filepath/path.js +133 -4
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.d.ts +4 -1
- package/dist/gs/path/path.js +16 -4
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +3 -3
- package/dist/gs/reflect/index.js +2 -2
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js +3 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +9 -5
- package/dist/gs/reflect/type.js +233 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/debug/index.d.ts +2 -0
- package/dist/gs/runtime/debug/index.js +8 -0
- package/dist/gs/runtime/debug/index.js.map +1 -0
- package/dist/gs/runtime/runtime.d.ts +35 -3
- package/dist/gs/runtime/runtime.js +72 -0
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +24 -5
- package/dist/gs/slices/slices.js +214 -5
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sort/slice.gs.d.ts +3 -3
- package/dist/gs/sort/slice.gs.js +6 -6
- package/dist/gs/sort/slice.gs.js.map +1 -1
- package/dist/gs/sort/sort.gs.d.ts +4 -4
- package/dist/gs/sort/sort.gs.js +11 -8
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.d.ts +1 -1
- package/dist/gs/strings/builder.js +3 -2
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +9 -8
- package/dist/gs/sync/atomic/type.gs.js +0 -2
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +3 -0
- package/dist/gs/sync/sync.js +39 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/constants.d.ts +36 -24
- package/dist/gs/syscall/constants.js +12 -0
- package/dist/gs/syscall/constants.js.map +1 -1
- package/dist/gs/syscall/errors.d.ts +2 -0
- package/dist/gs/syscall/errors.js +8 -0
- package/dist/gs/syscall/errors.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +43 -0
- package/dist/gs/syscall/fs.js +102 -0
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/syscall/js/index.d.ts +90 -0
- package/dist/gs/syscall/js/index.js +375 -0
- package/dist/gs/syscall/js/index.js.map +1 -0
- package/dist/gs/syscall/types.d.ts +22 -0
- package/dist/gs/syscall/types.js +45 -1
- package/dist/gs/syscall/types.js.map +1 -1
- package/dist/gs/testing/index.d.ts +1 -0
- package/dist/gs/testing/index.js +2 -0
- package/dist/gs/testing/index.js.map +1 -0
- package/dist/gs/testing/testing.d.ts +77 -0
- package/dist/gs/testing/testing.js +301 -0
- package/dist/gs/testing/testing.js.map +1 -0
- package/dist/gs/time/time.d.ts +41 -4
- package/dist/gs/time/time.js +205 -36
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.d.ts +23 -1
- package/dist/gs/unicode/unicode.js +79 -10
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/dist/gs/unicode/utf8/utf8.d.ts +4 -4
- package/dist/gs/unicode/utf8/utf8.js +24 -11
- package/dist/gs/unicode/utf8/utf8.js.map +1 -1
- package/dist/gs/unique/index.d.ts +11 -0
- package/dist/gs/unique/index.js +71 -0
- package/dist/gs/unique/index.js.map +1 -0
- package/go.mod +2 -2
- package/go.sum +9 -0
- package/gs/builtin/builtin.ts +266 -8
- package/gs/builtin/channel.ts +22 -0
- package/gs/builtin/hostio.test.ts +177 -0
- package/gs/builtin/hostio.ts +171 -56
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/runtime-contract.test.ts +356 -0
- package/gs/builtin/slice.ts +259 -50
- package/gs/builtin/type.ts +188 -30
- package/gs/builtin/varRef.ts +38 -1
- package/gs/bytes/buffer.gs.ts +48 -44
- package/gs/bytes/meta.json +8 -3
- package/gs/bytes/reader.gs.ts +20 -19
- package/gs/context/context.test.ts +41 -0
- package/gs/context/context.ts +22 -26
- package/gs/crypto/internal/fips140deps/byteorder/index.ts +1 -0
- package/gs/crypto/internal/fips140deps/godebug/index.ts +1 -0
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/embed/index.ts +20 -0
- package/gs/embed/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +79 -0
- package/gs/encoding/json/index.ts +210 -0
- package/gs/errors/errors.test.ts +82 -0
- package/gs/errors/errors.ts +104 -0
- package/gs/fmt/fmt.ts +56 -16
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +95 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +300 -2
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +159 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +1005 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +719 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +40 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/github.com/klauspost/compress/internal/le/index.test.ts +36 -0
- package/gs/github.com/klauspost/compress/internal/le/index.ts +114 -0
- package/gs/go/internal/scannerhooks/index.test.ts +14 -0
- package/gs/go/internal/scannerhooks/index.ts +9 -0
- package/gs/go/scanner/index.test.ts +72 -0
- package/gs/go/scanner/index.ts +204 -0
- package/gs/go/token/index.test.ts +67 -0
- package/gs/go/token/index.ts +686 -0
- package/gs/internal/abi/index.test.ts +18 -0
- package/gs/internal/abi/index.ts +14 -0
- package/gs/internal/bytealg/index.test.ts +18 -0
- package/gs/internal/bytealg/index.ts +16 -0
- package/gs/internal/byteorder/index.test.ts +39 -0
- package/gs/internal/byteorder/index.ts +100 -27
- package/gs/internal/godebug/index.test.ts +16 -0
- package/gs/internal/godebug/index.ts +35 -0
- package/gs/io/fs/index.ts +1 -0
- package/gs/io/fs/meta.json +5 -0
- package/gs/io/fs/readlink.test.ts +43 -0
- package/gs/io/fs/readlink.ts +77 -0
- package/gs/io/fs/walk.test.ts +61 -0
- package/gs/io/fs/walk.ts +9 -9
- package/gs/io/io.ts +174 -31
- package/gs/io/meta.json +10 -2
- package/gs/maps/iter.ts +12 -6
- package/gs/maps/maps.ts +8 -6
- package/gs/math/bits/index.ts +103 -47
- package/gs/math/const.gs.test.ts +11 -5
- package/gs/math/const.gs.ts +5 -6
- package/gs/mime/index.ts +54 -0
- package/gs/net/http/httptest/index.ts +25 -0
- package/gs/net/http/index.test.ts +20 -0
- package/gs/net/http/index.ts +81 -0
- package/gs/os/dir_unix.gs.ts +2 -3
- package/gs/os/file_unix_js.test.ts +50 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +11 -11
- package/gs/path/filepath/match.test.ts +31 -12
- package/gs/path/filepath/match.ts +178 -3
- package/gs/path/filepath/path.test.ts +25 -0
- package/gs/path/filepath/path.ts +159 -5
- package/gs/path/path.ts +20 -5
- package/gs/reflect/index.ts +2 -1
- package/gs/reflect/map.test.ts +19 -0
- package/gs/reflect/map.ts +4 -0
- package/gs/reflect/type.ts +298 -29
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/runtime/debug/index.test.ts +24 -0
- package/gs/runtime/debug/index.ts +8 -0
- package/gs/runtime/runtime.test.ts +19 -0
- package/gs/runtime/runtime.ts +98 -3
- package/gs/slices/slices.test.ts +94 -0
- package/gs/slices/slices.ts +245 -5
- package/gs/sort/meta.json +7 -0
- package/gs/sort/slice.gs.ts +16 -7
- package/gs/sort/sort.gs.ts +16 -13
- package/gs/strings/builder.ts +4 -3
- package/gs/sync/atomic/type.gs.ts +13 -14
- package/gs/sync/meta.json +3 -1
- package/gs/sync/sync.test.ts +36 -0
- package/gs/sync/sync.ts +39 -0
- package/gs/syscall/constants.ts +39 -24
- package/gs/syscall/errors.ts +10 -0
- package/gs/syscall/fs.ts +195 -0
- package/gs/syscall/js/index.ts +458 -0
- package/gs/syscall/js/meta.json +4 -0
- package/gs/syscall/net.test.ts +85 -0
- package/gs/syscall/types.ts +56 -0
- package/gs/testing/index.ts +1 -0
- package/gs/testing/meta.json +5 -0
- package/gs/testing/testing.test.ts +90 -0
- package/gs/testing/testing.ts +382 -0
- package/gs/time/time.test.ts +106 -0
- package/gs/time/time.ts +278 -57
- package/gs/unicode/unicode.test.ts +25 -0
- package/gs/unicode/unicode.ts +119 -9
- package/gs/unicode/utf8/utf8.test.ts +13 -0
- package/gs/unicode/utf8/utf8.ts +28 -16
- package/gs/unique/index.ts +91 -0
- package/package.json +14 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
|
@@ -0,0 +1,1775 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"errors"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"regexp"
|
|
9
|
+
"slices"
|
|
10
|
+
"strings"
|
|
11
|
+
"testing"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
func TestConfigValidate(t *testing.T) {
|
|
15
|
+
tests := []struct {
|
|
16
|
+
name string
|
|
17
|
+
config *Config
|
|
18
|
+
wantErr bool
|
|
19
|
+
errMsg string
|
|
20
|
+
}{
|
|
21
|
+
{
|
|
22
|
+
name: "valid config",
|
|
23
|
+
config: &Config{
|
|
24
|
+
Dir: "/some/dir",
|
|
25
|
+
OutputPath: "/output/path",
|
|
26
|
+
BuildFlags: []string{"-tags", "sometag"},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "empty output path root",
|
|
31
|
+
config: &Config{
|
|
32
|
+
Dir: "/some/dir",
|
|
33
|
+
BuildFlags: []string{"-tags", "sometag"},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "nil config",
|
|
38
|
+
config: nil,
|
|
39
|
+
wantErr: true,
|
|
40
|
+
errMsg: "config cannot be nil",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "nil fset gets initialized",
|
|
44
|
+
config: &Config{
|
|
45
|
+
OutputPath: "/output/path",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for _, tt := range tests {
|
|
51
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
52
|
+
err := tt.config.Validate()
|
|
53
|
+
if (err != nil) != tt.wantErr {
|
|
54
|
+
t.Fatalf("Config.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
|
55
|
+
}
|
|
56
|
+
if err != nil && err.Error() != tt.errMsg {
|
|
57
|
+
t.Fatalf("Config.Validate() error = %q, want %q", err.Error(), tt.errMsg)
|
|
58
|
+
}
|
|
59
|
+
if err == nil && tt.config.fset == nil {
|
|
60
|
+
t.Fatalf("Config.Validate() did not initialize fset")
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func TestCompilePackagesRejectsSingleFileBeforeOutput(t *testing.T) {
|
|
67
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
68
|
+
comp, err := NewCompiler(&Config{OutputPath: outputDir}, nil, nil)
|
|
69
|
+
if err != nil {
|
|
70
|
+
t.Fatal(err.Error())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
result, err := comp.CompilePackages(context.Background(), "main.go")
|
|
74
|
+
if err == nil {
|
|
75
|
+
t.Fatal("expected single-file request to fail")
|
|
76
|
+
}
|
|
77
|
+
requireDiagnostic(t, err, "goscript/request:single-file-unsupported")
|
|
78
|
+
if result == nil || len(result.Diagnostics) == 0 {
|
|
79
|
+
t.Fatalf("expected structured diagnostics in result")
|
|
80
|
+
}
|
|
81
|
+
if _, statErr := os.Stat(outputDir); !os.IsNotExist(statErr) {
|
|
82
|
+
t.Fatalf("compile wrote output directory before validation stopped: %v", statErr)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func TestCompilePackagesEmitsSimplePackage(t *testing.T) {
|
|
87
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
88
|
+
"go.mod": "module example.test/simple\n\ngo 1.25.3\n",
|
|
89
|
+
"main.go": strings.Join([]string{
|
|
90
|
+
"package main",
|
|
91
|
+
"const Greeting = \"Hello\"",
|
|
92
|
+
"func Add(a int, b int) int {",
|
|
93
|
+
" return a + b",
|
|
94
|
+
"}",
|
|
95
|
+
"func main() {",
|
|
96
|
+
" total := Add(2, 3)",
|
|
97
|
+
" size := len(Greeting)",
|
|
98
|
+
" print(\"total:\", size)",
|
|
99
|
+
" if total == 5 {",
|
|
100
|
+
" println(Greeting, total)",
|
|
101
|
+
" }",
|
|
102
|
+
" if false {",
|
|
103
|
+
" panic(\"unreachable\")",
|
|
104
|
+
" }",
|
|
105
|
+
"}",
|
|
106
|
+
"",
|
|
107
|
+
}, "\n"),
|
|
108
|
+
})
|
|
109
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
110
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
111
|
+
if err != nil {
|
|
112
|
+
t.Fatal(err.Error())
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
116
|
+
if err != nil {
|
|
117
|
+
t.Fatal(err.Error())
|
|
118
|
+
}
|
|
119
|
+
if result == nil || len(result.CompiledPackages) != 1 || result.CompiledPackages[0] != "example.test/simple" {
|
|
120
|
+
t.Fatalf("unexpected result: %#v", result)
|
|
121
|
+
}
|
|
122
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "simple", "main.gs.ts")
|
|
123
|
+
content, err := os.ReadFile(outputFile)
|
|
124
|
+
if err != nil {
|
|
125
|
+
t.Fatal(err.Error())
|
|
126
|
+
}
|
|
127
|
+
text := string(content)
|
|
128
|
+
for _, want := range []string{
|
|
129
|
+
"import * as $ from \"@goscript/builtin/index.js\"",
|
|
130
|
+
"export const Greeting: string = \"Hello\"",
|
|
131
|
+
"export function Add(a: number, b: number): number",
|
|
132
|
+
"export async function main(): globalThis.Promise<void>",
|
|
133
|
+
"let size = 5",
|
|
134
|
+
"$.print(\"total:\", size)",
|
|
135
|
+
"$.println(Greeting, total)",
|
|
136
|
+
"$.panic(\"unreachable\")",
|
|
137
|
+
"await main()",
|
|
138
|
+
} {
|
|
139
|
+
if !strings.Contains(text, want) {
|
|
140
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func TestCompilePackagesSkipsPureTopLevelBlankAssertions(t *testing.T) {
|
|
146
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
147
|
+
"go.mod": "module example.test/blankassert\n\ngo 1.25.3\n",
|
|
148
|
+
"main.go": strings.Join([]string{
|
|
149
|
+
"package main",
|
|
150
|
+
"type named interface { Name() string }",
|
|
151
|
+
"type item struct{}",
|
|
152
|
+
"func (*item) Name() string { return \"item\" }",
|
|
153
|
+
"var defaultItem = &item{}",
|
|
154
|
+
"var _ named = defaultItem",
|
|
155
|
+
"func main() { println(defaultItem.Name()) }",
|
|
156
|
+
"",
|
|
157
|
+
}, "\n"),
|
|
158
|
+
})
|
|
159
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
160
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
161
|
+
if err != nil {
|
|
162
|
+
t.Fatal(err.Error())
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
166
|
+
t.Fatal(err.Error())
|
|
167
|
+
}
|
|
168
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "blankassert", "main.gs.ts")
|
|
169
|
+
content, err := os.ReadFile(outputFile)
|
|
170
|
+
if err != nil {
|
|
171
|
+
t.Fatal(err.Error())
|
|
172
|
+
}
|
|
173
|
+
text := string(content)
|
|
174
|
+
if strings.Contains(text, "__goscriptBlank") {
|
|
175
|
+
t.Fatalf("pure top-level blank assertion emitted runtime binding:\n%s", text)
|
|
176
|
+
}
|
|
177
|
+
if !strings.Contains(text, "export let defaultItem") {
|
|
178
|
+
t.Fatalf("missing real package variable:\n%s", text)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func TestCompilePackagesLazilyInitializesCrossFilePackageVars(t *testing.T) {
|
|
183
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
184
|
+
"go.mod": "module example.test/lazyvars\n\ngo 1.25.3\n",
|
|
185
|
+
"a.go": strings.Join([]string{
|
|
186
|
+
"package main",
|
|
187
|
+
"type words []int",
|
|
188
|
+
"type remote struct { n int }",
|
|
189
|
+
"var one = words{1}",
|
|
190
|
+
"func useTwo() int { return two.values[0] + remoteZero.n }",
|
|
191
|
+
"",
|
|
192
|
+
}, "\n"),
|
|
193
|
+
"b.go": strings.Join([]string{
|
|
194
|
+
"package main",
|
|
195
|
+
"type holder struct { values words }",
|
|
196
|
+
"var two = holder{one}",
|
|
197
|
+
"var remoteZero remote",
|
|
198
|
+
"func main() { println(useTwo(), two.values[0]) }",
|
|
199
|
+
"",
|
|
200
|
+
}, "\n"),
|
|
201
|
+
})
|
|
202
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
203
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
204
|
+
if err != nil {
|
|
205
|
+
t.Fatal(err.Error())
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
209
|
+
t.Fatal(err.Error())
|
|
210
|
+
}
|
|
211
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyvars", "b.gs.ts")
|
|
212
|
+
content, err := os.ReadFile(outputFile)
|
|
213
|
+
if err != nil {
|
|
214
|
+
t.Fatal(err.Error())
|
|
215
|
+
}
|
|
216
|
+
text := string(content)
|
|
217
|
+
for _, want := range []string{
|
|
218
|
+
"export let two: holder = undefined as unknown as holder",
|
|
219
|
+
"export function __goscript_get_two(): holder",
|
|
220
|
+
"export let remoteZero: __goscript_a.remote = undefined as unknown as __goscript_a.remote",
|
|
221
|
+
"export function __goscript_get_remoteZero(): __goscript_a.remote",
|
|
222
|
+
"__goscript_a.one",
|
|
223
|
+
} {
|
|
224
|
+
if !strings.Contains(text, want) {
|
|
225
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
aFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyvars", "a.gs.ts")
|
|
229
|
+
aContent, err := os.ReadFile(aFile)
|
|
230
|
+
if err != nil {
|
|
231
|
+
t.Fatal(err.Error())
|
|
232
|
+
}
|
|
233
|
+
if !strings.Contains(string(aContent), "__goscript_b.__goscript_get_two()") {
|
|
234
|
+
t.Fatalf("missing lazy cross-file getter use in a.go output:\n%s", string(aContent))
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
func TestCompilePackagesLazilyInitializesFunctionBodyPackageVarDependencies(t *testing.T) {
|
|
239
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
240
|
+
"go.mod": "module example.test/lazybodyvars\n\ngo 1.25.3\n",
|
|
241
|
+
"main.go": strings.Join([]string{
|
|
242
|
+
"package main",
|
|
243
|
+
"type Point struct { n int }",
|
|
244
|
+
"var first, _ = new(Point).SetBytes()",
|
|
245
|
+
"func (p *Point) SetBytes() (*Point, error) {",
|
|
246
|
+
" p.n = later",
|
|
247
|
+
" return p, nil",
|
|
248
|
+
"}",
|
|
249
|
+
"var later = 7",
|
|
250
|
+
"func main() { println(first.n) }",
|
|
251
|
+
"",
|
|
252
|
+
}, "\n"),
|
|
253
|
+
})
|
|
254
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
255
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
256
|
+
if err != nil {
|
|
257
|
+
t.Fatal(err.Error())
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
261
|
+
t.Fatal(err.Error())
|
|
262
|
+
}
|
|
263
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazybodyvars", "main.gs.ts")
|
|
264
|
+
content, err := os.ReadFile(outputFile)
|
|
265
|
+
if err != nil {
|
|
266
|
+
t.Fatal(err.Error())
|
|
267
|
+
}
|
|
268
|
+
text := string(content)
|
|
269
|
+
for _, want := range []string{
|
|
270
|
+
"export let first: Point | $.VarRef<Point> | null = undefined as unknown as Point | $.VarRef<Point> | null",
|
|
271
|
+
"export function __goscript_get_first(): Point | $.VarRef<Point> | null",
|
|
272
|
+
"function __goscript_get___goscriptTuple",
|
|
273
|
+
"export let later: number = 7",
|
|
274
|
+
} {
|
|
275
|
+
if !strings.Contains(text, want) {
|
|
276
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
func TestCompilePackagesEmitsShadowedBuiltinCalls(t *testing.T) {
|
|
282
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
283
|
+
"go.mod": "module example.test/shadowbuiltin\n\ngo 1.25.3\n",
|
|
284
|
+
"main.go": strings.Join([]string{
|
|
285
|
+
"package shadowbuiltin",
|
|
286
|
+
"type Value struct {",
|
|
287
|
+
" N int",
|
|
288
|
+
"}",
|
|
289
|
+
"func Build(new func() (*Value, error)) (*Value, error) {",
|
|
290
|
+
" return new()",
|
|
291
|
+
"}",
|
|
292
|
+
"",
|
|
293
|
+
}, "\n"),
|
|
294
|
+
})
|
|
295
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
296
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
297
|
+
if err != nil {
|
|
298
|
+
t.Fatal(err.Error())
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
302
|
+
t.Fatal(err.Error())
|
|
303
|
+
}
|
|
304
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "shadowbuiltin", "main.gs.ts")
|
|
305
|
+
content, err := os.ReadFile(outputFile)
|
|
306
|
+
if err != nil {
|
|
307
|
+
t.Fatal(err.Error())
|
|
308
|
+
}
|
|
309
|
+
text := string(content)
|
|
310
|
+
if !strings.Contains(text, "return await _new!()") {
|
|
311
|
+
t.Fatalf("shadowed builtin call was not emitted as a callable value:\n%s", text)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
func TestCompilePackagesQuotesRawStringLiterals(t *testing.T) {
|
|
316
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
317
|
+
"go.mod": "module example.test/rawstrings\n\ngo 1.25.3\n",
|
|
318
|
+
"main.go": strings.Join([]string{
|
|
319
|
+
"package rawstrings",
|
|
320
|
+
"func Values() (string, string) {",
|
|
321
|
+
" return `\\u00`, `invalid escape char after \\`",
|
|
322
|
+
"}",
|
|
323
|
+
"",
|
|
324
|
+
}, "\n"),
|
|
325
|
+
})
|
|
326
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
327
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
328
|
+
if err != nil {
|
|
329
|
+
t.Fatal(err.Error())
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
333
|
+
t.Fatal(err.Error())
|
|
334
|
+
}
|
|
335
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "rawstrings", "main.gs.ts")
|
|
336
|
+
content, err := os.ReadFile(outputFile)
|
|
337
|
+
if err != nil {
|
|
338
|
+
t.Fatal(err.Error())
|
|
339
|
+
}
|
|
340
|
+
text := string(content)
|
|
341
|
+
if !strings.Contains(text, `return ["\\u00", "invalid escape char after \\"]`) {
|
|
342
|
+
t.Fatalf("raw string literals were not quoted for TypeScript:\n%s", text)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
func TestCompilePackagesUsesEmbedOverride(t *testing.T) {
|
|
347
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
348
|
+
"go.mod": "module example.test/embedblank\n\ngo 1.25.3\n",
|
|
349
|
+
"version.txt": "1.2.3\n",
|
|
350
|
+
"version..txt": "4.5.6\n",
|
|
351
|
+
"binary.bin": string([]byte{0x00, 0xff, 0x80, 0x41}),
|
|
352
|
+
"main.go": strings.Join([]string{
|
|
353
|
+
"package embedblank",
|
|
354
|
+
"import _ \"embed\"",
|
|
355
|
+
"//go:embed version.txt",
|
|
356
|
+
"var Version string",
|
|
357
|
+
"//go:embed version..txt",
|
|
358
|
+
"var Dotted string",
|
|
359
|
+
"//go:embed binary.bin",
|
|
360
|
+
"var Binary []byte",
|
|
361
|
+
"func GetVersion() string {",
|
|
362
|
+
" return Version",
|
|
363
|
+
"}",
|
|
364
|
+
"",
|
|
365
|
+
}, "\n"),
|
|
366
|
+
})
|
|
367
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
368
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir, AllDependencies: true}, nil, nil)
|
|
369
|
+
if err != nil {
|
|
370
|
+
t.Fatal(err.Error())
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
374
|
+
if err != nil {
|
|
375
|
+
t.Fatal(err.Error())
|
|
376
|
+
}
|
|
377
|
+
if !slices.Contains(result.CopiedPackages, "embed") {
|
|
378
|
+
t.Fatalf("embed override was not copied: %#v", result.CopiedPackages)
|
|
379
|
+
}
|
|
380
|
+
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "index.ts")); err != nil {
|
|
381
|
+
t.Fatalf("embed override missing from output: %v", err)
|
|
382
|
+
}
|
|
383
|
+
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "embed.gs.ts")); !os.IsNotExist(err) {
|
|
384
|
+
t.Fatalf("stdlib embed was emitted instead of override: %v", err)
|
|
385
|
+
}
|
|
386
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "embedblank", "main.gs.ts"))
|
|
387
|
+
if err != nil {
|
|
388
|
+
t.Fatal(err.Error())
|
|
389
|
+
}
|
|
390
|
+
if !strings.Contains(string(content), "export let Version: string = \"1.2.3\\n\"") {
|
|
391
|
+
t.Fatalf("embedded string content was not emitted:\n%s", string(content))
|
|
392
|
+
}
|
|
393
|
+
if !strings.Contains(string(content), "export let Dotted: string = \"4.5.6\\n\"") {
|
|
394
|
+
t.Fatalf("embedded dotted filename content was not emitted:\n%s", string(content))
|
|
395
|
+
}
|
|
396
|
+
if !strings.Contains(string(content), "export let Binary: $.Slice<number> = new Uint8Array([0, 255, 128, 65])") {
|
|
397
|
+
t.Fatalf("embedded binary content was not emitted as byte values:\n%s", string(content))
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
func TestCompilePackagesEmitsPackageLocalImport(t *testing.T) {
|
|
402
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
403
|
+
"go.mod": "module example.test/imports\n\ngo 1.25.3\n",
|
|
404
|
+
"main.go": strings.Join([]string{
|
|
405
|
+
"package main",
|
|
406
|
+
"import \"example.test/imports/subpkg\"",
|
|
407
|
+
"func main() {",
|
|
408
|
+
" var b subpkg.Builder",
|
|
409
|
+
" b.Set(\"built\")",
|
|
410
|
+
" println(b.Value)",
|
|
411
|
+
" println(subpkg.Greet(\"world\"))",
|
|
412
|
+
" println(localMessage())",
|
|
413
|
+
"}",
|
|
414
|
+
"",
|
|
415
|
+
}, "\n"),
|
|
416
|
+
"helper.go": strings.Join([]string{
|
|
417
|
+
"package main",
|
|
418
|
+
"func localMessage() string {",
|
|
419
|
+
" return \"from helper\"",
|
|
420
|
+
"}",
|
|
421
|
+
"",
|
|
422
|
+
}, "\n"),
|
|
423
|
+
"subpkg/subpkg.go": strings.Join([]string{
|
|
424
|
+
"package subpkg",
|
|
425
|
+
"type Builder struct {",
|
|
426
|
+
" Value string",
|
|
427
|
+
"}",
|
|
428
|
+
"func (b *Builder) Set(value string) {",
|
|
429
|
+
" b.Value = value",
|
|
430
|
+
"}",
|
|
431
|
+
"func Greet(name string) string {",
|
|
432
|
+
" return \"Hello, \" + name",
|
|
433
|
+
"}",
|
|
434
|
+
"",
|
|
435
|
+
}, "\n"),
|
|
436
|
+
})
|
|
437
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
438
|
+
comp, err := NewCompiler(&Config{
|
|
439
|
+
Dir: moduleDir,
|
|
440
|
+
OutputPath: outputDir,
|
|
441
|
+
AllDependencies: true,
|
|
442
|
+
}, nil, nil)
|
|
443
|
+
if err != nil {
|
|
444
|
+
t.Fatal(err.Error())
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
448
|
+
if err != nil {
|
|
449
|
+
t.Fatal(err.Error())
|
|
450
|
+
}
|
|
451
|
+
if result == nil || len(result.CompiledPackages) != 2 {
|
|
452
|
+
t.Fatalf("unexpected result: %#v", result)
|
|
453
|
+
}
|
|
454
|
+
mainFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "main.gs.ts")
|
|
455
|
+
mainContent, err := os.ReadFile(mainFile)
|
|
456
|
+
if err != nil {
|
|
457
|
+
t.Fatal(err.Error())
|
|
458
|
+
}
|
|
459
|
+
if !strings.Contains(string(mainContent), "import * as subpkg from \"@goscript/example.test/imports/subpkg/index.js\"") {
|
|
460
|
+
t.Fatalf("missing package-local import:\n%s", string(mainContent))
|
|
461
|
+
}
|
|
462
|
+
if !strings.Contains(string(mainContent), "let b: $.VarRef<subpkg.Builder> = $.varRef($.markAsStructValue(new subpkg.Builder()))") {
|
|
463
|
+
t.Fatalf("missing imported struct zero value qualification:\n%s", string(mainContent))
|
|
464
|
+
}
|
|
465
|
+
if !strings.Contains(string(mainContent), "import * as __goscript_helper from \"./helper.gs.ts\"") ||
|
|
466
|
+
!strings.Contains(string(mainContent), "$.println(__goscript_helper.localMessage())") {
|
|
467
|
+
t.Fatalf("missing same-package helper import:\n%s", string(mainContent))
|
|
468
|
+
}
|
|
469
|
+
indexFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "subpkg", "index.ts")
|
|
470
|
+
indexContent, err := os.ReadFile(indexFile)
|
|
471
|
+
if err != nil {
|
|
472
|
+
t.Fatal(err.Error())
|
|
473
|
+
}
|
|
474
|
+
if string(indexContent) != "export { Builder, Greet } from \"./subpkg.gs.ts\"\n" {
|
|
475
|
+
t.Fatalf("unexpected subpkg index:\n%s", string(indexContent))
|
|
476
|
+
}
|
|
477
|
+
mainIndexFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "index.ts")
|
|
478
|
+
mainIndexContent, err := os.ReadFile(mainIndexFile)
|
|
479
|
+
if err != nil {
|
|
480
|
+
t.Fatal(err.Error())
|
|
481
|
+
}
|
|
482
|
+
if strings.Contains(string(mainIndexContent), "localMessage") {
|
|
483
|
+
t.Fatalf("unexported helper leaked into package index:\n%s", string(mainIndexContent))
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
func TestCompilePackagesEmitsIndexAddressRefs(t *testing.T) {
|
|
488
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
489
|
+
"go.mod": "module example.test/indexaddr\n\ngo 1.25.3\n",
|
|
490
|
+
"main.go": strings.Join([]string{
|
|
491
|
+
"package main",
|
|
492
|
+
"type Item struct { N int }",
|
|
493
|
+
"func set(ptr *int, value int) {",
|
|
494
|
+
" *ptr = value",
|
|
495
|
+
"}",
|
|
496
|
+
"func Use(values []int, i int) int {",
|
|
497
|
+
" set(&values[i], 9)",
|
|
498
|
+
" return values[i]",
|
|
499
|
+
"}",
|
|
500
|
+
"func Items() []*Item {",
|
|
501
|
+
" return []*Item{{N: 1}}",
|
|
502
|
+
"}",
|
|
503
|
+
"",
|
|
504
|
+
}, "\n"),
|
|
505
|
+
})
|
|
506
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
507
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
508
|
+
if err != nil {
|
|
509
|
+
t.Fatal(err.Error())
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
_, err = comp.CompilePackages(context.Background(), ".")
|
|
513
|
+
if err != nil {
|
|
514
|
+
t.Fatal(err.Error())
|
|
515
|
+
}
|
|
516
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "indexaddr", "main.gs.ts")
|
|
517
|
+
content, err := os.ReadFile(outputFile)
|
|
518
|
+
if err != nil {
|
|
519
|
+
t.Fatal(err.Error())
|
|
520
|
+
}
|
|
521
|
+
text := string(content)
|
|
522
|
+
if !strings.Contains(text, "set($.indexRef(values!, i), 9)") {
|
|
523
|
+
t.Fatalf("missing index address reference:\n%s", text)
|
|
524
|
+
}
|
|
525
|
+
if !strings.Contains(text, "new Item({N: 1})") {
|
|
526
|
+
t.Fatalf("missing elided pointer composite literal:\n%s", text)
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
531
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
532
|
+
"go.mod": "module example.test/structs\n\ngo 1.25.3\n",
|
|
533
|
+
"main.go": strings.Join([]string{
|
|
534
|
+
"package main",
|
|
535
|
+
"type Counter struct {",
|
|
536
|
+
" // Value counts reads.",
|
|
537
|
+
" Value int `json:\"value\"`",
|
|
538
|
+
"}",
|
|
539
|
+
"func (c Counter) Read() int {",
|
|
540
|
+
" return c.Value",
|
|
541
|
+
"}",
|
|
542
|
+
"func (c *Counter) Set(v int) {",
|
|
543
|
+
" c.Value = v",
|
|
544
|
+
"}",
|
|
545
|
+
"func NewCounter() *Counter {",
|
|
546
|
+
" return &Counter{Value: 3}",
|
|
547
|
+
"}",
|
|
548
|
+
"func main() {",
|
|
549
|
+
" original := Counter{Value: 1}",
|
|
550
|
+
"",
|
|
551
|
+
" // Copy should stay readable in generated output.",
|
|
552
|
+
" copy := original",
|
|
553
|
+
" pointer := &original",
|
|
554
|
+
" pointer.Set(2)",
|
|
555
|
+
" NewCounter().Set(5)",
|
|
556
|
+
" var iface any = pointer",
|
|
557
|
+
" _, ok := iface.(*Counter)",
|
|
558
|
+
" println(copy.Read(), original.Read(), ok)",
|
|
559
|
+
"}",
|
|
560
|
+
"",
|
|
561
|
+
}, "\n"),
|
|
562
|
+
})
|
|
563
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
564
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
565
|
+
if err != nil {
|
|
566
|
+
t.Fatal(err.Error())
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
570
|
+
t.Fatal(err.Error())
|
|
571
|
+
}
|
|
572
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "structs", "main.gs.ts")
|
|
573
|
+
content, err := os.ReadFile(outputFile)
|
|
574
|
+
if err != nil {
|
|
575
|
+
t.Fatal(err.Error())
|
|
576
|
+
}
|
|
577
|
+
text := string(content)
|
|
578
|
+
for _, want := range []string{
|
|
579
|
+
"export class Counter",
|
|
580
|
+
"// Value counts reads.\n\tpublic get Value(): number",
|
|
581
|
+
"public clone(): Counter",
|
|
582
|
+
"public Read(): number",
|
|
583
|
+
"public Set(v: number): void",
|
|
584
|
+
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))",
|
|
585
|
+
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))\n\n\t// Copy should stay readable in generated output.\n\tlet copy",
|
|
586
|
+
"let copy = $.markAsStructValue($.cloneStructValue(original.value))",
|
|
587
|
+
"let pointer: Counter | $.VarRef<Counter> | null = original",
|
|
588
|
+
"$.pointerValue<Counter>(pointer).Set(2)",
|
|
589
|
+
"$.pointerValue<Counter>(NewCounter()).Set(5)",
|
|
590
|
+
"let [, ok] = $.typeAssertTuple<Counter | $.VarRef<Counter> | null>(iface, { kind: $.TypeKind.Pointer, elemType: \"main.Counter\" })",
|
|
591
|
+
"\"Value\": { type: { kind: $.TypeKind.Basic, name: \"int\" }, tag: \"json:\\\"value\\\"\" }",
|
|
592
|
+
} {
|
|
593
|
+
if !strings.Contains(text, want) {
|
|
594
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
600
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
601
|
+
"go.mod": "module example.test/pointers\n\ngo 1.25.3\n",
|
|
602
|
+
"main.go": strings.Join([]string{
|
|
603
|
+
"package main",
|
|
604
|
+
"func main() {",
|
|
605
|
+
" var x int = 10",
|
|
606
|
+
" p1 := &x",
|
|
607
|
+
" p2 := &p1",
|
|
608
|
+
" p3 := &p2",
|
|
609
|
+
" ***p3 = 12",
|
|
610
|
+
" println(x)",
|
|
611
|
+
"}",
|
|
612
|
+
"",
|
|
613
|
+
}, "\n"),
|
|
614
|
+
})
|
|
615
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
616
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
617
|
+
if err != nil {
|
|
618
|
+
t.Fatal(err.Error())
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
622
|
+
t.Fatal(err.Error())
|
|
623
|
+
}
|
|
624
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "pointers", "main.gs.ts")
|
|
625
|
+
content, err := os.ReadFile(outputFile)
|
|
626
|
+
if err != nil {
|
|
627
|
+
t.Fatal(err.Error())
|
|
628
|
+
}
|
|
629
|
+
text := string(content)
|
|
630
|
+
for _, want := range []string{
|
|
631
|
+
"let x: $.VarRef<number> = $.varRef(10)",
|
|
632
|
+
"let p1 = $.varRef(x)",
|
|
633
|
+
"let p2 = $.varRef(p1)",
|
|
634
|
+
"let p3 = p2",
|
|
635
|
+
"$.pointerValue<$.VarRef<number> | null>($.pointerValue<$.VarRef<$.VarRef<number> | null> | null>(p3))!.value = 12",
|
|
636
|
+
} {
|
|
637
|
+
if !strings.Contains(text, want) {
|
|
638
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
644
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
645
|
+
"go.mod": "module example.test/collections\n\ngo 1.25.3\n",
|
|
646
|
+
"main.go": strings.Join([]string{
|
|
647
|
+
"package main",
|
|
648
|
+
"type MyInt int",
|
|
649
|
+
"func (m MyInt) Double() int { return int(m) * 2 }",
|
|
650
|
+
"type MySlice []int",
|
|
651
|
+
"func (s *MySlice) Add(v int) { *s = append(*s, v) }",
|
|
652
|
+
"func main() {",
|
|
653
|
+
" arr := [3]int{1: 10}",
|
|
654
|
+
" slice := make([]int, 0, 2)",
|
|
655
|
+
" empty := []rune{}",
|
|
656
|
+
" literal := []int{1, 2}",
|
|
657
|
+
" literal = append(literal, 3)",
|
|
658
|
+
" slice = append(slice, 5)",
|
|
659
|
+
" slice[0] = arr[1]",
|
|
660
|
+
" m := make(map[string]int)",
|
|
661
|
+
" m[\"one\"] = 1",
|
|
662
|
+
" value, ok := m[\"missing\"]",
|
|
663
|
+
" text := \"hé\"",
|
|
664
|
+
" var list MySlice",
|
|
665
|
+
" list.Add(7)",
|
|
666
|
+
" println(arr[1], slice[0], literal[2], len(slice), cap(slice), len(empty), value, ok, text[0], text[1], MyInt(5).Double(), len(list))",
|
|
667
|
+
"}",
|
|
668
|
+
"",
|
|
669
|
+
}, "\n"),
|
|
670
|
+
})
|
|
671
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
672
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
673
|
+
if err != nil {
|
|
674
|
+
t.Fatal(err.Error())
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
678
|
+
t.Fatal(err.Error())
|
|
679
|
+
}
|
|
680
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "collections", "main.gs.ts")
|
|
681
|
+
content, err := os.ReadFile(outputFile)
|
|
682
|
+
if err != nil {
|
|
683
|
+
t.Fatal(err.Error())
|
|
684
|
+
}
|
|
685
|
+
text := string(content)
|
|
686
|
+
for _, want := range []string{
|
|
687
|
+
"export type MyInt = number",
|
|
688
|
+
"export function MyInt_Double(m: MyInt): number",
|
|
689
|
+
"export type MySlice = $.Slice<number>",
|
|
690
|
+
"export function MySlice_Add(s: $.VarRef<MySlice> | null, v: number): void",
|
|
691
|
+
"let arr = [0, 10, 0]",
|
|
692
|
+
"let slice = $.makeSlice<number>(0, 2, \"number\")",
|
|
693
|
+
"let empty = $.arrayToSlice<number>([])",
|
|
694
|
+
"let literal = $.arrayToSlice<number>([1, 2])",
|
|
695
|
+
"literal = $.append(literal, 3)",
|
|
696
|
+
"slice![0] = arr[1]",
|
|
697
|
+
"let m: Map<string, number> | null = $.makeMap<string, number>()",
|
|
698
|
+
"$.mapSet(m, \"one\", 1)",
|
|
699
|
+
"let [value, ok] = $.mapGet(m, \"missing\", 0)",
|
|
700
|
+
"slice![0]",
|
|
701
|
+
"literal![2]",
|
|
702
|
+
"let list: $.VarRef<MySlice> = $.varRef(null as MySlice)",
|
|
703
|
+
"MySlice_Add(list, 7)",
|
|
704
|
+
"$.indexStringOrBytes(text, 0)",
|
|
705
|
+
"MyInt_Double(5)",
|
|
706
|
+
} {
|
|
707
|
+
if !strings.Contains(text, want) {
|
|
708
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssertions(t *testing.T) {
|
|
714
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
715
|
+
"go.mod": "module example.test/interfaces\n\ngo 1.25.3\n",
|
|
716
|
+
"main.go": strings.Join([]string{
|
|
717
|
+
"package main",
|
|
718
|
+
"type Greeter func(name string) string",
|
|
719
|
+
"func greet(name string) string { return \"hello \" + name }",
|
|
720
|
+
"type Reader interface { Read() string }",
|
|
721
|
+
"type Closer interface { Close() string }",
|
|
722
|
+
"type ReadCloser interface { Reader; Closer }",
|
|
723
|
+
"type Counter struct { Value int }",
|
|
724
|
+
"func (c *Counter) Inc() { c.Value++ }",
|
|
725
|
+
"func (c Counter) Read() string { return \"read\" }",
|
|
726
|
+
"func (c Counter) Close() string { return \"close\" }",
|
|
727
|
+
"func call(fn func()) { fn() }",
|
|
728
|
+
"func main() {",
|
|
729
|
+
" counter := &Counter{}",
|
|
730
|
+
" call(counter.Inc)",
|
|
731
|
+
" var rc ReadCloser = counter",
|
|
732
|
+
" _, ok := rc.(ReadCloser)",
|
|
733
|
+
" var i any = Greeter(greet)",
|
|
734
|
+
" fn, ok := i.(Greeter)",
|
|
735
|
+
" var l any = (*struct { Name string })(nil)",
|
|
736
|
+
" _, ok2 := l.(*struct { Name string })",
|
|
737
|
+
" switch v := rc.(type) {",
|
|
738
|
+
" case ReadCloser:",
|
|
739
|
+
" println(v.Read(), fn(\"gopher\"), ok, ok2)",
|
|
740
|
+
" }",
|
|
741
|
+
"}",
|
|
742
|
+
"",
|
|
743
|
+
}, "\n"),
|
|
744
|
+
})
|
|
745
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
746
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
747
|
+
if err != nil {
|
|
748
|
+
t.Fatal(err.Error())
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
752
|
+
t.Fatal(err.Error())
|
|
753
|
+
}
|
|
754
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interfaces", "main.gs.ts")
|
|
755
|
+
content, err := os.ReadFile(outputFile)
|
|
756
|
+
if err != nil {
|
|
757
|
+
t.Fatal(err.Error())
|
|
758
|
+
}
|
|
759
|
+
text := string(content)
|
|
760
|
+
for _, want := range []string{
|
|
761
|
+
"export type Greeter = ((name: string) => string | globalThis.Promise<string>) | null",
|
|
762
|
+
"export type ReadCloser = null | {",
|
|
763
|
+
"Read(): string",
|
|
764
|
+
"Close(): string",
|
|
765
|
+
"$.registerInterfaceType(\n\t\"main.ReadCloser\"",
|
|
766
|
+
"((__receiver) => () => __receiver.Inc())($.pointerValue<Counter>(counter))",
|
|
767
|
+
"$.namedFunction(greet, \"main.Greeter\")",
|
|
768
|
+
"$.typedNil(\"*struct{Name string}\")",
|
|
769
|
+
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: {\"Name\": { kind: $.TypeKind.Basic, name: \"string\" }} }",
|
|
770
|
+
"let fn = __goscriptTuple",
|
|
771
|
+
"switch (true)",
|
|
772
|
+
"case $.typeAssert<ReadCloser | null>(__goscriptTypeSwitchValue, \"main.ReadCloser\").ok",
|
|
773
|
+
"let v: ReadCloser | null = $.typeAssert<ReadCloser | null>(__goscriptTypeSwitchValue, \"main.ReadCloser\").value",
|
|
774
|
+
} {
|
|
775
|
+
if !strings.Contains(text, want) {
|
|
776
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
|
|
782
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
783
|
+
"go.mod": "module example.test/interface-receivers\n\ngo 1.25.3\n",
|
|
784
|
+
"main.go": strings.Join([]string{
|
|
785
|
+
"package main",
|
|
786
|
+
"type FileInfo interface { Name() string }",
|
|
787
|
+
"type fileInfo struct { name string }",
|
|
788
|
+
"func (f fileInfo) Name() string { return f.name }",
|
|
789
|
+
"func stat() (FileInfo, error) { return fileInfo{name: \"demo\"}, nil }",
|
|
790
|
+
"func main() {",
|
|
791
|
+
" info, err := stat()",
|
|
792
|
+
" if err == nil {",
|
|
793
|
+
" println(info.Name())",
|
|
794
|
+
" }",
|
|
795
|
+
"}",
|
|
796
|
+
"",
|
|
797
|
+
}, "\n"),
|
|
798
|
+
})
|
|
799
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
800
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
801
|
+
if err != nil {
|
|
802
|
+
t.Fatal(err.Error())
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
806
|
+
t.Fatal(err.Error())
|
|
807
|
+
}
|
|
808
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interface-receivers", "main.gs.ts")
|
|
809
|
+
content, err := os.ReadFile(outputFile)
|
|
810
|
+
if err != nil {
|
|
811
|
+
t.Fatal(err.Error())
|
|
812
|
+
}
|
|
813
|
+
text := string(content)
|
|
814
|
+
for _, want := range []string{
|
|
815
|
+
"export type FileInfo = null | {",
|
|
816
|
+
"$.println($.pointerValue<Exclude<FileInfo, null>>(info).Name())",
|
|
817
|
+
} {
|
|
818
|
+
if !strings.Contains(text, want) {
|
|
819
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
|
|
825
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
826
|
+
"go.mod": "module example.test/typed-nil-interface\n\ngo 1.25.3\n",
|
|
827
|
+
"main.go": strings.Join([]string{
|
|
828
|
+
"package main",
|
|
829
|
+
"type Animal interface { Name() string }",
|
|
830
|
+
"type Dog struct { name string }",
|
|
831
|
+
"func (d *Dog) Name() string {",
|
|
832
|
+
" if d == nil {",
|
|
833
|
+
" return \"unknown dog\"",
|
|
834
|
+
" }",
|
|
835
|
+
" return d.name",
|
|
836
|
+
"}",
|
|
837
|
+
"func FindDog() *Dog { return nil }",
|
|
838
|
+
"func FindAnimal() Animal { return Animal(FindDog()) }",
|
|
839
|
+
"func main() {",
|
|
840
|
+
" animal := FindAnimal()",
|
|
841
|
+
" println(animal.Name())",
|
|
842
|
+
" var dog *Dog = nil",
|
|
843
|
+
" var a Animal = dog",
|
|
844
|
+
" println(a == nil)",
|
|
845
|
+
"}",
|
|
846
|
+
"",
|
|
847
|
+
}, "\n"),
|
|
848
|
+
})
|
|
849
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
850
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
851
|
+
if err != nil {
|
|
852
|
+
t.Fatal(err.Error())
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
856
|
+
t.Fatal(err.Error())
|
|
857
|
+
}
|
|
858
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "typed-nil-interface", "main.gs.ts")
|
|
859
|
+
content, err := os.ReadFile(outputFile)
|
|
860
|
+
if err != nil {
|
|
861
|
+
t.Fatal(err.Error())
|
|
862
|
+
}
|
|
863
|
+
text := string(content)
|
|
864
|
+
for _, want := range []string{
|
|
865
|
+
"return $.interfaceValue<Animal | null>(FindDog(), \"*main.Dog\")",
|
|
866
|
+
"$.println($.pointerValue<Exclude<Animal, null>>(animal).Name())",
|
|
867
|
+
"let a: Animal | null = $.interfaceValue<Animal | null>(dog, \"*main.Dog\")",
|
|
868
|
+
} {
|
|
869
|
+
if !strings.Contains(text, want) {
|
|
870
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T) {
|
|
876
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
877
|
+
"go.mod": "module example.test/generics\n\ngo 1.25.3\n",
|
|
878
|
+
"main.go": strings.Join([]string{
|
|
879
|
+
"package main",
|
|
880
|
+
"type Stringer interface { String() string }",
|
|
881
|
+
"type MyInt int",
|
|
882
|
+
"func (m MyInt) String() string { return \"int\" }",
|
|
883
|
+
"type Box[T any] struct { value T }",
|
|
884
|
+
"func (b Box[T]) Get() T { return b.value }",
|
|
885
|
+
"func NewBox[T any](value T) Box[T] { return Box[T]{value: value} }",
|
|
886
|
+
"type Set[T comparable] map[T]struct{}",
|
|
887
|
+
"func ZeroValue[T Stringer]() T {",
|
|
888
|
+
" var zero T",
|
|
889
|
+
" return zero",
|
|
890
|
+
"}",
|
|
891
|
+
"func CallString[T Stringer](v T) string { return v.String() }",
|
|
892
|
+
"func Sum[T Stringer](vals ...T) T {",
|
|
893
|
+
" var zero T",
|
|
894
|
+
" return zero",
|
|
895
|
+
"}",
|
|
896
|
+
"func main() {",
|
|
897
|
+
" box := NewBox(7)",
|
|
898
|
+
" println(box.Get())",
|
|
899
|
+
" seen := make(Set[int])",
|
|
900
|
+
" seen[1] = struct{}{}",
|
|
901
|
+
" zero := ZeroValue[MyInt]()",
|
|
902
|
+
" println(CallString(zero))",
|
|
903
|
+
" sum := Sum[MyInt]()",
|
|
904
|
+
" println(CallString(sum))",
|
|
905
|
+
"}",
|
|
906
|
+
"",
|
|
907
|
+
}, "\n"),
|
|
908
|
+
})
|
|
909
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
910
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
911
|
+
if err != nil {
|
|
912
|
+
t.Fatal(err.Error())
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
916
|
+
t.Fatal(err.Error())
|
|
917
|
+
}
|
|
918
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "generics", "main.gs.ts")
|
|
919
|
+
content, err := os.ReadFile(outputFile)
|
|
920
|
+
if err != nil {
|
|
921
|
+
t.Fatal(err.Error())
|
|
922
|
+
}
|
|
923
|
+
text := string(content)
|
|
924
|
+
for _, want := range []string{
|
|
925
|
+
"public Get(): any",
|
|
926
|
+
"export function NewBox(__typeArgs: $.GenericTypeArgs | undefined, value: any): Box",
|
|
927
|
+
"let seen: Set = $.makeMap<number, {}>()",
|
|
928
|
+
"$.mapSet(seen, 1, {})",
|
|
929
|
+
"$.genericZero(__typeArgs, \"T\", null)",
|
|
930
|
+
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
931
|
+
"ZeroValue({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }})",
|
|
932
|
+
"CallString({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, zero)",
|
|
933
|
+
"Sum({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, null)",
|
|
934
|
+
} {
|
|
935
|
+
if !strings.Contains(text, want) {
|
|
936
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
func TestCompilePackagesAttachesFunctionLiteralTypeInfo(t *testing.T) {
|
|
942
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
943
|
+
"go.mod": "module example.test/function-type-info\n\ngo 1.25.3\n",
|
|
944
|
+
"main.go": strings.Join([]string{
|
|
945
|
+
"package main",
|
|
946
|
+
"type Callback func(value int) string",
|
|
947
|
+
"func call(cb Callback) string {",
|
|
948
|
+
" return cb(1)",
|
|
949
|
+
"}",
|
|
950
|
+
"func main() {",
|
|
951
|
+
" fn := func(value int) string {",
|
|
952
|
+
" return \"\"",
|
|
953
|
+
" }",
|
|
954
|
+
" var cb Callback = nil",
|
|
955
|
+
" _ = fn",
|
|
956
|
+
" _ = cb",
|
|
957
|
+
" _ = call(fn)",
|
|
958
|
+
"}",
|
|
959
|
+
"",
|
|
960
|
+
}, "\n"),
|
|
961
|
+
})
|
|
962
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
963
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
964
|
+
if err != nil {
|
|
965
|
+
t.Fatal(err.Error())
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
969
|
+
t.Fatal(err.Error())
|
|
970
|
+
}
|
|
971
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "function-type-info", "main.gs.ts")
|
|
972
|
+
content, err := os.ReadFile(outputFile)
|
|
973
|
+
if err != nil {
|
|
974
|
+
t.Fatal(err.Error())
|
|
975
|
+
}
|
|
976
|
+
text := string(content)
|
|
977
|
+
for _, want := range []string{
|
|
978
|
+
"export type Callback = ((value: number) => string | globalThis.Promise<string>) | null",
|
|
979
|
+
"export async function call(cb: ((value: number) => string | globalThis.Promise<string>) | null): globalThis.Promise<string> {\n\treturn await cb!(1)",
|
|
980
|
+
"$.functionValue((value: number): string => {",
|
|
981
|
+
"kind: $.TypeKind.Function",
|
|
982
|
+
"params: [{ kind: $.TypeKind.Basic, name: \"int\" }]",
|
|
983
|
+
"results: [{ kind: $.TypeKind.Basic, name: \"string\" }]",
|
|
984
|
+
} {
|
|
985
|
+
if !strings.Contains(text, want) {
|
|
986
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
func TestCompilePackagesEmitsRecursiveFunctionTypeInfo(t *testing.T) {
|
|
992
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
993
|
+
"go.mod": "module example.test/recursive-function-type\n\ngo 1.25.3\n",
|
|
994
|
+
"main.go": strings.Join([]string{
|
|
995
|
+
"package main",
|
|
996
|
+
"type Handler func(Handler) Handler",
|
|
997
|
+
"type Holder struct { Next Handler }",
|
|
998
|
+
"func main() { _ = Holder{} }",
|
|
999
|
+
"",
|
|
1000
|
+
}, "\n"),
|
|
1001
|
+
})
|
|
1002
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1003
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1004
|
+
if err != nil {
|
|
1005
|
+
t.Fatal(err.Error())
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1009
|
+
t.Fatal(err.Error())
|
|
1010
|
+
}
|
|
1011
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "recursive-function-type", "main.gs.ts")
|
|
1012
|
+
content, err := os.ReadFile(outputFile)
|
|
1013
|
+
if err != nil {
|
|
1014
|
+
t.Fatal(err.Error())
|
|
1015
|
+
}
|
|
1016
|
+
text := string(content)
|
|
1017
|
+
for _, want := range []string{
|
|
1018
|
+
"export type Handler = ((_p0: ((_p0: Handler) => Handler | globalThis.Promise<Handler>) | null) => Handler | globalThis.Promise<Handler>) | null",
|
|
1019
|
+
"\"Next\": { kind: $.TypeKind.Function, name: \"main.Handler\"",
|
|
1020
|
+
"params: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
1021
|
+
"results: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
1022
|
+
} {
|
|
1023
|
+
if !strings.Contains(text, want) {
|
|
1024
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
func TestCompilePackagesPacksVariadicCalls(t *testing.T) {
|
|
1030
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1031
|
+
"go.mod": "module example.test/variadic\n\ngo 1.25.3\n",
|
|
1032
|
+
"main.go": strings.Join([]string{
|
|
1033
|
+
"package main",
|
|
1034
|
+
"type Collector func(label string, parts ...string) string",
|
|
1035
|
+
"type Joiner interface {",
|
|
1036
|
+
" Join(parts ...string) string",
|
|
1037
|
+
"}",
|
|
1038
|
+
"type Path struct{}",
|
|
1039
|
+
"func collect(label string, parts ...string) string {",
|
|
1040
|
+
" for _, part := range parts {",
|
|
1041
|
+
" if part == \"\" {",
|
|
1042
|
+
" return label",
|
|
1043
|
+
" }",
|
|
1044
|
+
" }",
|
|
1045
|
+
" return label + string(rune(len(parts)+'0'))",
|
|
1046
|
+
"}",
|
|
1047
|
+
"func maybeErr(parts ...string) error { return nil }",
|
|
1048
|
+
"func (Path) Join(parts ...string) string {",
|
|
1049
|
+
" return collect(\"method\", parts...)",
|
|
1050
|
+
"}",
|
|
1051
|
+
"func main() {",
|
|
1052
|
+
" parts := []string{\"a\", \"b\"}",
|
|
1053
|
+
" collect(\"none\")",
|
|
1054
|
+
" collect(\"two\", \"a\", \"b\")",
|
|
1055
|
+
" collect(\"spread\", parts...)",
|
|
1056
|
+
" parts = append(parts, \"c\", \"d\")",
|
|
1057
|
+
" maybeErr(\"ok\")",
|
|
1058
|
+
" var fn Collector = collect",
|
|
1059
|
+
" fn(\"fn\", \"x\")",
|
|
1060
|
+
" var joiner Joiner = Path{}",
|
|
1061
|
+
" joiner.Join(\"q\", \"r\")",
|
|
1062
|
+
"}",
|
|
1063
|
+
"",
|
|
1064
|
+
}, "\n"),
|
|
1065
|
+
})
|
|
1066
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1067
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1068
|
+
if err != nil {
|
|
1069
|
+
t.Fatal(err.Error())
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1073
|
+
t.Fatal(err.Error())
|
|
1074
|
+
}
|
|
1075
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "variadic", "main.gs.ts")
|
|
1076
|
+
content, err := os.ReadFile(outputFile)
|
|
1077
|
+
if err != nil {
|
|
1078
|
+
t.Fatal(err.Error())
|
|
1079
|
+
}
|
|
1080
|
+
text := string(content)
|
|
1081
|
+
for _, want := range []string{
|
|
1082
|
+
"export type Collector = ((label: string, parts: $.Slice<string>) => string | globalThis.Promise<string>) | null",
|
|
1083
|
+
"Join(parts: $.Slice<string>): string",
|
|
1084
|
+
"export function collect(label: string, parts: $.Slice<string>): string",
|
|
1085
|
+
"let part = parts![__rangeIndex]",
|
|
1086
|
+
"export function maybeErr(parts: $.Slice<string>): $.GoError",
|
|
1087
|
+
"public Join(parts: $.Slice<string>): string",
|
|
1088
|
+
"collect(\"none\", null)",
|
|
1089
|
+
"collect(\"two\", $.arrayToSlice<string>([\"a\", \"b\"]))",
|
|
1090
|
+
"collect(\"spread\", parts)",
|
|
1091
|
+
"$.append(parts, \"c\", \"d\")",
|
|
1092
|
+
"maybeErr($.arrayToSlice<string>([\"ok\"]))",
|
|
1093
|
+
"fn!(\"fn\", $.arrayToSlice<string>([\"x\"]))",
|
|
1094
|
+
"$.pointerValue<Exclude<Joiner, null>>(joiner).Join($.arrayToSlice<string>([\"q\", \"r\"]))",
|
|
1095
|
+
} {
|
|
1096
|
+
if !strings.Contains(text, want) {
|
|
1097
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
func TestCompilePackagesPacksVariadicCallsInGeneratedSubpackage(t *testing.T) {
|
|
1103
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1104
|
+
"go.mod": "module example.test/variadic-subpackage\n\ngo 1.25.3\n",
|
|
1105
|
+
"json/json.go": strings.Join([]string{
|
|
1106
|
+
"package json",
|
|
1107
|
+
"import \"fmt\"",
|
|
1108
|
+
"type State struct { err error }",
|
|
1109
|
+
"func (s *State) SetErrorf(format string, a ...any) {",
|
|
1110
|
+
" s.err = fmt.Errorf(format, a...)",
|
|
1111
|
+
"}",
|
|
1112
|
+
"func (s *State) Read(key string) {",
|
|
1113
|
+
" s.SetErrorf(\"bad %q\", key)",
|
|
1114
|
+
"}",
|
|
1115
|
+
"",
|
|
1116
|
+
}, "\n"),
|
|
1117
|
+
})
|
|
1118
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1119
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1120
|
+
if err != nil {
|
|
1121
|
+
t.Fatal(err.Error())
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if _, err := comp.CompilePackages(context.Background(), "./json"); err != nil {
|
|
1125
|
+
t.Fatal(err.Error())
|
|
1126
|
+
}
|
|
1127
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "variadic-subpackage", "json", "json.gs.ts")
|
|
1128
|
+
content, err := os.ReadFile(outputFile)
|
|
1129
|
+
if err != nil {
|
|
1130
|
+
t.Fatal(err.Error())
|
|
1131
|
+
}
|
|
1132
|
+
text := string(content)
|
|
1133
|
+
want := "$.pointerValue<State>(s).SetErrorf(\"bad %q\", $.arrayToSlice<any>([key]))"
|
|
1134
|
+
if !strings.Contains(text, want) {
|
|
1135
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1136
|
+
}
|
|
1137
|
+
if strings.Contains(text, "$.pointerValue<State>(s).SetErrorf(\"bad %q\", key)") {
|
|
1138
|
+
t.Fatalf("generated override subpackage call was not packed:\n%s", text)
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
1143
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1144
|
+
"go.mod": "module example.test/iterators\n\ngo 1.25.3\n",
|
|
1145
|
+
"main.go": strings.Join([]string{
|
|
1146
|
+
"package main",
|
|
1147
|
+
"func pairs(yield func(int, string) bool) {",
|
|
1148
|
+
" values := []string{\"a\", \"b\"}",
|
|
1149
|
+
" for i, v := range values {",
|
|
1150
|
+
" if !yield(i, v) {",
|
|
1151
|
+
" break",
|
|
1152
|
+
" }",
|
|
1153
|
+
" }",
|
|
1154
|
+
"}",
|
|
1155
|
+
"func main() {",
|
|
1156
|
+
" for i, v := range pairs {",
|
|
1157
|
+
" println(i, v)",
|
|
1158
|
+
" }",
|
|
1159
|
+
" var last int",
|
|
1160
|
+
" for last = range pairs {",
|
|
1161
|
+
" println(last)",
|
|
1162
|
+
" }",
|
|
1163
|
+
" for i := range 3 {",
|
|
1164
|
+
" if i == 1 {",
|
|
1165
|
+
" continue",
|
|
1166
|
+
" }",
|
|
1167
|
+
" println(i)",
|
|
1168
|
+
" }",
|
|
1169
|
+
" ch := make(chan int, 1)",
|
|
1170
|
+
" for _, outer := range backward([]int{1, 2}) {",
|
|
1171
|
+
" for range backward([]int{3}) {",
|
|
1172
|
+
" ch <- outer",
|
|
1173
|
+
" }",
|
|
1174
|
+
" }",
|
|
1175
|
+
"}",
|
|
1176
|
+
"func backward(values []int) func(func(int, int) bool) {",
|
|
1177
|
+
" return func(yield func(int, int) bool) {",
|
|
1178
|
+
" for i := len(values) - 1; i >= 0; i-- {",
|
|
1179
|
+
" if !yield(i, values[i]) {",
|
|
1180
|
+
" return",
|
|
1181
|
+
" }",
|
|
1182
|
+
" }",
|
|
1183
|
+
" }",
|
|
1184
|
+
"}",
|
|
1185
|
+
"",
|
|
1186
|
+
}, "\n"),
|
|
1187
|
+
})
|
|
1188
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1189
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1190
|
+
if err != nil {
|
|
1191
|
+
t.Fatal(err.Error())
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1195
|
+
t.Fatal(err.Error())
|
|
1196
|
+
}
|
|
1197
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "iterators", "main.gs.ts")
|
|
1198
|
+
content, err := os.ReadFile(outputFile)
|
|
1199
|
+
if err != nil {
|
|
1200
|
+
t.Fatal(err.Error())
|
|
1201
|
+
}
|
|
1202
|
+
text := string(content)
|
|
1203
|
+
for _, want := range []string{
|
|
1204
|
+
"if (!await _yield!(i, v))",
|
|
1205
|
+
"break",
|
|
1206
|
+
"await pairs!(async (i, v) => {",
|
|
1207
|
+
"last = __goscriptRange",
|
|
1208
|
+
"return true",
|
|
1209
|
+
"continue",
|
|
1210
|
+
"await backward($.arrayToSlice<number>([1, 2]))!(async (__goscriptRange",
|
|
1211
|
+
"await backward($.arrayToSlice<number>([3]))!(async (__goscriptRange",
|
|
1212
|
+
} {
|
|
1213
|
+
if !strings.Contains(text, want) {
|
|
1214
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
func TestCompilePackagesLowersFunctionIteratorControlFlow(t *testing.T) {
|
|
1220
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1221
|
+
"go.mod": "module example.test/iterator-control\n\ngo 1.25.3\n",
|
|
1222
|
+
"main.go": strings.Join([]string{
|
|
1223
|
+
"package main",
|
|
1224
|
+
"func values(yield func(int) bool) {",
|
|
1225
|
+
" for i := range 4 {",
|
|
1226
|
+
" if !yield(i) {",
|
|
1227
|
+
" return",
|
|
1228
|
+
" }",
|
|
1229
|
+
" }",
|
|
1230
|
+
"}",
|
|
1231
|
+
"func first(limit int) int {",
|
|
1232
|
+
" j := 3",
|
|
1233
|
+
" for i := 0; i < j; i, j = i+1, j-1 {",
|
|
1234
|
+
" println(i, j)",
|
|
1235
|
+
" }",
|
|
1236
|
+
" for v := range values {",
|
|
1237
|
+
" if v == 0 {",
|
|
1238
|
+
" continue",
|
|
1239
|
+
" }",
|
|
1240
|
+
" for i := range 2 {",
|
|
1241
|
+
" if i == 1 {",
|
|
1242
|
+
" break",
|
|
1243
|
+
" }",
|
|
1244
|
+
" }",
|
|
1245
|
+
" if v == limit {",
|
|
1246
|
+
" break",
|
|
1247
|
+
" }",
|
|
1248
|
+
" switch v {",
|
|
1249
|
+
" case 2:",
|
|
1250
|
+
" return v",
|
|
1251
|
+
" }",
|
|
1252
|
+
" switch any(v).(type) {",
|
|
1253
|
+
" case int:",
|
|
1254
|
+
" if v == 3 {",
|
|
1255
|
+
" return v",
|
|
1256
|
+
" }",
|
|
1257
|
+
" }",
|
|
1258
|
+
" }",
|
|
1259
|
+
" return -1",
|
|
1260
|
+
"}",
|
|
1261
|
+
"func nestedReturn(limit int) int {",
|
|
1262
|
+
" for v := range values {",
|
|
1263
|
+
" for i := range values {",
|
|
1264
|
+
" if i == limit {",
|
|
1265
|
+
" return v + i",
|
|
1266
|
+
" }",
|
|
1267
|
+
" }",
|
|
1268
|
+
" }",
|
|
1269
|
+
" return -1",
|
|
1270
|
+
"}",
|
|
1271
|
+
"func main() { println(first(3), nestedReturn(2)) }",
|
|
1272
|
+
"",
|
|
1273
|
+
}, "\n"),
|
|
1274
|
+
})
|
|
1275
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1276
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1277
|
+
if err != nil {
|
|
1278
|
+
t.Fatal(err.Error())
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1282
|
+
t.Fatal(err.Error())
|
|
1283
|
+
}
|
|
1284
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "iterator-control", "main.gs.ts")
|
|
1285
|
+
content, err := os.ReadFile(outputFile)
|
|
1286
|
+
if err != nil {
|
|
1287
|
+
t.Fatal(err.Error())
|
|
1288
|
+
}
|
|
1289
|
+
text := string(content)
|
|
1290
|
+
for _, want := range []string{
|
|
1291
|
+
"let __goscriptRangeReturn",
|
|
1292
|
+
"let __goscriptRangeReturnValue",
|
|
1293
|
+
"return true",
|
|
1294
|
+
"return false",
|
|
1295
|
+
"__goscriptRangeReturnValue",
|
|
1296
|
+
"if (__goscriptRangeReturn",
|
|
1297
|
+
"return __goscriptRangeReturnValue",
|
|
1298
|
+
"for (let i = 0; i < j; [i, j] = [i + 1, j - 1])",
|
|
1299
|
+
"for (let i = 0; i < 2; i++)",
|
|
1300
|
+
"switch (v)",
|
|
1301
|
+
"const __goscriptTypeSwitchValue",
|
|
1302
|
+
"switch (true)",
|
|
1303
|
+
"case $.typeAssert<number>(__goscriptTypeSwitchValue, { kind: $.TypeKind.Basic, name: \"int\" }).ok",
|
|
1304
|
+
"break",
|
|
1305
|
+
} {
|
|
1306
|
+
if !strings.Contains(text, want) {
|
|
1307
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
nestedReturn := regexp.MustCompile(`if \(__goscriptRangeReturn\d+\) \{\n\t+__goscriptRangeReturn\d+ = true\n\t+__goscriptRangeReturnValue\d+ = __goscriptRangeReturnValue\d+!\n\t+return false\n\t+\}`)
|
|
1311
|
+
if !nestedReturn.MatchString(text) {
|
|
1312
|
+
t.Fatalf("missing nested range return propagation:\n%s", text)
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
1317
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1318
|
+
"go.mod": "module example.test/async\n\ngo 1.25.3\n",
|
|
1319
|
+
"main.go": strings.Join([]string{
|
|
1320
|
+
"package main",
|
|
1321
|
+
"type Processor interface { Process(v int) int }",
|
|
1322
|
+
"type Worker struct { ch chan int }",
|
|
1323
|
+
"func (w *Worker) Process(v int) int {",
|
|
1324
|
+
" w.ch <- v",
|
|
1325
|
+
" return <-w.ch",
|
|
1326
|
+
"}",
|
|
1327
|
+
"func call(p Processor) int { return p.Process(2) }",
|
|
1328
|
+
"func main() {",
|
|
1329
|
+
" ch := make(chan int, 1)",
|
|
1330
|
+
" defer func() { <-ch }()",
|
|
1331
|
+
" go func() { ch <- 1 }()",
|
|
1332
|
+
" select {",
|
|
1333
|
+
" case v := <-ch:",
|
|
1334
|
+
" println(v)",
|
|
1335
|
+
" default:",
|
|
1336
|
+
" println(\"default\")",
|
|
1337
|
+
" }",
|
|
1338
|
+
" _ = call(&Worker{ch: make(chan int, 1)})",
|
|
1339
|
+
"}",
|
|
1340
|
+
"",
|
|
1341
|
+
}, "\n"),
|
|
1342
|
+
})
|
|
1343
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1344
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1345
|
+
if err != nil {
|
|
1346
|
+
t.Fatal(err.Error())
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1350
|
+
t.Fatal(err.Error())
|
|
1351
|
+
}
|
|
1352
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "async", "main.gs.ts")
|
|
1353
|
+
content, err := os.ReadFile(outputFile)
|
|
1354
|
+
if err != nil {
|
|
1355
|
+
t.Fatal(err.Error())
|
|
1356
|
+
}
|
|
1357
|
+
text := string(content)
|
|
1358
|
+
for _, want := range []string{
|
|
1359
|
+
"Process(v: number): globalThis.Promise<number>",
|
|
1360
|
+
"public async Process(v: number): globalThis.Promise<number>",
|
|
1361
|
+
"let ch = $.makeChannel<number>(1, 0, \"both\")",
|
|
1362
|
+
"await $.chanSend($.pointerValue<Worker>(w).ch, v)",
|
|
1363
|
+
"return await $.chanRecv($.pointerValue<Worker>(w).ch)",
|
|
1364
|
+
"await using __defer = new $.AsyncDisposableStack()",
|
|
1365
|
+
"queueMicrotask(async () => { await ($.functionValue(async (): globalThis.Promise<void> => {",
|
|
1366
|
+
"$.selectStatement<any, void>([",
|
|
1367
|
+
"let v = result.value",
|
|
1368
|
+
"await call($.interfaceValue<Processor | null>(new Worker({ch: $.makeChannel<number>(1, 0, \"both\")}), \"*main.Worker\"))",
|
|
1369
|
+
} {
|
|
1370
|
+
if !strings.Contains(text, want) {
|
|
1371
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
|
|
1377
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1378
|
+
"go.mod": "module example.test/ifinit\n\ngo 1.25.3\n",
|
|
1379
|
+
"main.go": strings.Join([]string{
|
|
1380
|
+
"package main",
|
|
1381
|
+
"func pair() (string, bool) {",
|
|
1382
|
+
" return \"value\", true",
|
|
1383
|
+
"}",
|
|
1384
|
+
"func main() {",
|
|
1385
|
+
" if value, ok := pair(); ok {",
|
|
1386
|
+
" println(value)",
|
|
1387
|
+
" }",
|
|
1388
|
+
" if value, ok := pair(); ok {",
|
|
1389
|
+
" println(value)",
|
|
1390
|
+
" }",
|
|
1391
|
+
"}",
|
|
1392
|
+
"",
|
|
1393
|
+
}, "\n"),
|
|
1394
|
+
})
|
|
1395
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1396
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1397
|
+
if err != nil {
|
|
1398
|
+
t.Fatal(err.Error())
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1402
|
+
t.Fatal(err.Error())
|
|
1403
|
+
}
|
|
1404
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "ifinit", "main.gs.ts"))
|
|
1405
|
+
if err != nil {
|
|
1406
|
+
t.Fatal(err.Error())
|
|
1407
|
+
}
|
|
1408
|
+
if strings.Count(string(content), "{\n\t\tlet [value, ok] = pair()") != 2 {
|
|
1409
|
+
t.Fatalf("if init declarations were not block scoped:\n%s", string(content))
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
func TestCompilePackagesLowersSwitchesAndFunctionValueCalls(t *testing.T) {
|
|
1414
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1415
|
+
"go.mod": "module example.test/switchcall\n\ngo 1.25.3\n",
|
|
1416
|
+
"main.go": strings.Join([]string{
|
|
1417
|
+
"package main",
|
|
1418
|
+
"func main() {",
|
|
1419
|
+
" value := 2",
|
|
1420
|
+
" switch value {",
|
|
1421
|
+
" case 1:",
|
|
1422
|
+
" println(\"one\")",
|
|
1423
|
+
" case 2, 3:",
|
|
1424
|
+
" local := \"two-three\"",
|
|
1425
|
+
" println(local)",
|
|
1426
|
+
" default:",
|
|
1427
|
+
" println(\"other\")",
|
|
1428
|
+
" }",
|
|
1429
|
+
" switch {",
|
|
1430
|
+
" case value > 1:",
|
|
1431
|
+
" println(\"positive\")",
|
|
1432
|
+
" }",
|
|
1433
|
+
"Block:",
|
|
1434
|
+
" for value > 0 {",
|
|
1435
|
+
" switch value {",
|
|
1436
|
+
" case 2:",
|
|
1437
|
+
" value--",
|
|
1438
|
+
" fallthrough",
|
|
1439
|
+
" case 1:",
|
|
1440
|
+
" break Block",
|
|
1441
|
+
" }",
|
|
1442
|
+
" }",
|
|
1443
|
+
"Again:",
|
|
1444
|
+
" value--",
|
|
1445
|
+
" if value > 0 {",
|
|
1446
|
+
" goto Again",
|
|
1447
|
+
" }",
|
|
1448
|
+
" release := func() { println(\"release\") }",
|
|
1449
|
+
" rel := &release",
|
|
1450
|
+
" (*rel)()",
|
|
1451
|
+
" wrapped := func() {",
|
|
1452
|
+
" defer println(\"wrapped deferred\")",
|
|
1453
|
+
" println(\"wrapped body\")",
|
|
1454
|
+
" }",
|
|
1455
|
+
" wrapped()",
|
|
1456
|
+
"}",
|
|
1457
|
+
"",
|
|
1458
|
+
}, "\n"),
|
|
1459
|
+
})
|
|
1460
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1461
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1462
|
+
if err != nil {
|
|
1463
|
+
t.Fatal(err.Error())
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1467
|
+
t.Fatal(err.Error())
|
|
1468
|
+
}
|
|
1469
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "switchcall", "main.gs.ts"))
|
|
1470
|
+
if err != nil {
|
|
1471
|
+
t.Fatal(err.Error())
|
|
1472
|
+
}
|
|
1473
|
+
text := string(content)
|
|
1474
|
+
for _, want := range []string{
|
|
1475
|
+
"switch (value) {",
|
|
1476
|
+
"case 2:",
|
|
1477
|
+
"case 3:",
|
|
1478
|
+
"let local = \"two-three\"",
|
|
1479
|
+
"switch (true) {",
|
|
1480
|
+
"Block: while (value > 0)",
|
|
1481
|
+
"break Block",
|
|
1482
|
+
"Again: while (true)",
|
|
1483
|
+
"continue Again",
|
|
1484
|
+
"($.pointerValue<(() => void) | null>(rel))!()",
|
|
1485
|
+
"$.functionValue((): void => {\n\t\tusing __defer = new $.DisposableStack()",
|
|
1486
|
+
"__defer.defer(() => { $.println(\"wrapped deferred\") })",
|
|
1487
|
+
"$.println(\"wrapped body\")",
|
|
1488
|
+
} {
|
|
1489
|
+
if !strings.Contains(text, want) {
|
|
1490
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
if strings.Count(text, "\t\tbreak\n") < 3 {
|
|
1494
|
+
t.Fatalf("switch cases were not rendered with implicit breaks:\n%s", text)
|
|
1495
|
+
}
|
|
1496
|
+
if strings.Contains(text, "fallthrough") {
|
|
1497
|
+
t.Fatalf("fallthrough marker leaked into generated output:\n%s", text)
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
func TestCompilePackagesLowersMethodValuesWithFixedParameters(t *testing.T) {
|
|
1502
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1503
|
+
"go.mod": "module example.test/methodvalue\n\ngo 1.25.3\n",
|
|
1504
|
+
"main.go": strings.Join([]string{
|
|
1505
|
+
"package main",
|
|
1506
|
+
"type Counter int",
|
|
1507
|
+
"func (c Counter) Add(n int) int {",
|
|
1508
|
+
" return int(c) + n",
|
|
1509
|
+
"}",
|
|
1510
|
+
"type Runner struct{}",
|
|
1511
|
+
"func (r Runner) Run() {",
|
|
1512
|
+
" println(\"run\")",
|
|
1513
|
+
"}",
|
|
1514
|
+
"func main() {",
|
|
1515
|
+
" c := Counter(4)",
|
|
1516
|
+
" add := c.Add",
|
|
1517
|
+
" println(add(3))",
|
|
1518
|
+
" r := Runner{}",
|
|
1519
|
+
" run := r.Run",
|
|
1520
|
+
" run()",
|
|
1521
|
+
"}",
|
|
1522
|
+
"",
|
|
1523
|
+
}, "\n"),
|
|
1524
|
+
})
|
|
1525
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1526
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1527
|
+
if err != nil {
|
|
1528
|
+
t.Fatal(err.Error())
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1532
|
+
t.Fatal(err.Error())
|
|
1533
|
+
}
|
|
1534
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "methodvalue", "main.gs.ts"))
|
|
1535
|
+
if err != nil {
|
|
1536
|
+
t.Fatal(err.Error())
|
|
1537
|
+
}
|
|
1538
|
+
text := string(content)
|
|
1539
|
+
for _, want := range []string{
|
|
1540
|
+
"((__receiver) => (n: number) => Counter_Add(__receiver, n))(c)",
|
|
1541
|
+
"((__receiver) => () => __receiver.Run())(",
|
|
1542
|
+
} {
|
|
1543
|
+
if !strings.Contains(text, want) {
|
|
1544
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if strings.Contains(text, "...args: any[]") {
|
|
1548
|
+
t.Fatalf("method value lowering still uses spread args:\n%s", text)
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testing.T) {
|
|
1553
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1554
|
+
"go.mod": "module example.test/qualified\n\ngo 1.25.3\n",
|
|
1555
|
+
"lib/lib.go": strings.Join([]string{
|
|
1556
|
+
"package lib",
|
|
1557
|
+
"type Box struct {",
|
|
1558
|
+
" Value int",
|
|
1559
|
+
"}",
|
|
1560
|
+
"",
|
|
1561
|
+
}, "\n"),
|
|
1562
|
+
"main.go": strings.Join([]string{
|
|
1563
|
+
"package main",
|
|
1564
|
+
"import (",
|
|
1565
|
+
" \"example.test/qualified/lib\"",
|
|
1566
|
+
" \"sync/atomic\"",
|
|
1567
|
+
")",
|
|
1568
|
+
"type Holder struct {",
|
|
1569
|
+
" Box lib.Box",
|
|
1570
|
+
" Boxes []lib.Box",
|
|
1571
|
+
" Fn func(lib.Box) (lib.Box, error)",
|
|
1572
|
+
" Ptr atomic.Pointer[func()]",
|
|
1573
|
+
"}",
|
|
1574
|
+
"func Use(fn func(lib.Box) (lib.Box, error), box lib.Box) (lib.Box, error) {",
|
|
1575
|
+
" return fn(box)",
|
|
1576
|
+
"}",
|
|
1577
|
+
"func main() {",
|
|
1578
|
+
" _ = Holder{}",
|
|
1579
|
+
" _, _ = Use(func(box lib.Box) (lib.Box, error) { return box, nil }, lib.Box{})",
|
|
1580
|
+
"}",
|
|
1581
|
+
"",
|
|
1582
|
+
}, "\n"),
|
|
1583
|
+
})
|
|
1584
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1585
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1586
|
+
if err != nil {
|
|
1587
|
+
t.Fatal(err.Error())
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1591
|
+
t.Fatal(err.Error())
|
|
1592
|
+
}
|
|
1593
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "qualified", "main.gs.ts"))
|
|
1594
|
+
if err != nil {
|
|
1595
|
+
t.Fatal(err.Error())
|
|
1596
|
+
}
|
|
1597
|
+
text := string(content)
|
|
1598
|
+
for _, want := range []string{
|
|
1599
|
+
"Box: $.VarRef<lib.Box>",
|
|
1600
|
+
"Boxes: $.VarRef<$.Slice<lib.Box>>",
|
|
1601
|
+
"Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null>",
|
|
1602
|
+
"Ptr: $.VarRef<atomic.Pointer<(() => void) | null>>",
|
|
1603
|
+
"$.markAsStructValue(new lib.Box())",
|
|
1604
|
+
"$.markAsStructValue(new atomic.Pointer<(() => void) | null>())",
|
|
1605
|
+
"export async function Use(fn: ((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null, box: lib.Box): globalThis.Promise<[lib.Box, $.GoError]>",
|
|
1606
|
+
"$.functionValue((box: lib.Box): [lib.Box, $.GoError] => {",
|
|
1607
|
+
} {
|
|
1608
|
+
if !strings.Contains(text, want) {
|
|
1609
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
func TestCompilePackagesLowersUnaryBitwiseComplement(t *testing.T) {
|
|
1615
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1616
|
+
"go.mod": "module example.test/unary-bitwise\n\ngo 1.25.3\n",
|
|
1617
|
+
"main.go": strings.Join([]string{
|
|
1618
|
+
"package main",
|
|
1619
|
+
"var value = 1",
|
|
1620
|
+
"func main() {",
|
|
1621
|
+
" mask := 7",
|
|
1622
|
+
" mask &^= 3",
|
|
1623
|
+
" println(^value, value &^ 3, mask, 0700)",
|
|
1624
|
+
"}",
|
|
1625
|
+
"",
|
|
1626
|
+
}, "\n"),
|
|
1627
|
+
})
|
|
1628
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1629
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1630
|
+
if err != nil {
|
|
1631
|
+
t.Fatal(err.Error())
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1635
|
+
t.Fatal(err.Error())
|
|
1636
|
+
}
|
|
1637
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "unary-bitwise", "main.gs.ts")
|
|
1638
|
+
content, err := os.ReadFile(outputFile)
|
|
1639
|
+
if err != nil {
|
|
1640
|
+
t.Fatal(err.Error())
|
|
1641
|
+
}
|
|
1642
|
+
text := string(content)
|
|
1643
|
+
for _, want := range []string{
|
|
1644
|
+
"mask = mask & ~(3)",
|
|
1645
|
+
"$.println(~value, value & ~(3), mask, 0o700)",
|
|
1646
|
+
} {
|
|
1647
|
+
if !strings.Contains(text, want) {
|
|
1648
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
func TestCompileSourceToTypeScriptCompilesSingleFile(t *testing.T) {
|
|
1654
|
+
output, err := CompileSourceToTypeScript("package main\nfunc main() { println(\"hi\") }\n", "main")
|
|
1655
|
+
if err != nil {
|
|
1656
|
+
t.Fatal(err.Error())
|
|
1657
|
+
}
|
|
1658
|
+
if !strings.Contains(output, "$.println(\"hi\")") {
|
|
1659
|
+
t.Fatalf("missing println in generated output:\n%s", output)
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
func TestTypeScriptEmitOwnerEmitsToMemoryOnDiskPath(t *testing.T) {
|
|
1664
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1665
|
+
"go.mod": "module example.test/memoryemit\n\ngo 1.25.3\n",
|
|
1666
|
+
"main.go": "package main\nfunc main() { println(\"memory\") }\n",
|
|
1667
|
+
})
|
|
1668
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1669
|
+
req := &CompileRequest{
|
|
1670
|
+
Patterns: []string{"."},
|
|
1671
|
+
Dir: moduleDir,
|
|
1672
|
+
OutputPath: outputDir,
|
|
1673
|
+
DependencyMode: DependencyModeRequested,
|
|
1674
|
+
RuntimeEmissionMode: RuntimeEmissionModeReference,
|
|
1675
|
+
}
|
|
1676
|
+
service := NewCompileService()
|
|
1677
|
+
graph, diagnostics := service.PackageGraphOwner().Load(context.Background(), req)
|
|
1678
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
1679
|
+
t.Fatalf("graph diagnostics: %#v", diagnostics)
|
|
1680
|
+
}
|
|
1681
|
+
model, diagnostics := service.SemanticModelOwner().Build(context.Background(), graph)
|
|
1682
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
1683
|
+
t.Fatalf("semantic diagnostics: %#v", diagnostics)
|
|
1684
|
+
}
|
|
1685
|
+
program, diagnostics := service.LoweringOwner().Build(context.Background(), model)
|
|
1686
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
1687
|
+
t.Fatalf("lowering diagnostics: %#v", diagnostics)
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
files, diagnostics := service.TypeScriptEmitOwner().EmitToMemory(context.Background(), program)
|
|
1691
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
1692
|
+
t.Fatalf("memory emit diagnostics: %#v", diagnostics)
|
|
1693
|
+
}
|
|
1694
|
+
path := "@goscript/example.test/memoryemit/main.gs.ts"
|
|
1695
|
+
if !strings.Contains(files[path], "$.println(\"memory\")") {
|
|
1696
|
+
t.Fatalf("missing in-memory output: %#v", files)
|
|
1697
|
+
}
|
|
1698
|
+
if _, diagnostics := service.TypeScriptEmitOwner().Emit(context.Background(), req, program); diagnosticsHaveErrors(diagnostics) {
|
|
1699
|
+
t.Fatalf("disk emit diagnostics: %#v", diagnostics)
|
|
1700
|
+
}
|
|
1701
|
+
content, err := os.ReadFile(filepath.Join(outputDir, filepath.FromSlash(path)))
|
|
1702
|
+
if err != nil {
|
|
1703
|
+
t.Fatal(err.Error())
|
|
1704
|
+
}
|
|
1705
|
+
if string(content) != files[path] {
|
|
1706
|
+
t.Fatalf("disk and memory emit diverged:\n%s\n---\n%s", string(content), files[path])
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
func TestCompilePackagesLowersNamedStructConversionWithTypedAsyncFact(t *testing.T) {
|
|
1711
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1712
|
+
"go.mod": "module example.test/namedstructconvert\n\ngo 1.25.3\n",
|
|
1713
|
+
"main.go": strings.Join([]string{
|
|
1714
|
+
"package main",
|
|
1715
|
+
"type Source struct { Value int }",
|
|
1716
|
+
"type Target Source",
|
|
1717
|
+
"func Make() Source {",
|
|
1718
|
+
" ch := make(chan Source, 1)",
|
|
1719
|
+
" ch <- Source{Value: 7}",
|
|
1720
|
+
" return <-ch",
|
|
1721
|
+
"}",
|
|
1722
|
+
"func Convert() Target {",
|
|
1723
|
+
" return Target(Make())",
|
|
1724
|
+
"}",
|
|
1725
|
+
"func ConvertLiteral() Target {",
|
|
1726
|
+
" return Target(func() Source {",
|
|
1727
|
+
" ch := make(chan Source, 1)",
|
|
1728
|
+
" ch <- Source{Value: 9}",
|
|
1729
|
+
" return <-ch",
|
|
1730
|
+
" }())",
|
|
1731
|
+
"}",
|
|
1732
|
+
"func main() { println(Convert().Value) }",
|
|
1733
|
+
"",
|
|
1734
|
+
}, "\n"),
|
|
1735
|
+
})
|
|
1736
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1737
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1738
|
+
if err != nil {
|
|
1739
|
+
t.Fatal(err.Error())
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1743
|
+
t.Fatal(err.Error())
|
|
1744
|
+
}
|
|
1745
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "namedstructconvert", "main.gs.ts")
|
|
1746
|
+
content, err := os.ReadFile(outputFile)
|
|
1747
|
+
if err != nil {
|
|
1748
|
+
t.Fatal(err.Error())
|
|
1749
|
+
}
|
|
1750
|
+
text := string(content)
|
|
1751
|
+
if !strings.Contains(text, "await (async () => { const __goscriptConvert") {
|
|
1752
|
+
t.Fatalf("missing async named struct conversion:\n%s", text)
|
|
1753
|
+
}
|
|
1754
|
+
if !strings.Contains(text, "$.markAsStructValue(new Target({Value: __goscriptConvert") {
|
|
1755
|
+
t.Fatalf("missing typed named struct conversion target:\n%s", text)
|
|
1756
|
+
}
|
|
1757
|
+
if !strings.Contains(text, "const __goscriptConvert1 = await ($.functionValue(async ") {
|
|
1758
|
+
t.Fatalf("missing async fact from function literal conversion source:\n%s", text)
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
func requireDiagnostic(t *testing.T, err error, code string) {
|
|
1763
|
+
t.Helper()
|
|
1764
|
+
|
|
1765
|
+
var compileErr *CompileError
|
|
1766
|
+
if !errors.As(err, &compileErr) {
|
|
1767
|
+
t.Fatalf("expected CompileError, got %T: %v", err, err)
|
|
1768
|
+
}
|
|
1769
|
+
for _, diag := range compileErr.Diagnostics {
|
|
1770
|
+
if diag.Code == code {
|
|
1771
|
+
return
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
t.Fatalf("missing diagnostic %q in %#v", code, compileErr.Diagnostics)
|
|
1775
|
+
}
|