goscript 0.0.58 → 0.0.60

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 (44) hide show
  1. package/README.md +40 -33
  2. package/compiler/analysis.go +184 -43
  3. package/compiler/assignment.go +163 -217
  4. package/compiler/compiler.go +35 -31
  5. package/compiler/composite-lit.go +233 -196
  6. package/compiler/constraint.go +88 -0
  7. package/compiler/decl.go +82 -24
  8. package/compiler/expr-call-async.go +20 -34
  9. package/compiler/expr-call-builtins.go +19 -0
  10. package/compiler/expr-call-helpers.go +0 -28
  11. package/compiler/expr-call-make.go +93 -343
  12. package/compiler/expr-call-type-conversion.go +221 -249
  13. package/compiler/expr-call.go +70 -69
  14. package/compiler/expr-selector.go +21 -24
  15. package/compiler/expr.go +3 -60
  16. package/compiler/protobuf.go +180 -36
  17. package/compiler/spec-value.go +132 -24
  18. package/compiler/spec.go +14 -55
  19. package/compiler/stmt-assign.go +338 -356
  20. package/compiler/stmt-range.go +4 -24
  21. package/compiler/stmt.go +92 -203
  22. package/compiler/type-utils.go +185 -0
  23. package/compiler/type.go +26 -80
  24. package/dist/gs/builtin/slice.d.ts +1 -1
  25. package/dist/gs/builtin/slice.js +3 -0
  26. package/dist/gs/builtin/slice.js.map +1 -1
  27. package/dist/gs/builtin/type.js +8 -2
  28. package/dist/gs/builtin/type.js.map +1 -1
  29. package/dist/gs/fmt/fmt.js +113 -16
  30. package/dist/gs/fmt/fmt.js.map +1 -1
  31. package/dist/gs/runtime/runtime.d.ts +1 -1
  32. package/dist/gs/runtime/runtime.js +1 -1
  33. package/dist/gs/slices/slices.d.ts +23 -0
  34. package/dist/gs/slices/slices.js +61 -0
  35. package/dist/gs/slices/slices.js.map +1 -1
  36. package/go.mod +10 -10
  37. package/go.sum +22 -14
  38. package/gs/builtin/slice.ts +5 -2
  39. package/gs/builtin/type.ts +13 -6
  40. package/gs/fmt/fmt.test.ts +176 -0
  41. package/gs/fmt/fmt.ts +109 -18
  42. package/gs/runtime/runtime.ts +1 -1
  43. package/gs/slices/slices.ts +68 -0
  44. package/package.json +3 -3
@@ -8,95 +8,6 @@ import (
8
8
  "github.com/pkg/errors"
9
9
  )
10
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
11
  // getTypeHintForSliceElement returns the appropriate type hint for makeSlice based on the Go element type
101
12
  func (c *GoToTSCompiler) getTypeHintForSliceElement(elemType types.Type) string {
102
13
  if basicType, isBasic := elemType.(*types.Basic); isBasic {
@@ -116,6 +27,81 @@ func (c *GoToTSCompiler) getTypeHintForSliceElement(elemType types.Type) string
116
27
  return ""
117
28
  }
118
29
 
30
+ // writeMakeChannel writes the TypeScript code for creating a channel with $.makeChannel
31
+ // It handles buffer size, zero value, and direction parameters
32
+ func (c *GoToTSCompiler) writeMakeChannel(chanType *types.Chan, bufferArg ast.Expr) error {
33
+ c.tsw.WriteLiterally("$.makeChannel<")
34
+ c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
35
+ c.tsw.WriteLiterally(">(")
36
+
37
+ // If buffer size is provided, add it
38
+ if bufferArg != nil {
39
+ if err := c.WriteValueExpr(bufferArg); err != nil {
40
+ return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
41
+ }
42
+ } else {
43
+ // Default to 0 (unbuffered channel)
44
+ c.tsw.WriteLiterally("0")
45
+ }
46
+
47
+ c.tsw.WriteLiterally(", ") // Add comma for zero value argument
48
+
49
+ // Write the zero value for the channel's element type
50
+ if chanType.Elem().String() == "struct{}" {
51
+ c.tsw.WriteLiterally("{}")
52
+ } else {
53
+ c.WriteZeroValueForType(chanType.Elem())
54
+ }
55
+
56
+ // Add direction parameter
57
+ c.tsw.WriteLiterally(", ")
58
+
59
+ // Determine channel direction
60
+ switch chanType.Dir() {
61
+ case types.SendRecv:
62
+ c.tsw.WriteLiterally("'both'")
63
+ case types.SendOnly:
64
+ c.tsw.WriteLiterally("'send'")
65
+ case types.RecvOnly:
66
+ c.tsw.WriteLiterally("'receive'")
67
+ default:
68
+ c.tsw.WriteLiterally("'both'") // Default to bidirectional
69
+ }
70
+
71
+ c.tsw.WriteLiterally(")")
72
+ return nil
73
+ }
74
+
75
+ // writeMakeSlice writes the TypeScript code for creating a slice
76
+ // It handles []byte special case and generic slice creation
77
+ func (c *GoToTSCompiler) writeMakeSlice(sliceType *types.Slice, exp *ast.CallExpr) error {
78
+ goElemType := sliceType.Elem()
79
+
80
+ // Check if it's []byte
81
+ if c.isByteSliceType(sliceType) {
82
+ var lengthArg, capacityArg interface{}
83
+ if len(exp.Args) >= 2 {
84
+ lengthArg = exp.Args[1]
85
+ }
86
+ if len(exp.Args) == 3 {
87
+ capacityArg = exp.Args[2]
88
+ }
89
+ return c.writeByteSliceCreation(lengthArg, capacityArg)
90
+ }
91
+
92
+ // Handle other slice types
93
+ var lengthArg, capacityArg interface{}
94
+ if len(exp.Args) >= 2 {
95
+ lengthArg = exp.Args[1]
96
+ }
97
+ if len(exp.Args) == 3 {
98
+ capacityArg = exp.Args[2]
99
+ } else if len(exp.Args) > 3 {
100
+ return errors.New("makeSlice expects 2 or 3 arguments")
101
+ }
102
+ return c.writeGenericSliceCreation(goElemType, lengthArg, capacityArg)
103
+ }
104
+
119
105
  // WriteCallExprMake handles make() function calls and translates them to TypeScript.
120
106
  // It handles channel, map, and slice creation with different type patterns including:
121
107
  // - Channel creation with different directions
@@ -126,46 +112,11 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
126
112
  if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
127
113
  if chanType, ok := typ.Underlying().(*types.Chan); ok {
128
114
  // 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
115
+ var bufferArg ast.Expr
134
116
  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")
117
+ bufferArg = exp.Args[1]
141
118
  }
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
119
+ return c.writeMakeChannel(chanType, bufferArg)
169
120
  }
