goscript 0.0.45 → 0.0.48
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 +198 -504
- package/compiler/compiler.go +20 -70
- package/compiler/decl.go +52 -38
- package/compiler/expr-call-async.go +101 -0
- package/compiler/expr-call-builtins.go +133 -0
- package/compiler/expr-call-helpers.go +138 -0
- package/compiler/expr-call-make.go +568 -0
- package/compiler/expr-call-type-conversion.go +424 -0
- package/compiler/expr-call.go +59 -1305
- package/compiler/expr.go +126 -4
- package/compiler/spec-struct.go +22 -9
- package/compiler/spec.go +53 -118
- package/compiler/type.go +51 -0
- package/dist/gs/builtin/builtin.d.ts +3 -1
- package/dist/gs/builtin/builtin.js +6 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +12 -1
- package/dist/gs/io/fs/fs.js +106 -30
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -3
- package/dist/gs/os/types_js.gs.js +2 -1
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js +2 -2
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/gs/builtin/builtin.ts +7 -2
- package/gs/io/fs/fs.ts +100 -31
- package/gs/io/fs/godoc.txt +370 -17
- package/gs/os/types_js.gs.ts +2 -2
- package/gs/os/types_unix.gs.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"go/types"
|
|
7
|
+
|
|
8
|
+
"github.com/pkg/errors"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// hasSliceConstraint checks if an interface constraint includes slice types
|
|
12
|
+
// For constraints like ~[]E, this returns true
|
|
13
|
+
func hasSliceConstraint(iface *types.Interface) bool {
|
|
14
|
+
// Check if the interface has type terms that include slice types
|
|
15
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
16
|
+
embedded := iface.EmbeddedType(i)
|
|
17
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
18
|
+
for j := 0; j < union.Len(); j++ {
|
|
19
|
+
term := union.Term(j)
|
|
20
|
+
if _, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
21
|
+
return true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} else if _, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// getSliceElementTypeFromConstraint extracts the element type from a slice constraint
|
|
32
|
+
// For constraints like ~[]E, this returns E
|
|
33
|
+
func getSliceElementTypeFromConstraint(iface *types.Interface) types.Type {
|
|
34
|
+
// Check if the interface has type terms that include slice types
|
|
35
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
36
|
+
embedded := iface.EmbeddedType(i)
|
|
37
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
38
|
+
for j := 0; j < union.Len(); j++ {
|
|
39
|
+
term := union.Term(j)
|
|
40
|
+
if sliceType, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
41
|
+
return sliceType.Elem()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else if sliceType, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
45
|
+
return sliceType.Elem()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return nil
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// hasMixedStringByteConstraint checks if an interface constraint includes both string and []byte types
|
|
52
|
+
// For constraints like string | []byte, this returns true
|
|
53
|
+
// For pure slice constraints like ~[]E, this returns false
|
|
54
|
+
func hasMixedStringByteConstraint(iface *types.Interface) bool {
|
|
55
|
+
hasString := false
|
|
56
|
+
hasByteSlice := false
|
|
57
|
+
|
|
58
|
+
// Check if the interface has type terms that include both string and []byte
|
|
59
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
60
|
+
embedded := iface.EmbeddedType(i)
|
|
61
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
62
|
+
for j := 0; j < union.Len(); j++ {
|
|
63
|
+
term := union.Term(j)
|
|
64
|
+
termType := term.Type().Underlying()
|
|
65
|
+
|
|
66
|
+
// Check for string type
|
|
67
|
+
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
68
|
+
hasString = true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for []byte type
|
|
72
|
+
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
73
|
+
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
74
|
+
hasByteSlice = true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
// Handle non-union embedded types
|
|
80
|
+
termType := embedded.Underlying()
|
|
81
|
+
|
|
82
|
+
// Check for string type
|
|
83
|
+
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
84
|
+
hasString = true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check for []byte type
|
|
88
|
+
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
89
|
+
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
90
|
+
hasByteSlice = true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Return true only if we have both string and []byte in the constraint
|
|
97
|
+
return hasString && hasByteSlice
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// getTypeHintForSliceElement returns the appropriate type hint for makeSlice based on the Go element type
|
|
101
|
+
func (c *GoToTSCompiler) getTypeHintForSliceElement(elemType types.Type) string {
|
|
102
|
+
if basicType, isBasic := elemType.(*types.Basic); isBasic {
|
|
103
|
+
switch basicType.Kind() {
|
|
104
|
+
case types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
|
|
105
|
+
types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64,
|
|
106
|
+
types.Float32, types.Float64, types.Complex64, types.Complex128:
|
|
107
|
+
return "number"
|
|
108
|
+
case types.Bool:
|
|
109
|
+
return "boolean"
|
|
110
|
+
case types.String:
|
|
111
|
+
return "string"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// For other types (structs, interfaces, pointers, etc.), don't provide a hint
|
|
115
|
+
// This will use the default null initialization which is appropriate for object types
|
|
116
|
+
return ""
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// WriteCallExprMake handles make() function calls and translates them to TypeScript.
|
|
120
|
+
// It handles channel, map, and slice creation with different type patterns including:
|
|
121
|
+
// - Channel creation with different directions
|
|
122
|
+
// - Map creation for various type patterns
|
|
123
|
+
// - Slice creation with special handling for []byte, generic types, named types, instantiated generics, and selector expressions
|
|
124
|
+
func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
|
|
125
|
+
// First check if we have a channel type
|
|
126
|
+
if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
|
|
127
|
+
if chanType, ok := typ.Underlying().(*types.Chan); ok {
|
|
128
|
+
// Handle channel creation: make(chan T, bufferSize) or make(chan T)
|
|
129
|
+
c.tsw.WriteLiterally("$.makeChannel<")
|
|
130
|
+
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
131
|
+
c.tsw.WriteLiterally(">(")
|
|
132
|
+
|
|
133
|
+
// If buffer size is provided, add it
|
|
134
|
+
if len(exp.Args) >= 2 {
|
|
135
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
136
|
+
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
// Default to 0 (unbuffered channel)
|
|
140
|
+
c.tsw.WriteLiterally("0")
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
144
|
+
|
|
145
|
+
// Write the zero value for the channel's element type
|
|
146
|
+
if chanType.Elem().String() == "struct{}" {
|
|
147
|
+
c.tsw.WriteLiterally("{}")
|
|
148
|
+
} else {
|
|
149
|
+
c.WriteZeroValueForType(chanType.Elem())
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Add direction parameter
|
|
153
|
+
c.tsw.WriteLiterally(", ")
|
|
154
|
+
|
|
155
|
+
// Determine channel direction
|
|
156
|
+
switch chanType.Dir() {
|
|
157
|
+
case types.SendRecv:
|
|
158
|
+
c.tsw.WriteLiterally("'both'")
|
|
159
|
+
case types.SendOnly:
|
|
160
|
+
c.tsw.WriteLiterally("'send'")
|
|
161
|
+
case types.RecvOnly:
|
|
162
|
+
c.tsw.WriteLiterally("'receive'")
|
|
163
|
+
default:
|
|
164
|
+
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
c.tsw.WriteLiterally(")")
|
|
168
|
+
return nil // Handled make for channel
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Handle make for slices: make([]T, len, cap) or make([]T, len)
|
|
172
|
+
if len(exp.Args) >= 1 {
|
|
173
|
+
// Handle map creation: make(map[K]V)
|
|
174
|
+
if mapType, ok := exp.Args[0].(*ast.MapType); ok {
|
|
175
|
+
c.tsw.WriteLiterally("$.makeMap<")
|
|
176
|
+
c.WriteTypeExpr(mapType.Key) // Write the key type
|
|
177
|
+
c.tsw.WriteLiterally(", ")
|
|
178
|
+
c.WriteTypeExpr(mapType.Value) // Write the value type
|
|
179
|
+
c.tsw.WriteLiterally(">()")
|
|
180
|
+
return nil // Handled make for map
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Handle slice creation
|
|
184
|
+
if _, ok := exp.Args[0].(*ast.ArrayType); ok {
|
|
185
|
+
// Get the slice type information
|
|
186
|
+
sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
|
|
187
|
+
if sliceType == nil {
|
|
188
|
+
return errors.New("could not get type information for slice in make call")
|
|
189
|
+
}
|
|
190
|
+
goUnderlyingType, ok := sliceType.Underlying().(*types.Slice)
|
|
191
|
+
if !ok {
|
|
192
|
+
return errors.New("expected slice type for make call")
|
|
193
|
+
}
|
|
194
|
+
goElemType := goUnderlyingType.Elem()
|
|
195
|
+
|
|
196
|
+
// Check if it's make([]byte, ...)
|
|
197
|
+
if c.isByteSliceType(sliceType) {
|
|
198
|
+
var lengthArg, capacityArg interface{}
|
|
199
|
+
if len(exp.Args) >= 2 {
|
|
200
|
+
lengthArg = exp.Args[1]
|
|
201
|
+
}
|
|
202
|
+
if len(exp.Args) == 3 {
|
|
203
|
+
capacityArg = exp.Args[2]
|
|
204
|
+
}
|
|
205
|
+
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Check if the element type is a generic type parameter
|
|
209
|
+
if _, isTypeParam := goElemType.(*types.TypeParam); isTypeParam {
|
|
210
|
+
// This is make([]E, n) where E is a type parameter
|
|
211
|
+
c.tsw.WriteLiterally("$.makeSlice<")
|
|
212
|
+
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type parameter
|
|
213
|
+
c.tsw.WriteLiterally(">(")
|
|
214
|
+
|
|
215
|
+
if len(exp.Args) >= 2 {
|
|
216
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
217
|
+
return err
|
|
218
|
+
}
|
|
219
|
+
if len(exp.Args) == 3 {
|
|
220
|
+
c.tsw.WriteLiterally(", ")
|
|
221
|
+
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
222
|
+
return err
|
|
223
|
+
}
|
|
224
|
+
} else if len(exp.Args) > 3 {
|
|
225
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// If no length is provided, default to 0
|
|
229
|
+
c.tsw.WriteLiterally("0")
|
|
230
|
+
}
|
|
231
|
+
c.tsw.WriteLiterally(")")
|
|
232
|
+
return nil // Handled make for []E where E is type parameter
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var lengthArg, capacityArg interface{}
|
|
236
|
+
if len(exp.Args) >= 2 {
|
|
237
|
+
lengthArg = exp.Args[1]
|
|
238
|
+
}
|
|
239
|
+
if len(exp.Args) == 3 {
|
|
240
|
+
capacityArg = exp.Args[2]
|
|
241
|
+
} else if len(exp.Args) > 3 {
|
|
242
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return c.writeGenericSliceCreation(goElemType, lengthArg, capacityArg)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Handle generic type parameter make calls: make(S, len, cap) where S ~[]E
|
|
249
|
+
if ident, ok := exp.Args[0].(*ast.Ident); ok {
|
|
250
|
+
// Check if this identifier refers to a type parameter
|
|
251
|
+
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
252
|
+
if typeName, isTypeName := obj.(*types.TypeName); isTypeName {
|
|
253
|
+
if typeParam, isTypeParam := typeName.Type().(*types.TypeParam); isTypeParam {
|
|
254
|
+
// Check if the type parameter is constrained to slice types
|
|
255
|
+
constraint := typeParam.Constraint()
|
|
256
|
+
if constraint != nil {
|
|
257
|
+
underlying := constraint.Underlying()
|
|
258
|
+
if iface, isInterface := underlying.(*types.Interface); isInterface {
|
|
259
|
+
// Check if the constraint includes slice types
|
|
260
|
+
// For constraints like ~[]E, we need to look at the type terms
|
|
261
|
+
if hasSliceConstraint(iface) {
|
|
262
|
+
// This is a generic slice type parameter
|
|
263
|
+
// We need to determine the element type from the constraint
|
|
264
|
+
elemType := getSliceElementTypeFromConstraint(iface)
|
|
265
|
+
if elemType != nil {
|
|
266
|
+
// Check if it's make(S, ...) where S constrains to []byte
|
|
267
|
+
if c.isByteSliceType(types.NewSlice(elemType)) {
|
|
268
|
+
var lengthArg, capacityArg interface{}
|
|
269
|
+
if len(exp.Args) >= 2 {
|
|
270
|
+
lengthArg = exp.Args[1]
|
|
271
|
+
}
|
|
272
|
+
if len(exp.Args) == 3 {
|
|
273
|
+
capacityArg = exp.Args[2]
|
|
274
|
+
}
|
|
275
|
+
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
var lengthArg, capacityArg interface{}
|
|
279
|
+
if len(exp.Args) >= 2 {
|
|
280
|
+
lengthArg = exp.Args[1]
|
|
281
|
+
}
|
|
282
|
+
if len(exp.Args) == 3 {
|
|
283
|
+
capacityArg = exp.Args[2]
|
|
284
|
+
} else if len(exp.Args) > 3 {
|
|
285
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
286
|
+
}
|
|
287
|
+
return c.writeGenericSliceCreation(elemType, lengthArg, capacityArg)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
// Handle named types with slice underlying types: make(NamedSliceType, len, cap)
|
|
294
|
+
// This handles cases like: type appendSliceWriter []byte; make(appendSliceWriter, 0, len(s))
|
|
295
|
+
namedType := typeName.Type()
|
|
296
|
+
if sliceType, isSlice := namedType.Underlying().(*types.Slice); isSlice {
|
|
297
|
+
goElemType := sliceType.Elem()
|
|
298
|
+
|
|
299
|
+
// Check if it's a named type with []byte underlying type
|
|
300
|
+
if c.isByteSliceType(sliceType) {
|
|
301
|
+
var lengthArg, capacityArg interface{}
|
|
302
|
+
if len(exp.Args) >= 2 {
|
|
303
|
+
lengthArg = exp.Args[1]
|
|
304
|
+
}
|
|
305
|
+
if len(exp.Args) == 3 {
|
|
306
|
+
capacityArg = exp.Args[2]
|
|
307
|
+
}
|
|
308
|
+
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Handle other named slice types
|
|
312
|
+
var lengthArg, capacityArg interface{}
|
|
313
|
+
if len(exp.Args) >= 2 {
|
|
314
|
+
lengthArg = exp.Args[1]
|
|
315
|
+
}
|
|
316
|
+
if len(exp.Args) == 3 {
|
|
317
|
+
capacityArg = exp.Args[2]
|
|
318
|
+
} else if len(exp.Args) > 3 {
|
|
319
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
320
|
+
}
|
|
321
|
+
return c.writeGenericSliceCreation(goElemType, lengthArg, capacityArg)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Handle named types with map underlying types: make(NamedMapType)
|
|
325
|
+
if mapType, isMap := namedType.Underlying().(*types.Map); isMap {
|
|
326
|
+
c.tsw.WriteLiterally("$.makeMap<")
|
|
327
|
+
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
328
|
+
c.tsw.WriteLiterally(", ")
|
|
329
|
+
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
330
|
+
c.tsw.WriteLiterally(">()")
|
|
331
|
+
return nil // Handled make for named map type
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Handle named types with channel underlying types: make(NamedChannelType, bufferSize)
|
|
335
|
+
if chanType, isChan := namedType.Underlying().(*types.Chan); isChan {
|
|
336
|
+
c.tsw.WriteLiterally("$.makeChannel<")
|
|
337
|
+
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
338
|
+
c.tsw.WriteLiterally(">(")
|
|
339
|
+
|
|
340
|
+
// If buffer size is provided, add it
|
|
341
|
+
if len(exp.Args) >= 2 {
|
|
342
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
343
|
+
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
// Default to 0 (unbuffered channel)
|
|
347
|
+
c.tsw.WriteLiterally("0")
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
351
|
+
|
|
352
|
+
// Write the zero value for the channel's element type
|
|
353
|
+
if chanType.Elem().String() == "struct{}" {
|
|
354
|
+
c.tsw.WriteLiterally("{}")
|
|
355
|
+
} else {
|
|
356
|
+
c.WriteZeroValueForType(chanType.Elem())
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Add direction parameter
|
|
360
|
+
c.tsw.WriteLiterally(", ")
|
|
361
|
+
|
|
362
|
+
// Determine channel direction
|
|
363
|
+
switch chanType.Dir() {
|
|
364
|
+
case types.SendRecv:
|
|
365
|
+
c.tsw.WriteLiterally("'both'")
|
|
366
|
+
case types.SendOnly:
|
|
367
|
+
c.tsw.WriteLiterally("'send'")
|
|
368
|
+
case types.RecvOnly:
|
|
369
|
+
c.tsw.WriteLiterally("'receive'")
|
|
370
|
+
default:
|
|
371
|
+
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
c.tsw.WriteLiterally(")")
|
|
375
|
+
return nil // Handled make for named channel type
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Handle instantiated generic types: make(GenericType[TypeArg], ...)
|
|
383
|
+
// This handles cases like: make(Ints[int64]) where Ints[T] is a generic type
|
|
384
|
+
if indexExpr, ok := exp.Args[0].(*ast.IndexExpr); ok {
|
|
385
|
+
// Get the type information for the instantiated generic type
|
|
386
|
+
if typ := c.pkg.TypesInfo.TypeOf(indexExpr); typ != nil {
|
|
387
|
+
// Check the underlying type of the instantiated generic type
|
|
388
|
+
underlying := typ.Underlying()
|
|
389
|
+
|
|
390
|
+
// Handle instantiated generic map types: make(GenericMap[K, V])
|
|
391
|
+
if mapType, isMap := underlying.(*types.Map); isMap {
|
|
392
|
+
c.tsw.WriteLiterally("$.makeMap<")
|
|
393
|
+
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
394
|
+
c.tsw.WriteLiterally(", ")
|
|
395
|
+
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
396
|
+
c.tsw.WriteLiterally(">()")
|
|
397
|
+
return nil // Handled make for instantiated generic map type
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Handle instantiated generic slice types: make(GenericSlice[T], len, cap)
|
|
401
|
+
if sliceType, isSlice := underlying.(*types.Slice); isSlice {
|
|
402
|
+
goElemType := sliceType.Elem()
|
|
403
|
+
|
|
404
|
+
// Check if it's an instantiated generic type with []byte underlying type
|
|
405
|
+
if c.isByteSliceType(types.NewSlice(goElemType)) {
|
|
406
|
+
var lengthArg, capacityArg interface{}
|
|
407
|
+
if len(exp.Args) >= 2 {
|
|
408
|
+
lengthArg = exp.Args[1]
|
|
409
|
+
}
|
|
410
|
+
if len(exp.Args) == 3 {
|
|
411
|
+
capacityArg = exp.Args[2]
|
|
412
|
+
}
|
|
413
|
+
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Handle other instantiated generic slice types
|
|
417
|
+
var lengthArg, capacityArg interface{}
|
|
418
|
+
if len(exp.Args) >= 2 {
|
|
419
|
+
lengthArg = exp.Args[1]
|
|
420
|
+
}
|
|
421
|
+
if len(exp.Args) == 3 {
|
|
422
|
+
capacityArg = exp.Args[2]
|
|
423
|
+
} else if len(exp.Args) > 3 {
|
|
424
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
425
|
+
}
|
|
426
|
+
return c.writeGenericSliceCreation(goElemType, lengthArg, capacityArg)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Handle instantiated generic channel types: make(GenericChannel[T], bufferSize)
|
|
430
|
+
if chanType, isChan := underlying.(*types.Chan); isChan {
|
|
431
|
+
c.tsw.WriteLiterally("$.makeChannel<")
|
|
432
|
+
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
433
|
+
c.tsw.WriteLiterally(">(")
|
|
434
|
+
|
|
435
|
+
// If buffer size is provided, add it
|
|
436
|
+
if len(exp.Args) >= 2 {
|
|
437
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
438
|
+
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
439
|
+
}
|
|
440
|
+
} else {
|
|
441
|
+
// Default to 0 (unbuffered channel)
|
|
442
|
+
c.tsw.WriteLiterally("0")
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
446
|
+
|
|
447
|
+
// Write the zero value for the channel's element type
|
|
448
|
+
if chanType.Elem().String() == "struct{}" {
|
|
449
|
+
c.tsw.WriteLiterally("{}")
|
|
450
|
+
} else {
|
|
451
|
+
c.WriteZeroValueForType(chanType.Elem())
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Add direction parameter
|
|
455
|
+
c.tsw.WriteLiterally(", ")
|
|
456
|
+
|
|
457
|
+
// Determine channel direction
|
|
458
|
+
switch chanType.Dir() {
|
|
459
|
+
case types.SendRecv:
|
|
460
|
+
c.tsw.WriteLiterally("'both'")
|
|
461
|
+
case types.SendOnly:
|
|
462
|
+
c.tsw.WriteLiterally("'send'")
|
|
463
|
+
case types.RecvOnly:
|
|
464
|
+
c.tsw.WriteLiterally("'receive'")
|
|
465
|
+
default:
|
|
466
|
+
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
c.tsw.WriteLiterally(")")
|
|
470
|
+
return nil // Handled make for instantiated generic channel type
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// Handle selector expressions: make(pkg.TypeName, ...)
|
|
475
|
+
// This handles cases like: make(fstest.MapFS) where fstest.MapFS is map[string]*MapFile
|
|
476
|
+
if selectorExpr, ok := exp.Args[0].(*ast.SelectorExpr); ok {
|
|
477
|
+
// Get the type information for the selector expression
|
|
478
|
+
if typ := c.pkg.TypesInfo.TypeOf(selectorExpr); typ != nil {
|
|
479
|
+
// Check the underlying type of the selector expression
|
|
480
|
+
underlying := typ.Underlying()
|
|
481
|
+
|
|
482
|
+
// Handle selector expression map types: make(pkg.MapType)
|
|
483
|
+
if mapType, isMap := underlying.(*types.Map); isMap {
|
|
484
|
+
c.tsw.WriteLiterally("$.makeMap<")
|
|
485
|
+
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
486
|
+
c.tsw.WriteLiterally(", ")
|
|
487
|
+
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
488
|
+
c.tsw.WriteLiterally(">()")
|
|
489
|
+
return nil // Handled make for selector expression map type
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Handle selector expression slice types: make(pkg.SliceType, len, cap)
|
|
493
|
+
if sliceType, isSlice := underlying.(*types.Slice); isSlice {
|
|
494
|
+
goElemType := sliceType.Elem()
|
|
495
|
+
|
|
496
|
+
// Check if it's a selector expression with []byte underlying type
|
|
497
|
+
if c.isByteSliceType(sliceType) {
|
|
498
|
+
var lengthArg, capacityArg interface{}
|
|
499
|
+
if len(exp.Args) >= 2 {
|
|
500
|
+
lengthArg = exp.Args[1]
|
|
501
|
+
}
|
|
502
|
+
if len(exp.Args) == 3 {
|
|
503
|
+
capacityArg = exp.Args[2]
|
|
504
|
+
}
|
|
505
|
+
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Handle other selector expression slice types
|
|
509
|
+
var lengthArg, capacityArg interface{}
|
|
510
|
+
if len(exp.Args) >= 2 {
|
|
511
|
+
lengthArg = exp.Args[1]
|
|
512
|
+
}
|
|
513
|
+
if len(exp.Args) == 3 {
|
|
514
|
+
capacityArg = exp.Args[2]
|
|
515
|
+
} else if len(exp.Args) > 3 {
|
|
516
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
517
|
+
}
|
|
518
|
+
return c.writeGenericSliceCreation(goElemType, lengthArg, capacityArg)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Handle selector expression channel types: make(pkg.ChannelType, bufferSize)
|
|
522
|
+
if chanType, isChan := underlying.(*types.Chan); isChan {
|
|
523
|
+
c.tsw.WriteLiterally("$.makeChannel<")
|
|
524
|
+
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
525
|
+
c.tsw.WriteLiterally(">(")
|
|
526
|
+
|
|
527
|
+
// If buffer size is provided, add it
|
|
528
|
+
if len(exp.Args) >= 2 {
|
|
529
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
530
|
+
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
531
|
+
}
|
|
532
|
+
} else {
|
|
533
|
+
// Default to 0 (unbuffered channel)
|
|
534
|
+
c.tsw.WriteLiterally("0")
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
538
|
+
|
|
539
|
+
// Write the zero value for the channel's element type
|
|
540
|
+
if chanType.Elem().String() == "struct{}" {
|
|
541
|
+
c.tsw.WriteLiterally("{}")
|
|
542
|
+
} else {
|
|
543
|
+
c.WriteZeroValueForType(chanType.Elem())
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Add direction parameter
|
|
547
|
+
c.tsw.WriteLiterally(", ")
|
|
548
|
+
|
|
549
|
+
// Determine channel direction
|
|
550
|
+
switch chanType.Dir() {
|
|
551
|
+
case types.SendRecv:
|
|
552
|
+
c.tsw.WriteLiterally("'both'")
|
|
553
|
+
case types.SendOnly:
|
|
554
|
+
c.tsw.WriteLiterally("'send'")
|
|
555
|
+
case types.RecvOnly:
|
|
556
|
+
c.tsw.WriteLiterally("'receive'")
|
|
557
|
+
default:
|
|
558
|
+
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
c.tsw.WriteLiterally(")")
|
|
562
|
+
return nil // Handled make for selector expression channel type
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Fallthrough for unhandled make calls (e.g., channels)
|
|
567
|
+
return errors.New("unhandled make call")
|
|
568
|
+
}
|