goscript 0.0.21 → 0.0.23
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 +2 -2
- package/compiler/analysis.go +229 -51
- package/compiler/assignment.go +412 -0
- package/compiler/compiler.go +185 -5885
- package/compiler/compiler_test.go +40 -8
- package/compiler/composite-lit.go +552 -0
- package/compiler/config.go +3 -0
- package/compiler/decl.go +259 -0
- package/compiler/expr-call.go +479 -0
- package/compiler/expr-selector.go +125 -0
- package/compiler/expr-star.go +90 -0
- package/compiler/expr-type.go +309 -0
- package/compiler/expr-value.go +89 -0
- package/compiler/expr.go +591 -0
- package/compiler/field.go +169 -0
- package/compiler/lit.go +131 -0
- package/compiler/primitive.go +148 -0
- package/compiler/{write-type-spec.go → spec-struct.go} +211 -204
- package/compiler/spec-value.go +226 -0
- package/compiler/spec.go +272 -0
- package/compiler/stmt-assign.go +439 -0
- package/compiler/stmt-for.go +178 -0
- package/compiler/stmt-range.go +235 -0
- package/compiler/stmt-select.go +211 -0
- package/compiler/stmt-type-switch.go +147 -0
- package/compiler/stmt.go +792 -0
- package/compiler/type-assert.go +209 -0
- package/compiler/type-info.go +141 -0
- package/compiler/type.go +618 -0
- package/go.mod +2 -1
- package/go.sum +4 -2
- package/package.json +6 -6
- package/builtin/builtin.go +0 -11
- package/builtin/builtin.ts +0 -2114
- package/dist/builtin/builtin.d.ts +0 -495
- package/dist/builtin/builtin.js +0 -1490
- package/dist/builtin/builtin.js.map +0 -1
- /package/compiler/{writer.go → code-writer.go} +0 -0
package/compiler/decl.go
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"go/ast"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// WriteDecls iterates through a slice of Go top-level declarations (`ast.Decl`)
|
|
9
|
+
// and translates each one into its TypeScript equivalent.
|
|
10
|
+
// It distinguishes between:
|
|
11
|
+
// - Function declarations (`ast.FuncDecl`):
|
|
12
|
+
// - If it's a regular function (no receiver), it delegates to `WriteFuncDeclAsFunction`.
|
|
13
|
+
// - Methods (with receivers) are handled within `WriteTypeSpec` when their
|
|
14
|
+
// associated struct/type is defined, so they are skipped here.
|
|
15
|
+
// - General declarations (`ast.GenDecl`), which can contain imports, constants,
|
|
16
|
+
// variables, or type definitions: It iterates through `d.Specs` and calls
|
|
17
|
+
// `WriteSpec` for each specification.
|
|
18
|
+
//
|
|
19
|
+
// A newline is added after each processed declaration or spec group for readability.
|
|
20
|
+
// Unknown declaration types result in a printed diagnostic message.
|
|
21
|
+
func (c *GoToTSCompiler) WriteDecls(decls []ast.Decl) error {
|
|
22
|
+
for _, decl := range decls {
|
|
23
|
+
switch d := decl.(type) {
|
|
24
|
+
case *ast.FuncDecl:
|
|
25
|
+
// Only handle top-level functions here. Methods are handled within WriteTypeSpec.
|
|
26
|
+
if d.Recv == nil {
|
|
27
|
+
if err := c.WriteFuncDeclAsFunction(d); err != nil {
|
|
28
|
+
return err
|
|
29
|
+
}
|
|
30
|
+
c.tsw.WriteLine("") // Add space after function
|
|
31
|
+
}
|
|
32
|
+
case *ast.GenDecl:
|
|
33
|
+
for _, spec := range d.Specs {
|
|
34
|
+
if err := c.WriteSpec(spec); err != nil {
|
|
35
|
+
return err
|
|
36
|
+
}
|
|
37
|
+
c.tsw.WriteLine("") // Add space after spec
|
|
38
|
+
}
|
|
39
|
+
default:
|
|
40
|
+
fmt.Printf("unknown decl: %#v\n", decl)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return nil
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// WriteFuncDeclAsFunction translates a Go function declaration (`ast.FuncDecl`)
|
|
47
|
+
// that does not have a receiver (i.e., it's a regular function, not a method)
|
|
48
|
+
// into a TypeScript function.
|
|
49
|
+
// - Go documentation comments (`decl.Doc`) are preserved.
|
|
50
|
+
// - If the Go function is exported (name starts with an uppercase letter) or is
|
|
51
|
+
// the `main` function, the `export` keyword is added to the TypeScript output.
|
|
52
|
+
// - If the `Analysis` data indicates the function is asynchronous, the `async`
|
|
53
|
+
// keyword is prepended.
|
|
54
|
+
// - The function signature (parameters and return type) is translated using `WriteFuncType`,
|
|
55
|
+
// passing the `isAsync` status.
|
|
56
|
+
// - The function body (`decl.Body`) is translated using `WriteStmt`.
|
|
57
|
+
//
|
|
58
|
+
// This function specifically handles top-level functions; methods are generated
|
|
59
|
+
// by `WriteFuncDeclAsMethod` within the context of their type definition.
|
|
60
|
+
func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
|
|
61
|
+
if decl.Recv != nil {
|
|
62
|
+
// This function should not be called for methods.
|
|
63
|
+
// Methods are handled by WriteFuncDeclAsMethod within WriteTypeSpec.
|
|
64
|
+
return nil
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if decl.Doc != nil {
|
|
68
|
+
c.WriteDoc(decl.Doc)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Exported functions start with uppercase in Go, or special-case "main" entry point
|
|
72
|
+
isExported := decl.Name.IsExported() || decl.Name.Name == "main"
|
|
73
|
+
if isExported {
|
|
74
|
+
c.tsw.WriteLiterally("export ")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if this function is async using the analysis data
|
|
78
|
+
var isAsync bool
|
|
79
|
+
if obj := c.pkg.TypesInfo.Defs[decl.Name]; obj != nil {
|
|
80
|
+
isAsync = c.analysis.IsAsyncFunc(obj)
|
|
81
|
+
}
|
|
82
|
+
if isAsync {
|
|
83
|
+
c.tsw.WriteLiterally("async ")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
c.tsw.WriteLiterally("function ")
|
|
87
|
+
if err := c.WriteValueExpr(decl.Name); err != nil { // Function name is a value identifier
|
|
88
|
+
return fmt.Errorf("failed to write function name: %w", err)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Write type parameters if present
|
|
92
|
+
if decl.Type.TypeParams != nil {
|
|
93
|
+
c.WriteTypeParameters(decl.Type.TypeParams)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// WriteFuncType needs to be aware if the function is async
|
|
97
|
+
c.WriteFuncType(decl.Type, isAsync) // Write signature (params, return type)
|
|
98
|
+
c.tsw.WriteLiterally(" ")
|
|
99
|
+
|
|
100
|
+
hasNamedReturns := false
|
|
101
|
+
if decl.Type.Results != nil {
|
|
102
|
+
for _, field := range decl.Type.Results.List {
|
|
103
|
+
if len(field.Names) > 0 {
|
|
104
|
+
hasNamedReturns = true
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if hasNamedReturns {
|
|
111
|
+
c.tsw.WriteLine("{")
|
|
112
|
+
c.tsw.Indent(1)
|
|
113
|
+
|
|
114
|
+
// Declare named return variables and initialize them to their zero values
|
|
115
|
+
for _, field := range decl.Type.Results.List {
|
|
116
|
+
for _, name := range field.Names {
|
|
117
|
+
c.tsw.WriteLiterallyf("let %s: ", name.Name)
|
|
118
|
+
c.WriteTypeExpr(field.Type)
|
|
119
|
+
c.tsw.WriteLiterally(" = ")
|
|
120
|
+
c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
|
|
121
|
+
c.tsw.WriteLine("")
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if err := c.WriteStmt(decl.Body); err != nil {
|
|
127
|
+
return fmt.Errorf("failed to write function body: %w", err)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if hasNamedReturns {
|
|
131
|
+
c.tsw.Indent(-1)
|
|
132
|
+
c.tsw.WriteLine("}")
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return nil
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// WriteFuncDeclAsMethod translates a Go function declaration (`ast.FuncDecl`)
|
|
139
|
+
// that has a receiver (i.e., it's a method) into a TypeScript class method.
|
|
140
|
+
// - It preserves Go documentation comments (`decl.Doc`).
|
|
141
|
+
// - The method is declared as `public`.
|
|
142
|
+
// - If the `Analysis` data indicates the method is asynchronous, the `async`
|
|
143
|
+
// keyword is prepended.
|
|
144
|
+
// - The method name retains its original Go casing.
|
|
145
|
+
// - Parameters and return types are translated using `WriteFieldList` and
|
|
146
|
+
// `WriteTypeExpr`, respectively. Async methods have their return types
|
|
147
|
+
// wrapped in `Promise<>`.
|
|
148
|
+
// - The method body is translated. If the Go receiver has a name (e.g., `(s *MyStruct)`),
|
|
149
|
+
// a `const receiverName = this;` binding is generated at the start of the
|
|
150
|
+
// TypeScript method body to make `this` available via the Go receiver's name.
|
|
151
|
+
// If the method body requires deferred cleanup (`NeedsDefer`), the appropriate
|
|
152
|
+
// `using __defer = new $.DisposableStack()` (or `AsyncDisposableStack`)
|
|
153
|
+
// is also generated.
|
|
154
|
+
//
|
|
155
|
+
// This function assumes it is called only for `FuncDecl` nodes that are methods.
|
|
156
|
+
func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
|
|
157
|
+
if decl.Doc != nil {
|
|
158
|
+
c.WriteDoc(decl.Doc)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Determine if method is async
|
|
162
|
+
var isAsync bool
|
|
163
|
+
if obj := c.pkg.TypesInfo.Defs[decl.Name]; obj != nil {
|
|
164
|
+
isAsync = c.analysis.IsAsyncFunc(obj)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Methods are typically public in the TS output
|
|
168
|
+
c.tsw.WriteLiterally("public ")
|
|
169
|
+
|
|
170
|
+
// Add async modifier if needed
|
|
171
|
+
if isAsync {
|
|
172
|
+
c.tsw.WriteLiterally("async ")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Keep original Go casing for method names
|
|
176
|
+
if err := c.WriteValueExpr(decl.Name); err != nil { // Method name is a value identifier
|
|
177
|
+
return err
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Write signature (parameters and return type)
|
|
181
|
+
// We adapt the logic from WriteFuncType here, but without the 'function' keyword
|
|
182
|
+
funcType := decl.Type
|
|
183
|
+
c.tsw.WriteLiterally("(")
|
|
184
|
+
if funcType.Params != nil {
|
|
185
|
+
c.WriteFieldList(funcType.Params, true) // true = arguments
|
|
186
|
+
}
|
|
187
|
+
c.tsw.WriteLiterally(")")
|
|
188
|
+
|
|
189
|
+
// Handle return type
|
|
190
|
+
if funcType.Results != nil && len(funcType.Results.List) > 0 {
|
|
191
|
+
c.tsw.WriteLiterally(": ")
|
|
192
|
+
if isAsync {
|
|
193
|
+
c.tsw.WriteLiterally("Promise<")
|
|
194
|
+
}
|
|
195
|
+
if len(funcType.Results.List) == 1 {
|
|
196
|
+
// Single return value
|
|
197
|
+
resultType := funcType.Results.List[0].Type
|
|
198
|
+
c.WriteTypeExpr(resultType)
|
|
199
|
+
} else {
|
|
200
|
+
// Multiple return values -> tuple type
|
|
201
|
+
c.tsw.WriteLiterally("[")
|
|
202
|
+
for i, field := range funcType.Results.List {
|
|
203
|
+
if i > 0 {
|
|
204
|
+
c.tsw.WriteLiterally(", ")
|
|
205
|
+
}
|
|
206
|
+
c.WriteTypeExpr(field.Type)
|
|
207
|
+
}
|
|
208
|
+
c.tsw.WriteLiterally("]")
|
|
209
|
+
}
|
|
210
|
+
if isAsync {
|
|
211
|
+
c.tsw.WriteLiterally(">")
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
// No return value -> void
|
|
215
|
+
if isAsync {
|
|
216
|
+
c.tsw.WriteLiterally(": Promise<void>")
|
|
217
|
+
} else {
|
|
218
|
+
c.tsw.WriteLiterally(": void")
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
c.tsw.WriteLiterally(" ")
|
|
223
|
+
|
|
224
|
+
// Bind receiver name to this
|
|
225
|
+
if recvField := decl.Recv.List[0]; len(recvField.Names) > 0 {
|
|
226
|
+
recvName := recvField.Names[0].Name
|
|
227
|
+
if recvName != "_" {
|
|
228
|
+
c.tsw.WriteLine("{")
|
|
229
|
+
c.tsw.Indent(1)
|
|
230
|
+
c.tsw.WriteLinef("const %s = this", recvName)
|
|
231
|
+
|
|
232
|
+
// Add using statement if needed
|
|
233
|
+
if c.analysis.NeedsDefer(decl.Body) {
|
|
234
|
+
if c.analysis.IsInAsyncFunction(decl) {
|
|
235
|
+
c.tsw.WriteLine("await using __defer = new $.AsyncDisposableStack();")
|
|
236
|
+
} else {
|
|
237
|
+
c.tsw.WriteLine("using cleanup = new $.DisposableStack();")
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// write method body without outer braces
|
|
242
|
+
for _, stmt := range decl.Body.List {
|
|
243
|
+
if err := c.WriteStmt(stmt); err != nil {
|
|
244
|
+
return fmt.Errorf("failed to write statement in function body: %w", err)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
c.tsw.Indent(-1)
|
|
248
|
+
c.tsw.WriteLine("}")
|
|
249
|
+
|
|
250
|
+
return nil
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// no named receiver, write whole body
|
|
254
|
+
if err := c.WriteStmt(decl.Body); err != nil {
|
|
255
|
+
return fmt.Errorf("failed to write function body: %w", err)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return nil
|
|
259
|
+
}
|