ttsc 0.7.2 → 0.8.0-dev.20260505

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +5 -5
  2. package/cmd/platform/main.go +86 -76
  3. package/cmd/ttsc/api_compile.go +122 -105
  4. package/cmd/ttsc/api_transform.go +57 -49
  5. package/cmd/ttsc/build.go +116 -103
  6. package/cmd/ttsc/main.go +117 -117
  7. package/cmd/ttsc/main_test.go +191 -191
  8. package/driver/host.go +9 -9
  9. package/driver/program.go +285 -285
  10. package/driver/rewrite.go +266 -219
  11. package/lib/compiler/internal/compileProjectInMemory.js +3 -3
  12. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  13. package/lib/compiler/internal/resolveEmittedJavaScript.js +2 -1
  14. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  15. package/lib/compiler/internal/resolveTsgo.js.map +1 -1
  16. package/lib/compiler/internal/runBuild.js +47 -49
  17. package/lib/compiler/internal/runBuild.js.map +1 -1
  18. package/lib/compiler/internal/transformProjectInMemory.js +44 -4
  19. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  20. package/lib/launcher/internal/getCompilerVersionText.js +1 -2
  21. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
  22. package/lib/launcher/internal/prepareExecution.js +6 -4
  23. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  24. package/lib/launcher/internal/runTtsc.js +49 -5
  25. package/lib/launcher/internal/runTtsc.js.map +1 -1
  26. package/lib/launcher/internal/runTtsx.js +7 -2
  27. package/lib/launcher/internal/runTtsx.js.map +1 -1
  28. package/lib/plugin/internal/buildSourcePlugin.js +6 -0
  29. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  30. package/lib/plugin/internal/loadProjectPlugins.js +55 -2
  31. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  32. package/lib/structures/ITtscPlugin.d.ts +19 -3
  33. package/lib/structures/ITtscPlugin.js +4 -0
  34. package/lib/structures/ITtscPlugin.js.map +1 -1
  35. package/lib/structures/TtscPluginStage.d.ts +4 -10
  36. package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +5 -0
  37. package/package.json +11 -10
  38. package/shim/ast/lint.go +172 -171
  39. package/shim/ast/shim.go +84 -83
  40. package/shim/bundled/shim.go +5 -1
  41. package/shim/checker/shim.go +79 -79
  42. package/shim/compiler/emit_hooks.go +494 -0
  43. package/shim/compiler/shim.go +16 -1
  44. package/shim/core/shim.go +13 -10
  45. package/shim/diagnosticwriter/lint.go +79 -79
  46. package/shim/diagnosticwriter/shim.go +19 -19
  47. package/shim/parser/shim.go +7 -1
  48. package/shim/scanner/shim.go +39 -1
  49. package/shim/tsoptions/shim.go +51 -1
  50. package/shim/tspath/shim.go +72 -1
  51. package/shim/vfs/cachedvfs/shim.go +1 -1
  52. package/shim/vfs/osvfs/shim.go +1 -1
  53. package/shim/vfs/shim.go +4 -1
  54. package/src/compiler/internal/compileProjectInMemory.ts +6 -3
  55. package/src/compiler/internal/resolveEmittedJavaScript.ts +2 -1
  56. package/src/compiler/internal/resolveTsgo.ts +0 -1
  57. package/src/compiler/internal/runBuild.ts +58 -86
  58. package/src/compiler/internal/transformProjectInMemory.ts +51 -6
  59. package/src/launcher/internal/getCompilerVersionText.ts +1 -2
  60. package/src/launcher/internal/prepareExecution.ts +6 -6
  61. package/src/launcher/internal/runTtsc.ts +52 -5
  62. package/src/launcher/internal/runTtsx.ts +16 -5
  63. package/src/plugin/internal/buildSourcePlugin.ts +30 -2
  64. package/src/plugin/internal/loadProjectPlugins.ts +81 -2
  65. package/src/structures/ITtscPlugin.ts +30 -3
  66. package/src/structures/TtscPluginStage.ts +4 -10
  67. package/src/structures/internal/ITtscLoadedNativePlugin.ts +5 -0
  68. package/test/compiler.test.ts +3 -3
  69. package/test/platform.test.ts +1 -3
  70. package/test/tsgo.test.ts +15 -7
  71. package/tools/gen_shims/main.go +409 -409
  72. package/utility/host.go +707 -0
@@ -10,8 +10,8 @@
10
10
  //
11
11
  // Usage:
12
12
  //
13
- // cd packages/ttsc
14
- // go run ./tools/gen_shims
13
+ // cd packages/ttsc
14
+ // go run ./tools/gen_shims
15
15
  //
16
16
  // Each shim directory (`packages/ttsc/shim/<name>`) must contain an
17
17
  // `extra-shim.json` file; the generator writes its output to
@@ -19,21 +19,21 @@
19
19
  package main
20
20
 
