goscript 0.0.60 → 0.0.62
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 +9 -0
- package/compiler/analysis.go +974 -369
- package/compiler/assignment.go +72 -0
- package/compiler/compiler.go +74 -15
- package/compiler/composite-lit.go +29 -8
- package/compiler/decl.go +67 -98
- package/compiler/expr-call-async.go +26 -1
- package/compiler/expr-call-builtins.go +60 -4
- package/compiler/expr-call-helpers.go +182 -0
- package/compiler/expr-call-type-conversion.go +37 -5
- package/compiler/expr-call.go +25 -33
- package/compiler/expr-selector.go +71 -1
- package/compiler/expr-type.go +49 -3
- package/compiler/expr.go +37 -28
- package/compiler/index.test.ts +3 -1
- package/compiler/lit.go +13 -4
- package/compiler/spec-struct.go +42 -9
- package/compiler/spec-value.go +2 -2
- package/compiler/spec.go +42 -5
- package/compiler/stmt-assign.go +71 -0
- package/compiler/stmt-range.go +2 -2
- package/compiler/stmt.go +130 -10
- package/compiler/type-utils.go +40 -16
- package/compiler/type.go +50 -12
- package/dist/gs/builtin/builtin.d.ts +8 -1
- package/dist/gs/builtin/builtin.js +26 -1
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/errors.d.ts +1 -0
- package/dist/gs/builtin/errors.js +8 -0
- package/dist/gs/builtin/errors.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +5 -4
- package/dist/gs/builtin/slice.js +51 -21
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +28 -2
- package/dist/gs/builtin/type.js +132 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/reader.gs.d.ts +1 -1
- package/dist/gs/bytes/reader.gs.js +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +6 -0
- package/dist/gs/internal/byteorder/index.js +34 -0
- package/dist/gs/internal/byteorder/index.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.d.ts +3 -2
- package/dist/gs/reflect/map.js +37 -3
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +55 -8
- package/dist/gs/reflect/type.js +889 -23
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +11 -12
- package/dist/gs/reflect/types.js +26 -15
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +4 -4
- package/dist/gs/reflect/value.js +8 -2
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +32 -0
- package/dist/gs/slices/slices.js +81 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +2 -2
- package/dist/gs/sync/atomic/type.gs.js +12 -2
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/unicode/utf8/utf8.d.ts +2 -2
- package/dist/gs/unicode/utf8/utf8.js +10 -6
- package/dist/gs/unicode/utf8/utf8.js.map +1 -1
- package/go.mod +4 -4
- package/go.sum +8 -16
- package/gs/builtin/builtin.ts +27 -2
- package/gs/builtin/errors.ts +12 -0
- package/gs/builtin/slice.ts +77 -14
- package/gs/builtin/type.ts +167 -2
- package/gs/bytes/reader.gs.ts +2 -2
- package/gs/internal/byteorder/index.ts +40 -0
- package/gs/math/hypot.gs.test.ts +3 -1
- package/gs/math/pow10.gs.test.ts +5 -4
- package/gs/reflect/index.ts +6 -3
- package/gs/reflect/map.test.ts +7 -6
- package/gs/reflect/map.ts +49 -7
- package/gs/reflect/type.ts +1139 -43
- package/gs/reflect/types.ts +34 -21
- package/gs/reflect/value.ts +12 -6
- package/gs/slices/slices.ts +92 -0
- package/gs/sync/atomic/type.gs.ts +14 -5
- package/gs/sync/meta.json +1 -1
- package/gs/unicode/utf8/utf8.ts +12 -8
- package/package.json +13 -13
|
@@ -25,6 +25,9 @@ var builtinFunctions = map[string]bool{
|
|
|
25
25
|
"recover": true,
|
|
26
26
|
"print": true,
|
|
27
27
|
"println": true,
|
|
28
|
+
"min": true,
|
|
29
|
+
"max": true,
|
|
30
|
+
"clear": true,
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
// writeBuiltinFunction handles built-in Go functions
|
|
@@ -34,7 +37,7 @@ func (c *GoToTSCompiler) writeBuiltinFunction(exp *ast.CallExpr, funName string)
|
|
|
34
37
|
c.tsw.WriteLiterally("$.panic")
|
|
35
38
|
return true, nil
|
|
36
39
|
case "println":
|
|
37
|
-
c.tsw.WriteLiterally("
|
|
40
|
+
c.tsw.WriteLiterally("$.println")
|
|
38
41
|
return true, nil
|
|
39
42
|
case "len":
|
|
40
43
|
if len(exp.Args) != 1 {
|
|
@@ -89,6 +92,46 @@ func (c *GoToTSCompiler) writeBuiltinFunction(exp *ast.CallExpr, funName string)
|
|
|
89
92
|
return true, nil
|
|
90
93
|
case "append":
|
|
91
94
|
return true, c.writeAppendCall(exp)
|
|
95
|
+
case "min":
|
|
96
|
+
if len(exp.Args) < 1 {
|
|
97
|
+
return true, errors.New("unhandled min call with no arguments")
|
|
98
|
+
}
|
|
99
|
+
c.tsw.WriteLiterally("Math.min(")
|
|
100
|
+
for i, arg := range exp.Args {
|
|
101
|
+
if i > 0 {
|
|
102
|
+
c.tsw.WriteLiterally(", ")
|
|
103
|
+
}
|
|
104
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
105
|
+
return true, fmt.Errorf("failed to write argument %d in min call: %w", i, err)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
c.tsw.WriteLiterally(")")
|
|
109
|
+
return true, nil
|
|
110
|
+
case "max":
|
|
111
|
+
if len(exp.Args) < 1 {
|
|
112
|
+
return true, errors.New("unhandled max call with no arguments")
|
|
113
|
+
}
|
|
114
|
+
c.tsw.WriteLiterally("Math.max(")
|
|
115
|
+
for i, arg := range exp.Args {
|
|
116
|
+
if i > 0 {
|
|
117
|
+
c.tsw.WriteLiterally(", ")
|
|
118
|
+
}
|
|
119
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
120
|
+
return true, fmt.Errorf("failed to write argument %d in max call: %w", i, err)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
c.tsw.WriteLiterally(")")
|
|
124
|
+
return true, nil
|
|
125
|
+
case "clear":
|
|
126
|
+
if len(exp.Args) != 1 {
|
|
127
|
+
return true, errors.Errorf("unhandled clear call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
128
|
+
}
|
|
129
|
+
c.tsw.WriteLiterally("$.clear(")
|
|
130
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
131
|
+
return true, fmt.Errorf("failed to write argument in clear call: %w", err)
|
|
132
|
+
}
|
|
133
|
+
c.tsw.WriteLiterally(")")
|
|
134
|
+
return true, nil
|
|
92
135
|
case "byte":
|
|
93
136
|
if len(exp.Args) != 1 {
|
|
94
137
|
return true, errors.Errorf("unhandled byte call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
@@ -119,13 +162,16 @@ func (c *GoToTSCompiler) writeAppendCall(exp *ast.CallExpr) error {
|
|
|
119
162
|
}
|
|
120
163
|
|
|
121
164
|
// The remaining arguments are the elements to append
|
|
122
|
-
|
|
165
|
+
elemsToAppend := exp.Args[1:]
|
|
166
|
+
for i, arg := range elemsToAppend {
|
|
123
167
|
if i > 0 || len(exp.Args) > 1 {
|
|
124
168
|
c.tsw.WriteLiterally(", ")
|
|
125
169
|
}
|
|
126
170
|
|
|
127
|
-
//
|
|
128
|
-
|
|
171
|
+
// Handle ellipsis (spread) for the last argument: append(slice, elems...)
|
|
172
|
+
// The ellipsis can only appear on the last argument, so check if this is the last element
|
|
173
|
+
isLastElement := i == len(elemsToAppend)-1
|
|
174
|
+
if exp.Ellipsis != token.NoPos && isLastElement {
|
|
129
175
|
// Check if the slice is []byte and the argument is a string
|
|
130
176
|
sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
|
|
131
177
|
argType := c.pkg.TypesInfo.TypeOf(arg)
|
|
@@ -141,6 +187,16 @@ func (c *GoToTSCompiler) writeAppendCall(exp *ast.CallExpr) error {
|
|
|
141
187
|
continue
|
|
142
188
|
}
|
|
143
189
|
}
|
|
190
|
+
|
|
191
|
+
// For other slice types with ellipsis, use spread operator
|
|
192
|
+
// append(slice, anotherSlice...) -> $.append(slice, ...(anotherSlice || []))
|
|
193
|
+
// The || [] handles the case where anotherSlice is null (nil in Go)
|
|
194
|
+
c.tsw.WriteLiterally("...(")
|
|
195
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
196
|
+
return fmt.Errorf("failed to write spread argument in append call: %w", err)
|
|
197
|
+
}
|
|
198
|
+
c.tsw.WriteLiterally(" || [])")
|
|
199
|
+
continue
|
|
144
200
|
}
|
|
145
201
|
|
|
146
202
|
if err := c.WriteValueExpr(arg); err != nil {
|
|
@@ -108,3 +108,185 @@ func (c *GoToTSCompiler) writeExprOrDefault(expr interface{}, defaultValue strin
|
|
|
108
108
|
return errors.Errorf("unsupported expression type in writeExprOrDefault: %T", e)
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
// writeReflectTypeFor handles reflect.TypeFor[T]() calls by generating appropriate TypeScript
|
|
113
|
+
func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
114
|
+
// Check if this is reflect.TypeFor
|
|
115
|
+
if selectorExpr.Sel.Name != "TypeFor" {
|
|
116
|
+
return false, nil
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check if X is an identifier referring to the reflect package
|
|
120
|
+
xIdent, ok := selectorExpr.X.(*ast.Ident)
|
|
121
|
+
if !ok {
|
|
122
|
+
return false, nil
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
obj := c.objectOfIdent(xIdent)
|
|
126
|
+
if obj == nil {
|
|
127
|
+
return false, nil
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pkgName, ok := obj.(*types.PkgName)
|
|
131
|
+
if !ok || pkgName.Imported().Path() != "reflect" {
|
|
132
|
+
return false, nil
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// DEBUG: We found reflect.TypeFor
|
|
136
|
+
// fmt.Printf("DEBUG: Found reflect.TypeFor call\n")
|
|
137
|
+
|
|
138
|
+
// This is reflect.TypeFor - now get the type argument
|
|
139
|
+
if c.pkg.TypesInfo.Instances == nil {
|
|
140
|
+
return false, errors.New("reflect.TypeFor called but no type instances available")
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
instance, hasInstance := c.pkg.TypesInfo.Instances[selectorExpr.Sel]
|
|
144
|
+
if !hasInstance || instance.TypeArgs == nil || instance.TypeArgs.Len() == 0 {
|
|
145
|
+
return false, errors.New("reflect.TypeFor called without type arguments")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Get the first type argument
|
|
149
|
+
typeArg := instance.TypeArgs.At(0)
|
|
150
|
+
// fmt.Printf("DEBUG: Type argument: %v\n", typeArg)
|
|
151
|
+
|
|
152
|
+
// Generate TypeScript code to create a Type for this type
|
|
153
|
+
if err := c.writeTypeForTypeArg(typeArg); err != nil {
|
|
154
|
+
return true, err
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return true, nil
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// writeTypeForTypeArg generates TypeScript code to create a reflect.Type for the given Go type
|
|
161
|
+
func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
|
|
162
|
+
// Handle basic types
|
|
163
|
+
switch underlying := t.Underlying().(type) {
|
|
164
|
+
case *types.Basic:
|
|
165
|
+
return c.writeBasicTypeFor(underlying)
|
|
166
|
+
case *types.Named:
|
|
167
|
+
// For named types, use TypeOf with a zero value
|
|
168
|
+
return c.writeNamedTypeFor(t)
|
|
169
|
+
case *types.Pointer:
|
|
170
|
+
// For pointer types, use PointerTo
|
|
171
|
+
c.tsw.WriteLiterally("reflect.PointerTo(")
|
|
172
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
173
|
+
return err
|
|
174
|
+
}
|
|
175
|
+
c.tsw.WriteLiterally(")")
|
|
176
|
+
return nil
|
|
177
|
+
case *types.Slice:
|
|
178
|
+
// For slice types, use TypeOf with an empty slice
|
|
179
|
+
c.tsw.WriteLiterally("reflect.TypeOf([])")
|
|
180
|
+
return nil
|
|
181
|
+
case *types.Array:
|
|
182
|
+
// For array types, use TypeOf with an empty array
|
|
183
|
+
c.tsw.WriteLiterally("reflect.TypeOf([])")
|
|
184
|
+
return nil
|
|
185
|
+
case *types.Struct:
|
|
186
|
+
// For struct types, use TypeOf with zero value
|
|
187
|
+
return c.writeNamedTypeFor(t)
|
|
188
|
+
case *types.Interface:
|
|
189
|
+
// For interface types, use TypeOf with null
|
|
190
|
+
return c.writeNamedTypeFor(t)
|
|
191
|
+
default:
|
|
192
|
+
return errors.Errorf("unsupported type for reflect.TypeFor: %T", underlying)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// writeBasicTypeFor generates code for basic types
|
|
197
|
+
func (c *GoToTSCompiler) writeBasicTypeFor(basic *types.Basic) error {
|
|
198
|
+
// Map basic types to their reflect constructors or TypeOf calls
|
|
199
|
+
// Note: We don't pass type parameters to TypeOf - it infers from the value
|
|
200
|
+
switch basic.Kind() {
|
|
201
|
+
case types.Bool:
|
|
202
|
+
c.tsw.WriteLiterally("reflect.TypeOf(false)")
|
|
203
|
+
case types.Int:
|
|
204
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
205
|
+
case types.Int8:
|
|
206
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
207
|
+
case types.Int16:
|
|
208
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
209
|
+
case types.Int32:
|
|
210
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
211
|
+
case types.Int64:
|
|
212
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0n)")
|
|
213
|
+
case types.Uint:
|
|
214
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
215
|
+
case types.Uint8:
|
|
216
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
217
|
+
case types.Uint16:
|
|
218
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
219
|
+
case types.Uint32:
|
|
220
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
221
|
+
case types.Uint64:
|
|
222
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0n)")
|
|
223
|
+
case types.Uintptr:
|
|
224
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
225
|
+
case types.Float32:
|
|
226
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
227
|
+
case types.Float64:
|
|
228
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
229
|
+
case types.Complex64:
|
|
230
|
+
c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
|
|
231
|
+
case types.Complex128:
|
|
232
|
+
c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
|
|
233
|
+
case types.String:
|
|
234
|
+
c.tsw.WriteLiterally("reflect.TypeOf(\"\")")
|
|
235
|
+
case types.UnsafePointer:
|
|
236
|
+
c.tsw.WriteLiterally("reflect.TypeOf(null)")
|
|
237
|
+
default:
|
|
238
|
+
return errors.Errorf("unsupported basic type for reflect.TypeFor: %v", basic)
|
|
239
|
+
}
|
|
240
|
+
return nil
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// writeNamedTypeFor generates code for named types (structs, interfaces, etc.)
|
|
244
|
+
func (c *GoToTSCompiler) writeNamedTypeFor(t types.Type) error {
|
|
245
|
+
// For interface types, we need special handling since null doesn't carry type info
|
|
246
|
+
if _, ok := t.Underlying().(*types.Interface); ok {
|
|
247
|
+
if named, ok := t.(*types.Named); ok {
|
|
248
|
+
obj := named.Obj()
|
|
249
|
+
pkgPath := ""
|
|
250
|
+
if pkg := obj.Pkg(); pkg != nil {
|
|
251
|
+
if pkg.Name() == "main" {
|
|
252
|
+
pkgPath = "main."
|
|
253
|
+
} else if pkg.Path() != "" {
|
|
254
|
+
pkgPath = pkg.Path() + "."
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
typeName := pkgPath + obj.Name()
|
|
258
|
+
c.tsw.WriteLiterally("reflect.getInterfaceTypeByName(\"" + typeName + "\")")
|
|
259
|
+
return nil
|
|
260
|
+
}
|
|
261
|
+
// For anonymous interfaces, use TypeOf(null)
|
|
262
|
+
c.tsw.WriteLiterally("reflect.TypeOf(null)")
|
|
263
|
+
return nil
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// For named types, we need to create a zero value and call TypeOf
|
|
267
|
+
// Note: We don't pass a type parameter to TypeOf - it infers the type from the value
|
|
268
|
+
c.tsw.WriteLiterally("reflect.TypeOf(")
|
|
269
|
+
|
|
270
|
+
// Generate a zero value for this type
|
|
271
|
+
switch underlying := t.Underlying().(type) {
|
|
272
|
+
case *types.Struct:
|
|
273
|
+
// For struct types: new MyStruct()
|
|
274
|
+
// Check if this is a named type
|
|
275
|
+
if _, ok := t.(*types.Named); ok {
|
|
276
|
+
c.tsw.WriteLiterally("new ")
|
|
277
|
+
c.WriteGoType(t, GoTypeContextGeneral)
|
|
278
|
+
c.tsw.WriteLiterally("()")
|
|
279
|
+
} else {
|
|
280
|
+
// Anonymous struct
|
|
281
|
+
c.tsw.WriteLiterally("{}")
|
|
282
|
+
}
|
|
283
|
+
case *types.Basic:
|
|
284
|
+
// For basic types wrapped in named types
|
|
285
|
+
return c.writeBasicTypeFor(underlying)
|
|
286
|
+
default:
|
|
287
|
+
return errors.Errorf("unsupported named type underlying for reflect.TypeFor: %T", underlying)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
c.tsw.WriteLiterally(")")
|
|
291
|
+
return nil
|
|
292
|
+
}
|
|
@@ -18,14 +18,33 @@ func (c *GoToTSCompiler) writeNilConversion(exp *ast.CallExpr) (handled bool, er
|
|
|
18
18
|
return false, nil
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Check if this is actually a type conversion, not a method/function call
|
|
22
|
+
// For type conversions, exp.Fun is a type expression (IsType() is true)
|
|
23
|
+
// For method calls like s.ptr.Swap(nil), exp.Fun is a selector expression (IsType() is false)
|
|
24
|
+
if tv, ok := c.pkg.TypesInfo.Types[exp.Fun]; !ok || !tv.IsType() {
|
|
25
|
+
// This is not a type conversion, let the normal call handling proceed
|
|
26
|
+
return false, nil
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Get the type being converted to
|
|
30
|
+
if typ := c.pkg.TypesInfo.TypeOf(exp.Fun); typ != nil {
|
|
31
|
+
// For pointer types, create a typed nil that preserves type information
|
|
32
|
+
if ptrType, ok := typ.(*types.Pointer); ok {
|
|
33
|
+
// Use a qualifier that returns the package name for local types
|
|
34
|
+
// This matches Go's reflect output format (e.g., "main.Stringer")
|
|
35
|
+
qualifier := func(pkg *types.Package) string {
|
|
36
|
+
if pkg == nil {
|
|
37
|
+
return ""
|
|
38
|
+
}
|
|
39
|
+
return pkg.Name()
|
|
40
|
+
}
|
|
41
|
+
typeName := types.TypeString(ptrType, qualifier)
|
|
42
|
+
c.tsw.WriteLiterallyf("$.typedNil(%q)", typeName)
|
|
25
43
|
return true, nil
|
|
26
44
|
}
|
|
27
45
|
}
|
|
28
46
|
|
|
47
|
+
// For non-pointer types (or if type info is unavailable), use plain null
|
|
29
48
|
c.tsw.WriteLiterally("null")
|
|
30
49
|
return true, nil
|
|
31
50
|
}
|
|
@@ -141,8 +160,21 @@ func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
|
141
160
|
|
|
142
161
|
// Handle direct string(int32) conversion
|
|
143
162
|
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
|
|
144
|
-
// Case 3a: Argument is already a string - no-op
|
|
163
|
+
// Case 3a: Argument is already a string - no-op (unless it's a named type with toString)
|
|
145
164
|
if c.isStringType(tv.Type) {
|
|
165
|
+
// Check if this is a named type from the reflect package (like StructTag)
|
|
166
|
+
// which is implemented as a class in TypeScript with a toString() method
|
|
167
|
+
if namedType, isNamed := tv.Type.(*types.Named); isNamed {
|
|
168
|
+
obj := namedType.Obj()
|
|
169
|
+
if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "reflect" && obj.Name() == "StructTag" {
|
|
170
|
+
// Call toString() for reflect.StructTag
|
|
171
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
172
|
+
return fmt.Errorf("failed to write argument for string(reflect.StructTag) conversion: %w", err)
|
|
173
|
+
}
|
|
174
|
+
c.tsw.WriteLiterally(".toString()")
|
|
175
|
+
return nil
|
|
176
|
+
}
|
|
177
|
+
}
|
|
146
178
|
// Translate string(stringValue) to stringValue (no-op)
|
|
147
179
|
if err := c.WriteValueExpr(arg); err != nil {
|
|
148
180
|
return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
|
package/compiler/expr-call.go
CHANGED
|
@@ -5,7 +5,6 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"go/token"
|
|
7
7
|
"go/types"
|
|
8
|
-
"strings"
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
// WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
|
|
@@ -62,7 +61,8 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
62
61
|
// For built-ins that don't return early, write the arguments
|
|
63
62
|
if funIdent.String() != "new" && funIdent.String() != "close" && funIdent.String() != "make" &&
|
|
64
63
|
funIdent.String() != "string" && funIdent.String() != "append" && funIdent.String() != "byte" &&
|
|
65
|
-
funIdent.String() != "int"
|
|
64
|
+
funIdent.String() != "int" && funIdent.String() != "min" && funIdent.String() != "max" &&
|
|
65
|
+
funIdent.String() != "clear" {
|
|
66
66
|
return c.writeCallArguments(exp)
|
|
67
67
|
}
|
|
68
68
|
return nil
|
|
@@ -97,6 +97,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// Handle reflect.TypeFor[T]() - Fun is IndexExpr where X is SelectorExpr
|
|
101
|
+
if indexExpr, ok := expFun.(*ast.IndexExpr); ok {
|
|
102
|
+
if selectorExpr, ok := indexExpr.X.(*ast.SelectorExpr); ok {
|
|
103
|
+
if handled, err := c.writeReflectTypeFor(exp, selectorExpr); handled {
|
|
104
|
+
return err
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
100
109
|
// Handle non-identifier function expressions (method calls, function literals, etc.)
|
|
101
110
|
// Check if this is an async method call (e.g., mu.Lock())
|
|
102
111
|
c.writeAsyncCallIfNeeded(exp)
|
|
@@ -109,14 +118,26 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
109
118
|
}
|
|
110
119
|
c.tsw.WriteLiterally(")")
|
|
111
120
|
} else {
|
|
121
|
+
// Check if this is a function call that returns a function (e.g., simpleIterator(m)())
|
|
122
|
+
// and if the inner call is async, wrap it in parentheses
|
|
123
|
+
innerCallExpr, isCallExpr := expFun.(*ast.CallExpr)
|
|
124
|
+
needsParens := isCallExpr && c.isCallExprAsync(innerCallExpr)
|
|
125
|
+
|
|
126
|
+
if needsParens {
|
|
127
|
+
c.tsw.WriteLiterally("(")
|
|
128
|
+
}
|
|
129
|
+
|
|
112
130
|
// Not an identifier (e.g., method call on a value, function call result)
|
|
113
131
|
if err := c.WriteValueExpr(expFun); err != nil {
|
|
114
132
|
return fmt.Errorf("failed to write method expression in call: %w", err)
|
|
115
133
|
}
|
|
116
134
|
|
|
117
|
-
|
|
135
|
+
if needsParens {
|
|
136
|
+
c.tsw.WriteLiterally(")")
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
// Add non-null assertion since the returned function could be null
|
|
119
|
-
if
|
|
140
|
+
if isCallExpr {
|
|
120
141
|
c.tsw.WriteLiterally("!")
|
|
121
142
|
} else {
|
|
122
143
|
c.addNonNullAssertion(expFun)
|
|
@@ -246,35 +267,6 @@ func (c *GoToTSCompiler) getQualifiedTypeName(t types.Type) string {
|
|
|
246
267
|
return obj.Name()
|
|
247
268
|
}
|
|
248
269
|
|
|
249
|
-
// getImportAlias returns the import alias for a given package path
|
|
250
|
-
// Deprecated: use resolveImportAlias instead for better type safety
|
|
251
|
-
func (c *GoToTSCompiler) getImportAlias(pkgPath string) string {
|
|
252
|
-
if c.analysis == nil {
|
|
253
|
-
return ""
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// First try to find by exact package path
|
|
257
|
-
for importAlias := range c.analysis.Imports {
|
|
258
|
-
if importInfo := c.analysis.Imports[importAlias]; importInfo != nil {
|
|
259
|
-
if importInfo.importPath == pkgPath {
|
|
260
|
-
return importAlias
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Fallback: try to match by package name extracted from path
|
|
266
|
-
parts := strings.Split(pkgPath, "/")
|
|
267
|
-
defaultPkgName := parts[len(parts)-1]
|
|
268
|
-
|
|
269
|
-
for importAlias := range c.analysis.Imports {
|
|
270
|
-
if importAlias == defaultPkgName {
|
|
271
|
-
return importAlias
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return ""
|
|
276
|
-
}
|
|
277
|
-
|
|
278
270
|
// writeAutoWrappedArgument writes an argument, auto-wrapping it if needed based on the expected parameter type
|
|
279
271
|
func (c *GoToTSCompiler) writeAutoWrappedArgument(arg ast.Expr, expectedType types.Type) error {
|
|
280
272
|
// For wrapper types (now type aliases), no auto-wrapping is needed
|
|
@@ -27,10 +27,18 @@ func (c *GoToTSCompiler) WriteSelectorExpr(exp *ast.SelectorExpr) error {
|
|
|
27
27
|
// Check if this is a package selector (e.g., time.Now)
|
|
28
28
|
if pkgIdent, isPkgIdent := exp.X.(*ast.Ident); isPkgIdent {
|
|
29
29
|
if obj := c.pkg.TypesInfo.ObjectOf(pkgIdent); obj != nil {
|
|
30
|
-
if
|
|
30
|
+
if pkgName, isPkg := obj.(*types.PkgName); isPkg {
|
|
31
31
|
// Package selectors should never use .value on the package name
|
|
32
32
|
c.tsw.WriteLiterally(pkgIdent.Name)
|
|
33
33
|
c.tsw.WriteLiterally(".")
|
|
34
|
+
|
|
35
|
+
// Special case: reflect.Pointer should be translated to reflect.Ptr
|
|
36
|
+
// (Go has both names for the same Kind constant)
|
|
37
|
+
if pkgName.Imported().Path() == "reflect" && exp.Sel.Name == "Pointer" {
|
|
38
|
+
c.tsw.WriteLiterally("Ptr")
|
|
39
|
+
return nil
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
// Write the selected identifier, allowing .value if it's a varrefed package variable
|
|
35
43
|
c.WriteIdent(exp.Sel, true)
|
|
36
44
|
return nil
|
|
@@ -122,10 +130,23 @@ func (c *GoToTSCompiler) WriteSelectorExpr(exp *ast.SelectorExpr) error {
|
|
|
122
130
|
|
|
123
131
|
// Fallback / Normal Case (e.g., obj.Field, pkg.Var, method calls)
|
|
124
132
|
// WriteValueExpr handles adding .value for the base variable itself if it's varrefed.
|
|
133
|
+
|
|
134
|
+
// Check if the base expression is an async call - if so, we need to wrap it in parentheses
|
|
135
|
+
// so that await binds correctly: (await asyncFn()).method instead of await asyncFn().method
|
|
136
|
+
needsParensForAsync := false
|
|
137
|
+
if callExpr, isCall := exp.X.(*ast.CallExpr); isCall && c.isCallExprAsync(callExpr) {
|
|
138
|
+
needsParensForAsync = true
|
|
139
|
+
c.tsw.WriteLiterally("(")
|
|
140
|
+
}
|
|
141
|
+
|
|
125
142
|
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
126
143
|
return fmt.Errorf("failed to write selector base expression: %w", err)
|
|
127
144
|
}
|
|
128
145
|
|
|
146
|
+
if needsParensForAsync {
|
|
147
|
+
c.tsw.WriteLiterally(")")
|
|
148
|
+
}
|
|
149
|
+
|
|
129
150
|
// Add null assertion for selector expressions when accessing fields/methods on nullable types
|
|
130
151
|
// In Go, accessing fields or calling methods on nil pointers/interfaces panics, so we should throw in TypeScript
|
|
131
152
|
baseType := c.pkg.TypesInfo.TypeOf(exp.X)
|
|
@@ -189,6 +210,55 @@ func (c *GoToTSCompiler) writeMethodValue(exp *ast.SelectorExpr, selection *type
|
|
|
189
210
|
baseIsPointer = true
|
|
190
211
|
}
|
|
191
212
|
|
|
213
|
+
// Check if the receiver is a primitive/wrapper type
|
|
214
|
+
underlyingRecvType := recvType
|
|
215
|
+
if ptr, ok := recvType.(*types.Pointer); ok {
|
|
216
|
+
underlyingRecvType = ptr.Elem()
|
|
217
|
+
}
|
|
218
|
+
isPrimitiveReceiver := c.isWrapperType(underlyingRecvType)
|
|
219
|
+
|
|
220
|
+
// For primitive types, generate a closure that captures the receiver and calls the free function
|
|
221
|
+
if isPrimitiveReceiver {
|
|
222
|
+
// Get the type name for the free function
|
|
223
|
+
typeName := c.getQualifiedTypeName(underlyingRecvType)
|
|
224
|
+
if typeName == "" {
|
|
225
|
+
return fmt.Errorf("failed to get qualified type name for primitive receiver")
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Get the method parameters to forward them
|
|
229
|
+
params := sig.Params()
|
|
230
|
+
paramNames := make([]string, params.Len())
|
|
231
|
+
for i := 0; i < params.Len(); i++ {
|
|
232
|
+
paramNames[i] = fmt.Sprintf("_p%d", i)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Generate: ((_p0: type0, _p1: type1, ...) => TypeName_MethodName(receiverValue, _p0, _p1, ...))
|
|
236
|
+
c.tsw.WriteLiterally("((")
|
|
237
|
+
for i, name := range paramNames {
|
|
238
|
+
if i > 0 {
|
|
239
|
+
c.tsw.WriteLiterally(", ")
|
|
240
|
+
}
|
|
241
|
+
c.tsw.WriteLiterally(name)
|
|
242
|
+
c.tsw.WriteLiterally(": ")
|
|
243
|
+
c.WriteGoType(params.At(i).Type(), GoTypeContextGeneral)
|
|
244
|
+
}
|
|
245
|
+
c.tsw.WriteLiterally(") => ")
|
|
246
|
+
c.tsw.WriteLiterally(typeName)
|
|
247
|
+
c.tsw.WriteLiterally("_")
|
|
248
|
+
c.tsw.WriteLiterally(exp.Sel.Name)
|
|
249
|
+
c.tsw.WriteLiterally("(")
|
|
250
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
251
|
+
return fmt.Errorf("failed to write method value receiver: %w", err)
|
|
252
|
+
}
|
|
253
|
+
for _, name := range paramNames {
|
|
254
|
+
c.tsw.WriteLiterally(", ")
|
|
255
|
+
c.tsw.WriteLiterally(name)
|
|
256
|
+
}
|
|
257
|
+
c.tsw.WriteLiterally("))")
|
|
258
|
+
|
|
259
|
+
return nil
|
|
260
|
+
}
|
|
261
|
+
|
|
192
262
|
// Write the receiver expression
|
|
193
263
|
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
194
264
|
return fmt.Errorf("failed to write method value receiver: %w", err)
|
package/compiler/expr-type.go
CHANGED
|
@@ -26,13 +26,23 @@ func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
|
|
|
26
26
|
// Check if this is a package selector (e.g., os.FileInfo)
|
|
27
27
|
if obj := c.pkg.TypesInfo.Uses[pkgIdent]; obj != nil {
|
|
28
28
|
if _, isPkg := obj.(*types.PkgName); isPkg {
|
|
29
|
-
// This is a package.Type reference
|
|
29
|
+
// This is a package.Type reference
|
|
30
|
+
typ := c.pkg.TypesInfo.TypeOf(a)
|
|
31
|
+
|
|
32
|
+
// Check if this is an interface type and add null | prefix
|
|
33
|
+
if typ != nil {
|
|
34
|
+
if _, isInterface := typ.Underlying().(*types.Interface); isInterface {
|
|
35
|
+
c.tsw.WriteLiterally("null | ")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Write the qualified name
|
|
30
40
|
c.tsw.WriteLiterally(pkgIdent.Name)
|
|
31
41
|
c.tsw.WriteLiterally(".")
|
|
32
42
|
c.tsw.WriteLiterally(selectorExpr.Sel.Name)
|
|
33
43
|
|
|
34
44
|
// Check if this is a function type and add | null
|
|
35
|
-
if typ
|
|
45
|
+
if typ != nil {
|
|
36
46
|
if namedType, isNamed := typ.(*types.Named); isNamed {
|
|
37
47
|
if _, isSignature := namedType.Underlying().(*types.Signature); isSignature {
|
|
38
48
|
c.tsw.WriteLiterally(" | null")
|
|
@@ -134,11 +144,47 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
|
|
|
134
144
|
c.tsw.WriteLiterally("}")
|
|
135
145
|
}
|
|
136
146
|
} else {
|
|
137
|
-
// For named types,
|
|
147
|
+
// For named types, use the fully qualified name with package path
|
|
148
|
+
if goType != nil {
|
|
149
|
+
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
150
|
+
typeName := namedType.Obj().Name()
|
|
151
|
+
if pkg := namedType.Obj().Pkg(); pkg != nil {
|
|
152
|
+
pkgPath := pkg.Path()
|
|
153
|
+
pkgName := pkg.Name()
|
|
154
|
+
if pkgPath != "" && pkgName != "main" {
|
|
155
|
+
typeName = pkgPath + "." + typeName
|
|
156
|
+
} else if pkgName == "main" {
|
|
157
|
+
typeName = "main." + typeName
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
c.tsw.WriteLiterallyf("'%s'", typeName)
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Fallback to short name if type info unavailable
|
|
138
165
|
c.tsw.WriteLiterallyf("'%s'", t.Name)
|
|
139
166
|
}
|
|
140
167
|
case *ast.SelectorExpr:
|
|
141
168
|
if ident, ok := t.X.(*ast.Ident); ok {
|
|
169
|
+
// Use type info to get the actual package path
|
|
170
|
+
goType := c.pkg.TypesInfo.TypeOf(t)
|
|
171
|
+
if goType != nil {
|
|
172
|
+
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
173
|
+
typeName := namedType.Obj().Name()
|
|
174
|
+
if pkg := namedType.Obj().Pkg(); pkg != nil {
|
|
175
|
+
pkgPath := pkg.Path()
|
|
176
|
+
pkgName := pkg.Name()
|
|
177
|
+
if pkgPath != "" && pkgName != "main" {
|
|
178
|
+
typeName = pkgPath + "." + typeName
|
|
179
|
+
} else if pkgName == "main" {
|
|
180
|
+
typeName = "main." + typeName
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
c.tsw.WriteLiterallyf("'%s'", typeName)
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Fallback to using the identifier name (package alias)
|
|
142
188
|
c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
|
|
143
189
|
}
|
|
144
190
|
case *ast.ArrayType:
|