goscript 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/goscript/cmd_compile.go +28 -8
- package/cmd/goscript/cmd_compile_test.go +105 -6
- package/compiler/build-flags.go +9 -10
- package/compiler/gotest/runner_test.go +127 -0
- package/compiler/lowered-program.go +1 -0
- package/compiler/lowering.go +1325 -194
- package/compiler/lowering_bench_test.go +350 -0
- package/compiler/override-registry_test.go +43 -0
- package/compiler/package-graph.go +61 -4
- package/compiler/package-graph_test.go +30 -0
- package/compiler/semantic-model-types.go +8 -0
- package/compiler/semantic-model.go +447 -22
- package/compiler/semantic-model_test.go +138 -0
- package/compiler/skeleton_test.go +1436 -50
- package/compiler/typescript-emitter.go +47 -4
- package/dist/gs/builtin/builtin.d.ts +2 -2
- package/dist/gs/builtin/builtin.js +20 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.js +36 -9
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/slice.js +5 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +1 -1
- package/dist/gs/builtin/type.js +80 -8
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.d.ts +7 -5
- package/dist/gs/bytes/bytes.gs.js +10 -4
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/compress/zlib/index.d.ts +3 -3
- package/dist/gs/compress/zlib/index.js +88 -26
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/sha1/index.d.ts +5 -0
- package/dist/gs/crypto/sha1/index.js +103 -0
- package/dist/gs/crypto/sha1/index.js.map +1 -0
- package/dist/gs/crypto/sha256/index.js +2 -5
- package/dist/gs/crypto/sha256/index.js.map +1 -1
- package/dist/gs/crypto/sha512/index.js +2 -5
- package/dist/gs/crypto/sha512/index.js.map +1 -1
- package/dist/gs/embed/index.d.ts +6 -0
- package/dist/gs/embed/index.js +210 -5
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +4 -4
- package/dist/gs/fmt/fmt.js +93 -19
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
- package/dist/gs/io/fs/readdir.js +5 -3
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/io.d.ts +18 -11
- package/dist/gs/io/io.js +107 -44
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.d.ts +26 -5
- package/dist/gs/math/bits/index.js +13 -24
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +7 -5
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +11 -1
- package/dist/gs/net/http/index.js +157 -11
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +6 -2
- package/dist/gs/os/types_js.gs.js +169 -8
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +1 -0
- package/dist/gs/reflect/type.js +80 -51
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js +2 -2
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +2 -1
- package/dist/gs/sync/sync.js +37 -16
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/js/index.js +9 -0
- package/dist/gs/syscall/js/index.js.map +1 -1
- package/dist/gs/testing/testing.js +8 -6
- package/dist/gs/testing/testing.js.map +1 -1
- package/gs/builtin/builtin.ts +25 -2
- package/gs/builtin/channel.ts +47 -9
- package/gs/builtin/runtime-contract.test.ts +78 -0
- package/gs/builtin/slice.ts +7 -0
- package/gs/builtin/type.ts +97 -8
- package/gs/bytes/bytes.gs.ts +19 -10
- package/gs/bytes/bytes.test.ts +17 -0
- package/gs/compress/zlib/index.test.ts +97 -0
- package/gs/compress/zlib/index.ts +117 -27
- package/gs/compress/zlib/meta.json +4 -1
- package/gs/context/context.test.ts +5 -1
- package/gs/crypto/sha1/index.test.ts +45 -0
- package/gs/crypto/sha1/index.ts +127 -0
- package/gs/crypto/sha1/meta.json +8 -0
- package/gs/crypto/sha256/index.test.ts +14 -2
- package/gs/crypto/sha256/index.ts +3 -6
- package/gs/crypto/sha512/index.test.ts +17 -2
- package/gs/crypto/sha512/index.ts +3 -6
- package/gs/embed/index.test.ts +87 -0
- package/gs/embed/index.ts +229 -5
- package/gs/fmt/fmt.test.ts +61 -3
- package/gs/fmt/fmt.ts +115 -22
- package/gs/fmt/meta.json +6 -1
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +1 -1
- package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
- package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
- package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
- package/gs/io/fs/readdir.test.ts +38 -0
- package/gs/io/fs/readdir.ts +7 -3
- package/gs/io/io.test.ts +135 -0
- package/gs/io/io.ts +143 -63
- package/gs/io/meta.json +7 -1
- package/gs/math/bits/index.ts +52 -28
- package/gs/net/http/httptest/index.test.ts +34 -2
- package/gs/net/http/httptest/index.ts +23 -8
- package/gs/net/http/index.test.ts +46 -0
- package/gs/net/http/index.ts +178 -12
- package/gs/os/file_unix_js.test.ts +52 -0
- package/gs/os/meta.json +4 -0
- package/gs/os/readdir.test.ts +56 -0
- package/gs/os/types_js.gs.ts +169 -8
- package/gs/os/zero_copy_posix.gs.ts +1 -2
- package/gs/reflect/deepequal.test.ts +10 -1
- package/gs/reflect/type.ts +91 -56
- package/gs/reflect/typefor.test.ts +31 -1
- package/gs/strings/meta.json +5 -2
- package/gs/strings/reader.test.ts +2 -2
- package/gs/strings/reader.ts +2 -2
- package/gs/sync/meta.json +2 -0
- package/gs/sync/sync.test.ts +41 -1
- package/gs/sync/sync.ts +41 -16
- package/gs/syscall/js/index.test.ts +18 -0
- package/gs/syscall/js/index.ts +12 -0
- package/gs/testing/testing.test.ts +32 -3
- package/gs/testing/testing.ts +13 -10
- package/package.json +1 -1
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"go/types"
|
|
7
|
+
"os"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
"testing"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
type loweringBenchFixture struct {
|
|
13
|
+
model *SemanticModel
|
|
14
|
+
owner *LoweringOwner
|
|
15
|
+
semPkg *semanticPackage
|
|
16
|
+
file loweringBenchFile
|
|
17
|
+
genDecls []loweringBenchGenDecl
|
|
18
|
+
stmtLists []loweringBenchStmtList
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type loweringBenchFile struct {
|
|
22
|
+
file *ast.File
|
|
23
|
+
sourcePath string
|
|
24
|
+
associated []*ast.FuncDecl
|
|
25
|
+
declFiles map[types.Object]string
|
|
26
|
+
outputNames map[string]string
|
|
27
|
+
lazyPackageVars map[types.Object]bool
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type loweringBenchGenDecl struct {
|
|
31
|
+
ctx lowerFileContext
|
|
32
|
+
decl *ast.GenDecl
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type loweringBenchStmtList struct {
|
|
36
|
+
ctx lowerFileContext
|
|
37
|
+
stmts []ast.Stmt
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func BenchmarkLoweringPackage(b *testing.B) {
|
|
41
|
+
fixture := newLoweringBenchFixture(b)
|
|
42
|
+
b.ReportAllocs()
|
|
43
|
+
b.ResetTimer()
|
|
44
|
+
for i := 0; i < b.N; i++ {
|
|
45
|
+
if _, diagnostics := fixture.owner.lowerPackage(fixture.model, fixture.semPkg); diagnosticsHaveErrors(diagnostics) {
|
|
46
|
+
b.Fatal(diagnostics)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func BenchmarkLoweringAnalyzeLocalFileReferences(b *testing.B) {
|
|
52
|
+
fixture := newLoweringBenchFixture(b)
|
|
53
|
+
b.ReportAllocs()
|
|
54
|
+
b.ResetTimer()
|
|
55
|
+
for i := 0; i < b.N; i++ {
|
|
56
|
+
_ = fixture.owner.analyzeLocalFileReferences(
|
|
57
|
+
fixture.semPkg,
|
|
58
|
+
fixture.file.file,
|
|
59
|
+
fixture.file.sourcePath,
|
|
60
|
+
fixture.file.associated,
|
|
61
|
+
fixture.file.declFiles,
|
|
62
|
+
fixture.file.outputNames,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func BenchmarkLoweringFile(b *testing.B) {
|
|
68
|
+
fixture := newLoweringBenchFixture(b)
|
|
69
|
+
b.ReportAllocs()
|
|
70
|
+
b.ResetTimer()
|
|
71
|
+
for i := 0; i < b.N; i++ {
|
|
72
|
+
if _, diagnostics := fixture.owner.lowerFile(
|
|
73
|
+
fixture.model,
|
|
74
|
+
fixture.semPkg,
|
|
75
|
+
fixture.file.file,
|
|
76
|
+
fixture.file.sourcePath,
|
|
77
|
+
fixture.file.declFiles,
|
|
78
|
+
fixture.file.outputNames,
|
|
79
|
+
fixture.file.lazyPackageVars,
|
|
80
|
+
); diagnosticsHaveErrors(diagnostics) {
|
|
81
|
+
b.Fatal(diagnostics)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func BenchmarkLoweringGenDecls(b *testing.B) {
|
|
87
|
+
fixture := newLoweringBenchFixture(b)
|
|
88
|
+
b.ReportAllocs()
|
|
89
|
+
b.ResetTimer()
|
|
90
|
+
for i := 0; i < b.N; i++ {
|
|
91
|
+
for _, target := range fixture.genDecls {
|
|
92
|
+
if _, diagnostics := fixture.owner.lowerGenDecl(target.ctx, target.decl); diagnosticsHaveErrors(diagnostics) {
|
|
93
|
+
b.Fatal(diagnostics)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func BenchmarkLoweringStmtLists(b *testing.B) {
|
|
100
|
+
fixture := newLoweringBenchFixture(b)
|
|
101
|
+
b.ReportAllocs()
|
|
102
|
+
b.ResetTimer()
|
|
103
|
+
for i := 0; i < b.N; i++ {
|
|
104
|
+
for _, target := range fixture.stmtLists {
|
|
105
|
+
if _, diagnostics := fixture.owner.lowerStmtList(target.ctx, target.stmts); diagnosticsHaveErrors(diagnostics) {
|
|
106
|
+
b.Fatal(diagnostics)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func BenchmarkLoweringPackageDeclFiles(b *testing.B) {
|
|
113
|
+
fixture := newLoweringBenchFixture(b)
|
|
114
|
+
b.ReportAllocs()
|
|
115
|
+
b.ResetTimer()
|
|
116
|
+
for i := 0; i < b.N; i++ {
|
|
117
|
+
_ = packageDeclFiles(fixture.semPkg)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func BenchmarkLoweringLazyPackageVars(b *testing.B) {
|
|
122
|
+
fixture := newLoweringBenchFixture(b)
|
|
123
|
+
b.ReportAllocs()
|
|
124
|
+
b.ResetTimer()
|
|
125
|
+
for i := 0; i < b.N; i++ {
|
|
126
|
+
_ = fixture.owner.lazyPackageVars(fixture.semPkg, fixture.file.declFiles)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
func newLoweringBenchFixture(tb testing.TB) *loweringBenchFixture {
|
|
131
|
+
tb.Helper()
|
|
132
|
+
dir := tb.TempDir()
|
|
133
|
+
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module example.test/loweringbench\n\ngo 1.25.3\n"), 0o644); err != nil {
|
|
134
|
+
tb.Fatal(err)
|
|
135
|
+
}
|
|
136
|
+
for name, source := range loweringBenchSources {
|
|
137
|
+
if err := os.WriteFile(filepath.Join(dir, name), []byte(source), 0o644); err != nil {
|
|
138
|
+
tb.Fatal(err)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
service := NewCompileService()
|
|
143
|
+
req := &CompileRequest{
|
|
144
|
+
Dir: dir,
|
|
145
|
+
OutputPath: filepath.Join(dir, "out"),
|
|
146
|
+
Patterns: []string{"."},
|
|
147
|
+
}
|
|
148
|
+
graph, graphDiagnostics := service.PackageGraphOwner().Load(context.Background(), req)
|
|
149
|
+
if diagnosticsHaveErrors(graphDiagnostics) {
|
|
150
|
+
tb.Fatal(graphDiagnostics)
|
|
151
|
+
}
|
|
152
|
+
model, semanticDiagnostics := service.SemanticModelOwner().Build(context.Background(), graph)
|
|
153
|
+
if diagnosticsHaveErrors(semanticDiagnostics) {
|
|
154
|
+
tb.Fatal(semanticDiagnostics)
|
|
155
|
+
}
|
|
156
|
+
semPkg := model.packages["example.test/loweringbench"]
|
|
157
|
+
if semPkg == nil {
|
|
158
|
+
tb.Fatal("missing benchmark semantic package")
|
|
159
|
+
}
|
|
160
|
+
owner := service.LoweringOwner()
|
|
161
|
+
declFiles := packageDeclFiles(semPkg)
|
|
162
|
+
outputNames := packageOutputNames(semPkg)
|
|
163
|
+
lazyPackageVars := owner.lazyPackageVars(semPkg, declFiles)
|
|
164
|
+
|
|
165
|
+
var benchFile loweringBenchFile
|
|
166
|
+
var genDecls []loweringBenchGenDecl
|
|
167
|
+
var stmtLists []loweringBenchStmtList
|
|
168
|
+
for idx, file := range semPkg.source.Syntax {
|
|
169
|
+
sourcePath := sourceFilePath(semPkg, idx, file)
|
|
170
|
+
associated := owner.methodDeclsForFileTypes(semPkg, file)
|
|
171
|
+
localRefs := owner.analyzeLocalFileReferences(semPkg, file, sourcePath, associated, declFiles, outputNames)
|
|
172
|
+
ctx := lowerFileContext{
|
|
173
|
+
model: model,
|
|
174
|
+
semPkg: semPkg,
|
|
175
|
+
file: file,
|
|
176
|
+
importAliases: make(map[string]string),
|
|
177
|
+
importPaths: make(map[string]string),
|
|
178
|
+
importNames: make(map[string]string),
|
|
179
|
+
importObjects: make(map[*types.PkgName]string),
|
|
180
|
+
sourcePath: sourcePath,
|
|
181
|
+
localAliases: localRefs.aliases,
|
|
182
|
+
lazyPackageVars: lazyPackageVars,
|
|
183
|
+
tempNames: newTempNameOwner(),
|
|
184
|
+
topLevel: true,
|
|
185
|
+
}
|
|
186
|
+
if filepath.Base(sourcePath) == "bench.go" {
|
|
187
|
+
benchFile = loweringBenchFile{
|
|
188
|
+
file: file,
|
|
189
|
+
sourcePath: sourcePath,
|
|
190
|
+
associated: associated,
|
|
191
|
+
declFiles: declFiles,
|
|
192
|
+
outputNames: outputNames,
|
|
193
|
+
lazyPackageVars: lazyPackageVars,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
for _, decl := range file.Decls {
|
|
197
|
+
switch typed := decl.(type) {
|
|
198
|
+
case *ast.GenDecl:
|
|
199
|
+
genDecls = append(genDecls, loweringBenchGenDecl{ctx: ctx, decl: typed})
|
|
200
|
+
case *ast.FuncDecl:
|
|
201
|
+
fn, _ := semPkg.source.TypesInfo.Defs[typed.Name].(*types.Func)
|
|
202
|
+
signature, _ := fn.Type().(*types.Signature)
|
|
203
|
+
bodyCtx := ctx.withSignature(signature).withAsyncFunction(owner.functionAsync(ctx, fn))
|
|
204
|
+
if typed.Body != nil {
|
|
205
|
+
stmtLists = append(stmtLists, loweringBenchStmtList{ctx: bodyCtx, stmts: typed.Body.List})
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if benchFile.file == nil {
|
|
211
|
+
tb.Fatal("missing bench.go fixture file")
|
|
212
|
+
}
|
|
213
|
+
if len(genDecls) == 0 || len(stmtLists) == 0 {
|
|
214
|
+
tb.Fatalf("incomplete lowering benchmark fixture: genDecls=%d stmtLists=%d", len(genDecls), len(stmtLists))
|
|
215
|
+
}
|
|
216
|
+
return &loweringBenchFixture{
|
|
217
|
+
model: model,
|
|
218
|
+
owner: owner,
|
|
219
|
+
semPkg: semPkg,
|
|
220
|
+
file: benchFile,
|
|
221
|
+
genDecls: genDecls,
|
|
222
|
+
stmtLists: stmtLists,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
var loweringBenchSources = map[string]string{
|
|
227
|
+
"bench.go": `package loweringbench
|
|
228
|
+
|
|
229
|
+
type Number interface {
|
|
230
|
+
~int | ~int64
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
type Item[T Number] struct {
|
|
234
|
+
ID int
|
|
235
|
+
Name string
|
|
236
|
+
Values []T
|
|
237
|
+
Meta map[string]T
|
|
238
|
+
Next *Item[T]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
type Processor[T Number] interface {
|
|
242
|
+
Process(Item[T]) (T, error)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
type Runner[T Number] struct {
|
|
246
|
+
Items []Item[T]
|
|
247
|
+
Proc Processor[T]
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
var GlobalItems = []Item[int]{
|
|
251
|
+
{ID: 1, Name: "one", Values: []int{1, 2, 3}, Meta: map[string]int{"a": 1}},
|
|
252
|
+
{ID: 2, Name: "two", Values: []int{4, 5, 6}, Meta: map[string]int{"b": 2}},
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
var Lookup = map[string]Item[int]{
|
|
256
|
+
"one": GlobalItems[0],
|
|
257
|
+
"two": GlobalItems[1],
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
func (r *Runner[T]) Sum(seed T) (T, error) {
|
|
261
|
+
total := seed
|
|
262
|
+
for idx, item := range r.Items {
|
|
263
|
+
for _, value := range item.Values {
|
|
264
|
+
total += value
|
|
265
|
+
}
|
|
266
|
+
if r.Proc != nil {
|
|
267
|
+
next, err := r.Proc.Process(item)
|
|
268
|
+
if err != nil {
|
|
269
|
+
return total, err
|
|
270
|
+
}
|
|
271
|
+
total += next
|
|
272
|
+
}
|
|
273
|
+
if idx%2 == 0 {
|
|
274
|
+
total += T(idx)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return total, nil
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
func UseRunner(r *Runner[int]) int {
|
|
281
|
+
total, err := r.Sum(10)
|
|
282
|
+
if err != nil {
|
|
283
|
+
return -1
|
|
284
|
+
}
|
|
285
|
+
switch {
|
|
286
|
+
case total > 100:
|
|
287
|
+
return total / 2
|
|
288
|
+
case total > 20:
|
|
289
|
+
return total + len(r.Items)
|
|
290
|
+
default:
|
|
291
|
+
return total
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
`,
|
|
295
|
+
"flow.go": `package loweringbench
|
|
296
|
+
|
|
297
|
+
func FoldItems(items []Item[int], fn func(Item[int]) int) int {
|
|
298
|
+
total := 0
|
|
299
|
+
for _, item := range items {
|
|
300
|
+
total += fn(item)
|
|
301
|
+
}
|
|
302
|
+
return total
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
func ComplexFlow(items []Item[int], ch chan int) int {
|
|
306
|
+
total := 0
|
|
307
|
+
for idx := 0; idx < len(items); idx++ {
|
|
308
|
+
item := items[idx]
|
|
309
|
+
select {
|
|
310
|
+
case ch <- item.ID:
|
|
311
|
+
total += item.ID
|
|
312
|
+
default:
|
|
313
|
+
total += len(item.Values)
|
|
314
|
+
}
|
|
315
|
+
for key, value := range item.Meta {
|
|
316
|
+
if key == "" {
|
|
317
|
+
continue
|
|
318
|
+
}
|
|
319
|
+
total += value
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return total
|
|
323
|
+
}
|
|
324
|
+
`,
|
|
325
|
+
"types.go": `package loweringbench
|
|
326
|
+
|
|
327
|
+
type NamedInt int
|
|
328
|
+
|
|
329
|
+
func (n NamedInt) Process(item Item[int]) (int, error) {
|
|
330
|
+
return int(n) + item.ID + len(item.Values), nil
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
type Pair[A, B any] struct {
|
|
334
|
+
A A
|
|
335
|
+
B B
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
type Registry struct {
|
|
339
|
+
ByName map[string]Processor[int]
|
|
340
|
+
Pairs []Pair[string, Item[int]]
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
func NewRegistry() *Registry {
|
|
344
|
+
return &Registry{
|
|
345
|
+
ByName: map[string]Processor[int]{"default": NamedInt(3)},
|
|
346
|
+
Pairs: []Pair[string, Item[int]]{{A: "one", B: GlobalItems[0]}},
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
`,
|
|
350
|
+
}
|
|
@@ -341,6 +341,49 @@ func TestCompilePackagesPropagatesOverrideAsyncInterfaceMethods(t *testing.T) {
|
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
+
func TestCompilePackagesAwaitsOverrideAsyncInterfaceMethodCalls(t *testing.T) {
|
|
345
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
346
|
+
"go.mod": "module example.test/overrideasyncinterfacemethod\n\ngo 1.25.3\n",
|
|
347
|
+
"main.go": strings.Join([]string{
|
|
348
|
+
"package main",
|
|
349
|
+
"import \"sync\"",
|
|
350
|
+
"func Use(l sync.Locker) {",
|
|
351
|
+
" l.Lock()",
|
|
352
|
+
" l.Unlock()",
|
|
353
|
+
"}",
|
|
354
|
+
"func main() {}",
|
|
355
|
+
"",
|
|
356
|
+
}, "\n"),
|
|
357
|
+
})
|
|
358
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
359
|
+
comp, err := NewCompiler(&Config{
|
|
360
|
+
Dir: moduleDir,
|
|
361
|
+
OutputPath: out,
|
|
362
|
+
AllDependencies: true,
|
|
363
|
+
}, nil, nil)
|
|
364
|
+
if err != nil {
|
|
365
|
+
t.Fatal(err.Error())
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
369
|
+
t.Fatal(err.Error())
|
|
370
|
+
}
|
|
371
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "overrideasyncinterfacemethod", "main.gs.ts"))
|
|
372
|
+
if err != nil {
|
|
373
|
+
t.Fatal(err.Error())
|
|
374
|
+
}
|
|
375
|
+
text := string(content)
|
|
376
|
+
for _, want := range []string{
|
|
377
|
+
"export async function Use(l: sync.Locker | null): globalThis.Promise<void>",
|
|
378
|
+
"await $.pointerValue<Exclude<sync.Locker, null>>(l).Lock()",
|
|
379
|
+
"$.pointerValue<Exclude<sync.Locker, null>>(l).Unlock()",
|
|
380
|
+
} {
|
|
381
|
+
if !strings.Contains(text, want) {
|
|
382
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
344
387
|
func TestCompilePackagesAwaitsOverrideAsyncFunctions(t *testing.T) {
|
|
345
388
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
346
389
|
"go.mod": "module example.test/overrideasyncfunc\n\ngo 1.25.3\n",
|
|
@@ -2,6 +2,7 @@ package compiler
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"context"
|
|
5
|
+
"go/ast"
|
|
5
6
|
"os"
|
|
6
7
|
"slices"
|
|
7
8
|
"strings"
|
|
@@ -130,6 +131,15 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
|
|
|
130
131
|
graph.RequestedPackagePaths = append(graph.RequestedPackagePaths, path)
|
|
131
132
|
}
|
|
132
133
|
slices.Sort(graph.RequestedPackagePaths)
|
|
134
|
+
samePackageTestVariants := make(map[string]bool)
|
|
135
|
+
if req.Tests {
|
|
136
|
+
for _, pkg := range pkgs {
|
|
137
|
+
if pkg == nil || pkg.ForTest == "" || strings.HasSuffix(pkg.Name, "_test") {
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
samePackageTestVariants[pkg.ForTest] = true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
133
143
|
|
|
134
144
|
var diagnostics []Diagnostic
|
|
135
145
|
seen := make(map[string]bool)
|
|
@@ -137,7 +147,7 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
|
|
|
137
147
|
if isTestMainPackage(pkg) {
|
|
138
148
|
continue
|
|
139
149
|
}
|
|
140
|
-
o.collect(graph, pkg, req.DependencyMode, requested, overrideFacts, seen)
|
|
150
|
+
o.collect(graph, pkg, req.DependencyMode, requested, samePackageTestVariants, overrideFacts, seen)
|
|
141
151
|
diagnostics = append(diagnostics, packageDiagnostics(pkg)...)
|
|
142
152
|
}
|
|
143
153
|
slices.SortFunc(graph.Nodes, func(a, b *PackageGraphNode) int {
|
|
@@ -161,21 +171,33 @@ func (o *PackageGraphOwner) collect(
|
|
|
161
171
|
pkg *packages.Package,
|
|
162
172
|
mode DependencyMode,
|
|
163
173
|
requested map[string]bool,
|
|
174
|
+
samePackageTestVariants map[string]bool,
|
|
164
175
|
overrideFacts *OverrideFacts,
|
|
165
176
|
seen map[string]bool,
|
|
166
177
|
) {
|
|
167
178
|
if pkg == nil || seen[pkg.ID] {
|
|
168
179
|
return
|
|
169
180
|
}
|
|
181
|
+
path := packagePath(pkg)
|
|
182
|
+
if pkg.ForTest != "" && path != pkg.ForTest && !strings.HasSuffix(pkg.Name, "_test") && samePackageTestVariants[path] {
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
if pkg.ForTest == "" && samePackageTestVariants[path] {
|
|
186
|
+
return
|
|
187
|
+
}
|
|
170
188
|
if pkg.ForTest != "" && !requested[pkg.ForTest] {
|
|
171
189
|
if prod := pkg.Imports[pkg.ForTest]; prod != nil {
|
|
172
|
-
o.collect(graph, prod, mode, requested, overrideFacts, seen)
|
|
190
|
+
o.collect(graph, prod, mode, requested, samePackageTestVariants, overrideFacts, seen)
|
|
173
191
|
}
|
|
174
192
|
return
|
|
175
193
|
}
|
|
194
|
+
if graph.NodesByPackagePath[path] != nil {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
176
197
|
seen[pkg.ID] = true
|
|
177
198
|
|
|
178
|
-
|
|
199
|
+
normalizePackageFileOrder(pkg)
|
|
200
|
+
|
|
179
201
|
node := newPackageGraphNode(pkg, requested[path], overrideFacts)
|
|
180
202
|
graph.Nodes = append(graph.Nodes, node)
|
|
181
203
|
graph.NodesByPackagePath[path] = node
|
|
@@ -190,7 +212,7 @@ func (o *PackageGraphOwner) collect(
|
|
|
190
212
|
}
|
|
191
213
|
slices.Sort(imports)
|
|
192
214
|
for _, importPath := range imports {
|
|
193
|
-
o.collect(graph, pkg.Imports[importPath], mode, requested, overrideFacts, seen)
|
|
215
|
+
o.collect(graph, pkg.Imports[importPath], mode, requested, samePackageTestVariants, overrideFacts, seen)
|
|
194
216
|
}
|
|
195
217
|
}
|
|
196
218
|
|
|
@@ -223,6 +245,41 @@ func newPackageGraphNode(pkg *packages.Package, requested bool, overrideFacts *O
|
|
|
223
245
|
}
|
|
224
246
|
}
|
|
225
247
|
|
|
248
|
+
func normalizePackageFileOrder(pkg *packages.Package) {
|
|
249
|
+
if pkg == nil {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
slices.Sort(pkg.GoFiles)
|
|
253
|
+
if len(pkg.Syntax) == len(pkg.CompiledGoFiles) {
|
|
254
|
+
type sourceFile struct {
|
|
255
|
+
name string
|
|
256
|
+
file *ast.File
|
|
257
|
+
}
|
|
258
|
+
files := make([]sourceFile, len(pkg.Syntax))
|
|
259
|
+
for idx, file := range pkg.Syntax {
|
|
260
|
+
files[idx] = sourceFile{name: pkg.CompiledGoFiles[idx], file: file}
|
|
261
|
+
}
|
|
262
|
+
slices.SortFunc(files, func(a, b sourceFile) int {
|
|
263
|
+
return strings.Compare(a.name, b.name)
|
|
264
|
+
})
|
|
265
|
+
for idx, file := range files {
|
|
266
|
+
pkg.CompiledGoFiles[idx] = file.name
|
|
267
|
+
pkg.Syntax[idx] = file.file
|
|
268
|
+
}
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
slices.Sort(pkg.CompiledGoFiles)
|
|
272
|
+
slices.SortFunc(pkg.Syntax, func(a, b *ast.File) int {
|
|
273
|
+
if pkg.Fset == nil {
|
|
274
|
+
return strings.Compare(a.Name.Name, b.Name.Name)
|
|
275
|
+
}
|
|
276
|
+
return strings.Compare(
|
|
277
|
+
pkg.Fset.Position(a.Package).Filename,
|
|
278
|
+
pkg.Fset.Position(b.Package).Filename,
|
|
279
|
+
)
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
226
283
|
func isTestMainPackage(pkg *packages.Package) bool {
|
|
227
284
|
return pkg != nil && pkg.ForTest == "" && pkg.Name == "main" && strings.HasSuffix(packagePath(pkg), ".test")
|
|
228
285
|
}
|
|
@@ -176,6 +176,36 @@ func TestPackageGraphHonorsBuildFlags(t *testing.T) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
func TestPackageGraphNormalizesCompiledFileOrder(t *testing.T) {
|
|
180
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
181
|
+
"go.mod": "module example.test/order\n\ngo 1.25.3\n",
|
|
182
|
+
"z.go": "package order\nconst Z = 1\n",
|
|
183
|
+
"a.go": "package order\nconst A = 1\n",
|
|
184
|
+
"m.go": "package order\nconst M = 1\n",
|
|
185
|
+
})
|
|
186
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
187
|
+
Patterns: []string{"."},
|
|
188
|
+
Dir: moduleDir,
|
|
189
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
190
|
+
DependencyMode: DependencyModeRequested,
|
|
191
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
pkg := graph.packagesByPath["example.test/order"]
|
|
195
|
+
if pkg == nil {
|
|
196
|
+
t.Fatalf("missing loaded package")
|
|
197
|
+
}
|
|
198
|
+
var compiled []string
|
|
199
|
+
var syntax []string
|
|
200
|
+
for idx, file := range pkg.Syntax {
|
|
201
|
+
compiled = append(compiled, filepath.Base(pkg.CompiledGoFiles[idx]))
|
|
202
|
+
syntax = append(syntax, filepath.Base(pkg.Fset.Position(file.Package).Filename))
|
|
203
|
+
}
|
|
204
|
+
if want := []string{"a.go", "m.go", "z.go"}; !slices.Equal(compiled, want) || !slices.Equal(syntax, want) {
|
|
205
|
+
t.Fatalf("compiled files and syntax must sort together, got compiled=%v syntax=%v", compiled, syntax)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
179
209
|
func TestPackageGraphAddsGoScriptBuildTag(t *testing.T) {
|
|
180
210
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
181
211
|
"go.mod": "module example.test/goscripttag\n\ngo 1.25.3\n",
|
|
@@ -14,10 +14,13 @@ type SemanticModel struct {
|
|
|
14
14
|
functions map[*types.Func]*semanticFunction
|
|
15
15
|
functionsByFullName map[string]*semanticFunction
|
|
16
16
|
functionLookupMisses map[*types.Func]bool
|
|
17
|
+
functionFullNames map[*types.Func]string
|
|
17
18
|
types map[*types.Named]*semanticType
|
|
18
19
|
values map[types.Object]*semanticValue
|
|
19
20
|
generatedImports map[string]map[string]bool
|
|
20
21
|
interfaceImplementations []semanticInterfaceImplementation
|
|
22
|
+
asyncInterfaceMethods map[string]bool
|
|
23
|
+
asyncInterfaceMethodObjs map[*types.Func]bool
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
type semanticPackage struct {
|
|
@@ -103,6 +106,11 @@ type semanticInterfaceImplementationGraphEntry struct {
|
|
|
103
106
|
implMethods map[string]*types.Func
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
type semanticAnonymousInterfaceImplementation struct {
|
|
110
|
+
ifaceMethods map[string]*types.Func
|
|
111
|
+
implMethods map[string]*types.Func
|
|
112
|
+
}
|
|
113
|
+
|
|
106
114
|
type semanticImplementationMethodSet struct {
|
|
107
115
|
typ *types.Named
|
|
108
116
|
receiver types.Type
|