21
21
  import (
22
- "bytes"
23
- "fmt"
24
- "go/types"
25
- "log"
26
- "maps"
27
- "os"
28
- "path"
29
- "slices"
30
- "strings"
31
-
32
- "github.com/go-json-experiment/json"
33
-
34
- "golang.org/x/text/cases"
35
- "golang.org/x/text/language"
36
- "golang.org/x/tools/go/packages"
22
+ "bytes"
23
+ "fmt"
24
+ "go/types"
25
+ "log"
26
+ "maps"
27
+ "os"
28
+ "path"
29
+ "slices"
30
+ "strings"
31
+
32
+ "github.com/go-json-experiment/json"
33
+
34
+ "golang.org/x/text/cases"
35
+ "golang.org/x/text/language"
36
+ "golang.org/x/tools/go/packages"
37
37
  )
38
38
 
39
39
  const tsgoInternalPrefix = "github.com/microsoft/typescript-go/internal/"
@@ -42,405 +42,405 @@ const tsgoInternalPrefix = "github.com/microsoft/typescript-go/internal/"
42
42
  // project/lsp/lsproto removed for the current host boundary and the rest kept
43
43
  // verbatim so gen_shims output stays comparable across projects.
44
44
  var packagesToShim = []string{
45
- "ast",
46
- "bundled",
47
- "checker",
48
- "compiler",
49
- "core",
50
- "parser",
51
- "scanner",
52
- "tsoptions",
53
- "tspath",
54
- "vfs",
55
- "vfs/cachedvfs",
56
- "vfs/osvfs",
45
+ "ast",
46
+ "bundled",
47
+ "checker",
48
+ "compiler",
49
+ "core",
50
+ "parser",
51
+ "scanner",
52
+ "tsoptions",
53
+ "tspath",
54
+ "vfs",
55
+ "vfs/cachedvfs",
56
+ "vfs/osvfs",
57
57
  }
58
58
 
59
59
  type ExtraShim struct {
60
- ExtraFunctions []string
61
- ExtraMethods map[string][]string
62
- ExtraFields map[string][]string
63
- IgnoreFunctions []string
60
+ ExtraFunctions []string
61
+ ExtraMethods map[string][]string
62
+ ExtraFields map[string][]string
63
+ IgnoreFunctions []string
64
64
  }
65
65
 
66
66
  func signatureHasUnexportedType(t types.Signature) bool {
67
- if params := t.Params(); params != nil {
68
- for v := range params.Variables() {
69
- ty := v.Type()
70
- if ptrType, ok := ty.(*types.Pointer); ok {
71
- ty = ptrType.Elem()
72
- }
73
- if named, ok := ty.(*types.Named); ok {
74
- if !named.Obj().Exported() {
75
- return true
76
- }
77
- }
78
- }
79
- }
80
- return false
67
+ if params := t.Params(); params != nil {
68
+ for v := range params.Variables() {
69
+ ty := v.Type()
70
+ if ptrType, ok := ty.(*types.Pointer); ok {
71
+ ty = ptrType.Elem()
72
+ }
73
+ if named, ok := ty.(*types.Named); ok {
74
+ if !named.Obj().Exported() {
75
+ return true
76
+ }
77
+ }
78
+ }
79
+ }
80
+ return false
81
81
  }
82
82
 