170
121
  }
171
122
  // Handle make for slices: make([]T, len, cap) or make([]T, len)
@@ -191,25 +142,12 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
191
142
  if !ok {
192
143
  return errors.New("expected slice type for make call")
193
144
  }
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
145
 
208
146
  // Check if the element type is a generic type parameter
209
- if _, isTypeParam := goElemType.(*types.TypeParam); isTypeParam {
147
+ if _, isTypeParam := goUnderlyingType.Elem().(*types.TypeParam); isTypeParam {
210
148
  // This is make([]E, n) where E is a type parameter
211
149
  c.tsw.WriteLiterally("$.makeSlice<")
212
- c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type parameter
150
+ c.WriteGoType(goUnderlyingType.Elem(), GoTypeContextGeneral) // Write the element type parameter
213
151
  c.tsw.WriteLiterally(">(")
214
152
 
215
153
  if len(exp.Args) >= 2 {
@@ -232,17 +170,7 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
232
170
  return nil // Handled make for []E where E is type parameter
233
171
  }
234
172
 
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)
173
+ return c.writeMakeSlice(goUnderlyingType, exp)
246
174
  }
247
175
 
248
176
  // Handle generic type parameter make calls: make(S, len, cap) where S ~[]E
@@ -291,34 +219,9 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
291
219
  }
292
220
  } else {
293
221
  // 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
222
  namedType := typeName.Type()
296
223
  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)
224
+ return c.writeMakeSlice(sliceType, exp)
322
225
  }
323
226
 
324
227
  // Handle named types with map underlying types: make(NamedMapType)
@@ -333,46 +236,11 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
333
236
 
334
237
  // Handle named types with channel underlying types: make(NamedChannelType, bufferSize)
335
238
  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
239
+ var bufferArg ast.Expr
341
240
  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
241
+ bufferArg = exp.Args[1]
372
242
  }
373
-
374
- c.tsw.WriteLiterally(")")
375
- return nil // Handled make for named channel type
243
+ return c.writeMakeChannel(chanType, bufferArg)
376
244
  }
377
245
  }
378
246
  }
@@ -399,75 +267,16 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
399
267
 
400
268
  // Handle instantiated generic slice types: make(GenericSlice[T], len, cap)
401
269
  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)
270
+ return c.writeMakeSlice(sliceType, exp)
427
271
  }
428
272
 
429
273
  // Handle instantiated generic channel types: make(GenericChannel[T], bufferSize)
430
274
  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
275
+ var bufferArg ast.Expr
436
276
  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")
277
+ bufferArg = exp.Args[1]
443
278
  }
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
279
+ return c.writeMakeChannel(chanType, bufferArg)
471
280
  }
472
281
  }
473
282
  }
@@ -491,75 +300,16 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
491
300
 
492
301
  // Handle selector expression slice types: make(pkg.SliceType, len, cap)
493
302
  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)
303
+ return c.writeMakeSlice(sliceType, exp)
519
304
  }
520
305
 
521
306
  // Handle selector expression channel types: make(pkg.ChannelType, bufferSize)
522
307
  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
308
+ var bufferArg ast.Expr
528
309
  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
310
+ bufferArg = exp.Args[1]
559
311
  }
560
-
561
- c.tsw.WriteLiterally(")")
562
- return nil // Handled make for selector expression channel type
312
+ return c.writeMakeChannel(chanType, bufferArg)
563
313
  }
564
314
  }
565
315
  }