83
83
  func main() {
84
- fullNames := make([]string, len(packagesToShim))
85
- for i, pkg := range packagesToShim {
86
- fullNames[i] = tsgoInternalPrefix + pkg
87
- }
88
-
89
- loaded, err := packages.Load(&packages.Config{
90
- Dir: "./shim/ast", // any shim module works as anchor; they all require typescript-go
91
- Mode: packages.LoadSyntax,
92
- }, fullNames...)
93
- if err != nil {
94
- log.Fatalf("gen_shims: packages.Load: %v", err)
95
- }
96
-
97
- var shimHeaderBuilder strings.Builder
98
- var shimBuilder strings.Builder
99
- var tempBuffer bytes.Buffer
100
-
101
- for _, pkg := range loaded {
102
- if len(pkg.Errors) != 0 {
103
- for _, e := range pkg.Errors {
104
- fmt.Fprintln(os.Stderr, "gen_shims:", e)
105
- }
106
- log.Fatalf("gen_shims: package %s failed to load (see errors above)", pkg.PkgPath)
107
- }
108
- shimDirPath := path.Join("./shim/", strings.TrimPrefix(pkg.PkgPath, tsgoInternalPrefix))
109
-
110
- var extraShim ExtraShim
111
- extraShimFilePath := path.Join(shimDirPath, "extra-shim.json")
112
- if data, err := os.ReadFile(extraShimFilePath); err == nil {
113
- if err := json.Unmarshal(data, &extraShim); err != nil {
114
- fmt.Fprintf(os.Stderr, "gen_shims: error parsing %v: %v\n", extraShimFilePath, err)
115
- os.Exit(1)
116
- }
117
- }
118
- if extraShim.ExtraMethods == nil {
119
- extraShim.ExtraMethods = map[string][]string{}
120
- }
121
- if extraShim.ExtraFunctions == nil {
122
- extraShim.ExtraFunctions = []string{}
123
- }
124
- if extraShim.ExtraFields == nil {
125
- extraShim.ExtraFields = map[string][]string{}
126
- }
127
- if extraShim.IgnoreFunctions == nil {
128
- extraShim.IgnoreFunctions = []string{}
129
- }
130
-
131
- importedPackages := map[string]bool{}
132
- importPackage := func(path string, directly bool) {
133
- if directly {
134
- importedPackages[path] = true
135
- } else if _, ok := importedPackages[path]; !ok {
136
- importedPackages[path] = false
137
- }
138
- }
139
-
140
- var qualifierOnlyPackageName types.Qualifier = func(p *types.Package) string {
141
- importPackage(p.Path(), true)
142
- return p.Name()
143
- }
144
- var qualifierEmptyPackageName types.Qualifier = func(p *types.Package) string { return "" }
145
-
146
- emitGoLinknameDirective := func(localName string, fn *types.Func) {
147
- importPackage("unsafe", false)
148
- importPackage(pkg.Types.Path(), false)
149
- shimBuilder.WriteString("//go:linkname ")
150
- shimBuilder.WriteString(localName)
151
- shimBuilder.WriteByte(' ')
152
- shimBuilder.WriteString(fn.Pkg().Path())
153
- shimBuilder.WriteByte('.')
154
- if recv := fn.Signature().Recv(); recv != nil {
155
- shimBuilder.WriteByte('(')
156
- shimBuilder.WriteString(types.TypeString(recv.Type(), qualifierEmptyPackageName))
157
- shimBuilder.WriteByte(')')
158
- shimBuilder.WriteByte('.')
159
- }
160
- shimBuilder.WriteString(fn.Name())
161
- shimBuilder.WriteByte('\n')
162
- }
163
-
164
- emitLinkedFunction := func(fn *types.Func) bool {
165
- if fn.Signature().TypeParams() != nil {
166
- return false
167
- }
168
- if signatureHasUnexportedType(*fn.Signature()) {
169
- fmt.Fprintf(os.Stderr, "gen_shims: skipping %s.%s (unexported types)\n", fn.Pkg().Name(), fn.Name())
170
- return false
171
- }
172
- name := cases.Title(language.English, cases.NoLower).String(fn.Name())
173
- emitGoLinknameDirective(name, fn)
174
- shimBuilder.WriteString("func ")
175
- shimBuilder.WriteString(name)
176
- types.WriteSignature(&tempBuffer, fn.Signature(), qualifierOnlyPackageName)
177
- shimBuilder.Write(tempBuffer.Bytes())
178
- tempBuffer.Reset()
179
- shimBuilder.WriteString("\n")
180
- return true
181
- }
182
-
183
- matchedExtraFunctions := make(map[string]bool, len(extraShim.ExtraFunctions))
184
- for _, name := range extraShim.ExtraFunctions {
185
- matchedExtraFunctions[name] = false
186
- }
187
- matchedExtraMethods := make(map[string]map[string]bool, len(extraShim.ExtraMethods))
188
- for name, methods := range extraShim.ExtraMethods {
189
- matchedExtraMethods[name] = make(map[string]bool, len(methods))
190
- for _, method := range methods {
191
- matchedExtraMethods[name][method] = false
192
- }
193
- }
194
- matchedExtraFields := make(map[string]bool, len(extraShim.ExtraFields))
195
- for name := range extraShim.ExtraFields {
196
- matchedExtraFields[name] = false
197
- }
198
-
199
- scope := pkg.Types.Scope()
200
- for _, name := range scope.Names() {
201
- object := scope.Lookup(name)
202
- if !object.Exported() {
203
- fn, isFunc := object.(*types.Func)
204
- if _, exists := matchedExtraFunctions[name]; isFunc && exists {
205
- if emitLinkedFunction(fn) {
206
- matchedExtraFunctions[name] = true
207
- }
208
- }
209
- continue
210
- }
211
-
212
- printReexport := func(kind string) {
213
- importPackage(pkg.Types.Path(), true)
214
- shimBuilder.WriteString(kind)
215
- shimBuilder.WriteString(" ")
216
- shimBuilder.WriteString(name)
217
- shimBuilder.WriteString(" = ")
218
- shimBuilder.WriteString(pkg.Name)
219
- shimBuilder.WriteString(".")
220
- shimBuilder.WriteString(name)
221
- shimBuilder.WriteString("\n")
222
- }
223
-
224
- switch object.(type) {
225
- case *types.TypeName:
226
- typeName := object.(*types.TypeName)
227
- t := typeName.Type()
228
- named, isNamed := t.(*types.Named)
229
- if isNamed {
230
- _, nameWithTypeParams, _ := strings.Cut(types.TypeString(named, qualifierOnlyPackageName), ".")
231
- importPackage(pkg.Types.Path(), true)
232
- shimBuilder.WriteString("type ")
233
- shimBuilder.WriteString(nameWithTypeParams)
234
- shimBuilder.WriteString(" = ")
235
- shimBuilder.WriteString(pkg.Name)
236
- shimBuilder.WriteString(".")
237
- shimBuilder.WriteString(name)
238
-
239
- typeParams := slices.Collect(named.TypeParams().TypeParams())
240
- if len(typeParams) > 0 {
241
- shimBuilder.WriteByte('[')
242
- for i, ty := range typeParams {
243
- if i > 0 {
244
- shimBuilder.WriteByte(',')
245
- }
246
- shimBuilder.WriteString(ty.String())
247
- }
248
- shimBuilder.WriteByte(']')
249
- }
250
- shimBuilder.WriteString("\n")
251
- } else {
252
- printReexport("type")
253
- }
254
-
255
- if extraMethods, ok := matchedExtraMethods[name]; isNamed && ok {
256
- for method := range named.Methods() {
257
- methodName := method.Name()
258
- if _, exists := extraMethods[methodName]; !exists {
259
- continue
260
- }
261
- extraMethods[methodName] = true
262
- prefix := name + "_"
263
- emitGoLinknameDirective(prefix+methodName, method)
264
- funcDeclStr := types.ObjectString(method, qualifierOnlyPackageName)
265
- recvStart := 0
266
- recvEnd := 0
267
- paramsStart := 0
268
- for i, s := range funcDeclStr {
269
- if s == '(' {
270
- if recvStart == 0 {
271
- recvStart = i + 1
272
- }
273
- if recvEnd != 0 {
274
- paramsStart = i + 1
275
- break
276
- }
277
- }
278
- if s == ')' && recvEnd == 0 {
279
- recvEnd = i
280
- }
281
- }
282
- shimBuilder.WriteString("func ")
283
- shimBuilder.WriteString(prefix)
284
- shimBuilder.WriteString(funcDeclStr[recvEnd+2 : paramsStart])
285
- shimBuilder.WriteString("recv ")
286
- shimBuilder.WriteString(funcDeclStr[recvStart:recvEnd])
287
- if method.Signature().Params() != nil {
288
- shimBuilder.WriteString(", ")
289
- }
290
- shimBuilder.WriteString(funcDeclStr[paramsStart:])
291
- shimBuilder.WriteString("\n")
292
- }
293
- }
294
-
295
- if _, ok := matchedExtraFields[name]; isNamed && ok {
296
- importPackage("unsafe", true)
297
- matchedExtraFields[name] = true
298
- mirrorStructName := "extra_" + name
299
-
300
- var emitExtraStruct func(name string, s *types.Struct)
301
- emitExtraStruct = func(name string, s *types.Struct) {
302
- shimBuilder.WriteString("type extra_")
303
- shimBuilder.WriteString(name)
304
- shimBuilder.WriteString(" struct {")
305
-
306
- dependencies := []struct {
307
- string
308
- *types.Struct
309
- }{}
310
- for field := range s.Fields() {
311
- shimBuilder.WriteString("\n ")
312
- if !field.Embedded() {
313
- shimBuilder.WriteString(field.Name())
314
- shimBuilder.WriteByte(' ')
315
- }
316
-
317
- ptrType, ok := field.Type().(*types.Pointer)
318
- if ok {
319
- named, ok := ptrType.Elem().(*types.Named)
320
- if ok && !named.Obj().Exported() {
321
- strct, ok := named.Underlying().(*types.Struct)
322
- if ok {
323
- n := named.Obj().Name()
324
- dependencies = append(dependencies, struct {
325
- string
326
- *types.Struct
327
- }{n, strct})
328
- shimBuilder.WriteString("extra_")
329
- shimBuilder.WriteString(n)
330
- continue
331
- }
332
- }
333
- }
334
-
335
- shimBuilder.WriteString(
336
- strings.ReplaceAll(types.TypeString(field.Type(), qualifierOnlyPackageName), "checker.thisAssignmentDeclarationKind", "int32"),
337
- )
338
- }
339
- shimBuilder.WriteString("\n}\n")
340
- for _, dep := range dependencies {
341
- emitExtraStruct(dep.string, dep.Struct)
342
- }
343
- }
344
-
345
- strct, ok := named.Underlying().(*types.Struct)
346
- if !ok {
347
- log.Fatalf("gen_shims: expected %v to be struct", name)
348
- }
349
- emitExtraStruct(name, strct)
350
-
351
- mappedFieldTypes := make(map[string]*types.Var, strct.NumFields())
352
- for field := range strct.Fields() {
353
- mappedFieldTypes[field.Name()] = field
354
- }
355
-
356
- for _, field := range extraShim.ExtraFields[name] {
357
- shimBuilder.WriteString("func ")
358
- shimBuilder.WriteString(name)
359
- shimBuilder.WriteByte('_')
360
- shimBuilder.WriteString(field)
361
- shimBuilder.WriteString("(v *")
362
- shimBuilder.WriteString(pkg.Name)
363
- shimBuilder.WriteByte('.')
364
- shimBuilder.WriteString(name)
365
- shimBuilder.WriteString(") ")
366
-
367
- fieldVar, ok := mappedFieldTypes[field]
368
- if !ok {
369
- log.Fatalf("gen_shims: expected struct %q to contain field %q", name, field)
370
- }
371
- shimBuilder.WriteString(types.TypeString(fieldVar.Type(), qualifierOnlyPackageName))
372
- shimBuilder.WriteString(" {\n")
373
- shimBuilder.WriteString(" return ((*")
374
- shimBuilder.WriteString(mirrorStructName)
375
- shimBuilder.WriteString(")(unsafe.Pointer(v))).")
376
- shimBuilder.WriteString(field)
377
- shimBuilder.WriteString("\n")
378
- shimBuilder.WriteString("}\n")
379
- }
380
- }
381
- case *types.Const:
382
- printReexport("const")
383
- case *types.Var:
384
- printReexport("var")
385
- case *types.Func:
386
- if !slices.Contains(extraShim.IgnoreFunctions, name) {
387
- funcType := object.(*types.Func)
388
- emitLinkedFunction(funcType)
389
- }
390
- }
391
- }
392
-
393
- exit := false
394
- for fnName, found := range matchedExtraFunctions {
395
- if found {
396
- continue
397
- }
398
- fmt.Fprintf(os.Stderr, "gen_shims: ERROR couldn't find %v function\n", fnName)
399
- exit = true
400
- }
401
- for name, methods := range matchedExtraMethods {
402
- for methodName, found := range methods {
403
- if found {
404
- continue
405
- }
406
- fmt.Fprintf(os.Stderr, "gen_shims: ERROR couldn't find %v.%v method\n", name, methodName)
407
- exit = true
408
- }
409
- }
410
- if exit {
411
- os.Exit(1)
412
- }
413
-
414
- shimHeaderBuilder.WriteString("\n// Code generated by packages/ttsc/tools/gen_shims. DO NOT EDIT.\n\n")
415
- shimHeaderBuilder.WriteString("package ")
416
- shimHeaderBuilder.WriteString(pkg.Name)
417
- shimHeaderBuilder.WriteString("\n\n")
418
- importsList := slices.Collect(maps.Keys(importedPackages))
419
- slices.Sort(importsList)
420
- for _, imported := range importsList {
421
- shimHeaderBuilder.WriteString("import ")
422
- if !importedPackages[imported] {
423
- shimHeaderBuilder.WriteString("_ ")
424
- }
425
- shimHeaderBuilder.WriteString("\"")
426
- shimHeaderBuilder.WriteString(imported)
427
- shimHeaderBuilder.WriteString("\"\n")
428
- }
429
- shimHeaderBuilder.WriteString("\n")
430
-
431
- shimGoPath := path.Join(shimDirPath, "shim.go")
432
- file, err := os.Create(shimGoPath)
433
- if err != nil {
434
- log.Fatalf("gen_shims: opening %v for write: %v", shimGoPath, err)
435
- }
436
- file.WriteString(shimHeaderBuilder.String())
437
- file.WriteString(shimBuilder.String())
438
- if err := file.Close(); err != nil {
439
- log.Fatalf("gen_shims: closing %v: %v", shimGoPath, err)
440
- }
441
- fmt.Fprintf(os.Stdout, "gen_shims: wrote %s (%d bytes)\n", shimGoPath, len(shimBuilder.String()))
442
-
443
- shimHeaderBuilder.Reset()
444
- shimBuilder.Reset()
445
- }
84
+ fullNames := make([]string, len(packagesToShim))
85
+ for i, pkg := range packagesToShim {
86
+ fullNames[i] = tsgoInternalPrefix + pkg
87
+ }
88
+
89
+ loaded, err := packages.Load(&packages.Config{
90
+ Dir: "./shim/ast", // any shim module works as anchor; they all require typescript-go
91
+ Mode: packages.LoadSyntax,
92
+ }, fullNames...)
93
+ if err != nil {
94
+ log.Fatalf("gen_shims: packages.Load: %v", err)
95
+ }
96
+
97
+ var shimHeaderBuilder strings.Builder
98
+ var shimBuilder strings.Builder
99
+ var tempBuffer bytes.Buffer
100
+
101
+ for _, pkg := range loaded {
102
+ if len(pkg.Errors) != 0 {
103
+ for _, e := range pkg.Errors {
104
+ fmt.Fprintln(os.Stderr, "gen_shims:", e)
105
+ }
106
+ log.Fatalf("gen_shims: package %s failed to load (see errors above)", pkg.PkgPath)
107
+ }
108
+ shimDirPath := path.Join("./shim/", strings.TrimPrefix(pkg.PkgPath, tsgoInternalPrefix))
109
+
110
+ var extraShim ExtraShim
111
+ extraShimFilePath := path.Join(shimDirPath, "extra-shim.json")
112
+ if data, err := os.ReadFile(extraShimFilePath); err == nil {
113
+ if err := json.Unmarshal(data, &extraShim); err != nil {
114
+ fmt.Fprintf(os.Stderr, "gen_shims: error parsing %v: %v\n", extraShimFilePath, err)
115
+ os.Exit(1)
116
+ }
117
+ }
118
+ if extraShim.ExtraMethods == nil {
119
+ extraShim.ExtraMethods = map[string][]string{}
120
+ }
121
+ if extraShim.ExtraFunctions == nil {
122
+ extraShim.ExtraFunctions = []string{}
123
+ }
124
+ if extraShim.ExtraFields == nil {
125
+ extraShim.ExtraFields = map[string][]string{}
126
+ }
127
+ if extraShim.IgnoreFunctions == nil {
128
+ extraShim.IgnoreFunctions = []string{}
129
+ }
130
+
131
+ importedPackages := map[string]bool{}
132
+ importPackage := func(path string, directly bool) {
133
+ if directly {
134
+ importedPackages[path] = true
135
+ } else if _, ok := importedPackages[path]; !ok {
136
+ importedPackages[path] = false
137
+ }
138
+ }
139
+
140
+ var qualifierOnlyPackageName types.Qualifier = func(p *types.Package) string {
141
+ importPackage(p.Path(), true)
142
+ return p.Name()
143
+ }
144
+ var qualifierEmptyPackageName types.Qualifier = func(p *types.Package) string { return "" }
145
+
146
+ emitGoLinknameDirective := func(localName string, fn *types.Func) {
147
+ importPackage("unsafe", false)
148
+ importPackage(pkg.Types.Path(), false)
149
+ shimBuilder.WriteString("//go:linkname ")
150
+ shimBuilder.WriteString(localName)
151
+ shimBuilder.WriteByte(' ')
152
+ shimBuilder.WriteString(fn.Pkg().Path())
153
+ shimBuilder.WriteByte('.')
154
+ if recv := fn.Signature().Recv(); recv != nil {
155
+ shimBuilder.WriteByte('(')
156
+ shimBuilder.WriteString(types.TypeString(recv.Type(), qualifierEmptyPackageName))
157
+ shimBuilder.WriteByte(')')
158
+ shimBuilder.WriteByte('.')
159
+ }
160
+ shimBuilder.WriteString(fn.Name())
161
+ shimBuilder.WriteByte('\n')
162
+ }
163
+
164
+ emitLinkedFunction := func(fn *types.Func) bool {
165
+ if fn.Signature().TypeParams() != nil {
166
+ return false
167
+ }
168
+ if signatureHasUnexportedType(*fn.Signature()) {
169
+ fmt.Fprintf(os.Stderr, "gen_shims: skipping %s.%s (unexported types)\n", fn.Pkg().Name(), fn.Name())
170
+ return false
171
+ }
172
+ name := cases.Title(language.English, cases.NoLower).String(fn.Name())
173
+ emitGoLinknameDirective(name, fn)
174
+ shimBuilder.WriteString("func ")
175
+ shimBuilder.WriteString(name)
176
+ types.WriteSignature(&tempBuffer, fn.Signature(), qualifierOnlyPackageName)
177
+ shimBuilder.Write(tempBuffer.Bytes())
178
+ tempBuffer.Reset()
179
+ shimBuilder.WriteString("\n")
180
+ return true
181
+ }
182
+
183
+ matchedExtraFunctions := make(map[string]bool, len(extraShim.ExtraFunctions))
184
+ for _, name := range extraShim.ExtraFunctions {
185
+ matchedExtraFunctions[name] = false
186
+ }
187
+ matchedExtraMethods := make(map[string]map[string]bool, len(extraShim.ExtraMethods))
188
+ for name, methods := range extraShim.ExtraMethods {
189
+ matchedExtraMethods[name] = make(map[string]bool, len(methods))
190
+ for _, method := range methods {
191
+ matchedExtraMethods[name][method] = false
192
+ }
193
+ }
194
+ matchedExtraFields := make(map[string]bool, len(extraShim.ExtraFields))
195
+ for name := range extraShim.ExtraFields {
196
+ matchedExtraFields[name] = false
197
+ }
198
+
199
+ scope := pkg.Types.Scope()
200
+ for _, name := range scope.Names() {
201
+ object := scope.Lookup(name)
202
+ if !object.Exported() {
203
+ fn, isFunc := object.(*types.Func)
204
+ if _, exists := matchedExtraFunctions[name]; isFunc && exists {
205
+ if emitLinkedFunction(fn) {
206
+ matchedExtraFunctions[name] = true
207
+ }
208
+ }
209
+ continue
210
+ }
211
+
212
+ printReexport := func(kind string) {
213
+ importPackage(pkg.Types.Path(), true)
214
+ shimBuilder.WriteString(kind)
215
+ shimBuilder.WriteString(" ")
216
+ shimBuilder.WriteString(name)
217
+ shimBuilder.WriteString(" = ")
218
+ shimBuilder.WriteString(pkg.Name)
219
+ shimBuilder.WriteString(".")
220
+ shimBuilder.WriteString(name)
221
+ shimBuilder.WriteString("\n")
222
+ }
223
+
224
+ switch object.(type) {
225
+ case *types.TypeName:
226
+ typeName := object.(*types.TypeName)
227
+ t := typeName.Type()
228
+ named, isNamed := t.(*types.Named)
229
+ if isNamed {
230
+ _, nameWithTypeParams, _ := strings.Cut(types.TypeString(named, qualifierOnlyPackageName), ".")
231
+ importPackage(pkg.Types.Path(), true)
232
+ shimBuilder.WriteString("type ")
233
+ shimBuilder.WriteString(nameWithTypeParams)
234
+ shimBuilder.WriteString(" = ")
235
+ shimBuilder.WriteString(pkg.Name)
236
+ shimBuilder.WriteString(".")
237
+ shimBuilder.WriteString(name)
238
+
239
+ typeParams := slices.Collect(named.TypeParams().TypeParams())
240
+ if len(typeParams) > 0 {
241
+ shimBuilder.WriteByte('[')
242
+ for i, ty := range typeParams {
243
+ if i > 0 {
244
+ shimBuilder.WriteByte(',')
245
+ }
246
+ shimBuilder.WriteString(ty.String())
247
+ }
248
+ shimBuilder.WriteByte(']')
249
+ }
250
+ shimBuilder.WriteString("\n")
251
+ } else {
252
+ printReexport("type")
253
+ }
254
+
255
+ if extraMethods, ok := matchedExtraMethods[name]; isNamed && ok {
256
+ for method := range named.Methods() {
257
+ methodName := method.Name()
258
+ if _, exists := extraMethods[methodName]; !exists {
259
+ continue
260
+ }
261
+ extraMethods[methodName] = true
262
+ prefix := name + "_"
263
+ emitGoLinknameDirective(prefix+methodName, method)
264
+ funcDeclStr := types.ObjectString(method, qualifierOnlyPackageName)
265
+ recvStart := 0
266
+ recvEnd := 0
267
+ paramsStart := 0
268
+ for i, s := range funcDeclStr {
269
+ if s == '(' {
270
+ if recvStart == 0 {
271
+ recvStart = i + 1
272
+ }
273
+ if recvEnd != 0 {
274
+ paramsStart = i + 1
275
+ break
276
+ }
277
+ }
278
+ if s == ')' && recvEnd == 0 {
279
+ recvEnd = i
280
+ }
281
+ }
282
+ shimBuilder.WriteString("func ")
283
+ shimBuilder.WriteString(prefix)
284
+ shimBuilder.WriteString(funcDeclStr[recvEnd+2 : paramsStart])
285
+ shimBuilder.WriteString("recv ")
286
+ shimBuilder.WriteString(funcDeclStr[recvStart:recvEnd])
287
+ if method.Signature().Params() != nil {
288
+ shimBuilder.WriteString(", ")
289
+ }
290
+ shimBuilder.WriteString(funcDeclStr[paramsStart:])
291
+ shimBuilder.WriteString("\n")
292
+ }
293
+ }
294
+
295
+ if _, ok := matchedExtraFields[name]; isNamed && ok {
296
+ importPackage("unsafe", true)
297
+ matchedExtraFields[name] = true
298
+ mirrorStructName := "extra_" + name
299
+
300
+ var emitExtraStruct func(name string, s *types.Struct)
301
+ emitExtraStruct = func(name string, s *types.Struct) {
302
+ shimBuilder.WriteString("type extra_")
303
+ shimBuilder.WriteString(name)
304
+ shimBuilder.WriteString(" struct {")
305
+
306
+ dependencies := []struct {
307
+ string
308
+ *types.Struct
309
+ }{}
310
+ for field := range s.Fields() {
311
+ shimBuilder.WriteString("\n ")
312
+ if !field.Embedded() {
313
+ shimBuilder.WriteString(field.Name())
314
+ shimBuilder.WriteByte(' ')
315
+ }
316
+
317
+ ptrType, ok := field.Type().(*types.Pointer)
318
+ if ok {
319
+ named, ok := ptrType.Elem().(*types.Named)
320
+ if ok && !named.Obj().Exported() {
321
+ strct, ok := named.Underlying().(*types.Struct)
322
+ if ok {
323
+ n := named.Obj().Name()
324
+ dependencies = append(dependencies, struct {
325
+ string
326
+ *types.Struct
327
+ }{n, strct})
328
+ shimBuilder.WriteString("extra_")
329
+ shimBuilder.WriteString(n)
330
+ continue
331
+ }
332
+ }
333
+ }
334
+
335
+ shimBuilder.WriteString(
336
+ strings.ReplaceAll(types.TypeString(field.Type(), qualifierOnlyPackageName), "checker.thisAssignmentDeclarationKind", "int32"),
337
+ )
338
+ }
339
+ shimBuilder.WriteString("\n}\n")
340
+ for _, dep := range dependencies {
341
+ emitExtraStruct(dep.string, dep.Struct)
342
+ }
343
+ }
344
+
345
+ strct, ok := named.Underlying().(*types.Struct)
346
+ if !ok {
347
+ log.Fatalf("gen_shims: expected %v to be struct", name)
348
+ }
349
+ emitExtraStruct(name, strct)
350
+
351
+ mappedFieldTypes := make(map[string]*types.Var, strct.NumFields())
352
+ for field := range strct.Fields() {
353
+ mappedFieldTypes[field.Name()] = field
354
+ }
355
+
356
+ for _, field := range extraShim.ExtraFields[name] {
357
+ shimBuilder.WriteString("func ")
358
+ shimBuilder.WriteString(name)
359
+ shimBuilder.WriteByte('_')
360
+ shimBuilder.WriteString(field)
361
+ shimBuilder.WriteString("(v *")
362
+ shimBuilder.WriteString(pkg.Name)
363
+ shimBuilder.WriteByte('.')
364
+ shimBuilder.WriteString(name)
365
+ shimBuilder.WriteString(") ")
366
+
367
+ fieldVar, ok := mappedFieldTypes[field]
368
+ if !ok {
369
+ log.Fatalf("gen_shims: expected struct %q to contain field %q", name, field)
370
+ }
371
+ shimBuilder.WriteString(types.TypeString(fieldVar.Type(), qualifierOnlyPackageName))
372
+ shimBuilder.WriteString(" {\n")
373
+ shimBuilder.WriteString(" return ((*")
374
+ shimBuilder.WriteString(mirrorStructName)
375
+ shimBuilder.WriteString(")(unsafe.Pointer(v))).")
376
+ shimBuilder.WriteString(field)
377
+ shimBuilder.WriteString("\n")
378
+ shimBuilder.WriteString("}\n")
379
+ }
380
+ }
381
+ case *types.Const:
382
+ printReexport("const")
383
+ case *types.Var:
384
+ printReexport("var")
385
+ case *types.Func:
386
+ if !slices.Contains(extraShim.IgnoreFunctions, name) {
387
+ funcType := object.(*types.Func)
388
+ emitLinkedFunction(funcType)
389
+ }
390
+ }
391
+ }
392
+
393
+ exit := false
394
+ for fnName, found := range matchedExtraFunctions {
395
+ if found {
396
+ continue
397
+ }
398
+ fmt.Fprintf(os.Stderr, "gen_shims: ERROR couldn't find %v function\n", fnName)
399
+ exit = true
400
+ }
401
+ for name, methods := range matchedExtraMethods {
402
+ for methodName, found := range methods {
403
+ if found {
404
+ continue
405
+ }
406
+ fmt.Fprintf(os.Stderr, "gen_shims: ERROR couldn't find %v.%v method\n", name, methodName)
407
+ exit = true
408
+ }
409
+ }
410
+ if exit {
411
+ os.Exit(1)
412
+ }
413
+
414
+ shimHeaderBuilder.WriteString("\n// Code generated by packages/ttsc/tools/gen_shims. DO NOT EDIT.\n\n")
415
+ shimHeaderBuilder.WriteString("package ")
416
+ shimHeaderBuilder.WriteString(pkg.Name)
417
+ shimHeaderBuilder.WriteString("\n\n")
418
+ importsList := slices.Collect(maps.Keys(importedPackages))
419
+ slices.Sort(importsList)
420
+ for _, imported := range importsList {
421
+ shimHeaderBuilder.WriteString("import ")
422
+ if !importedPackages[imported] {
423
+ shimHeaderBuilder.WriteString("_ ")
424
+ }
425
+ shimHeaderBuilder.WriteString("\"")
426
+ shimHeaderBuilder.WriteString(imported)
427
+ shimHeaderBuilder.WriteString("\"\n")
428
+ }
429
+ shimHeaderBuilder.WriteString("\n")
430
+
431
+ shimGoPath := path.Join(shimDirPath, "shim.go")
432
+ file, err := os.Create(shimGoPath)
433
+ if err != nil {
434
+ log.Fatalf("gen_shims: opening %v for write: %v", shimGoPath, err)
435
+ }
436
+ file.WriteString(shimHeaderBuilder.String())
437
+ file.WriteString(shimBuilder.String())
438
+ if err := file.Close(); err != nil {
439
+ log.Fatalf("gen_shims: closing %v: %v", shimGoPath, err)
440
+ }
441
+ fmt.Fprintf(os.Stdout, "gen_shims: wrote %s (%d bytes)\n", shimGoPath, len(shimBuilder.String()))
442
+
443
+ shimHeaderBuilder.Reset()
444
+ shimBuilder.Reset()
445
+ }
446
446
  }