goscript 0.0.57 → 0.0.59

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 +115 -19
  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 +418 -7
  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 +99 -172
  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 +8 -8
  37. package/go.sum +14 -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
@@ -79,11 +79,7 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
79
79
  // Check if it's a []byte literal
80
80
  isByteSliceLiteral := false
81
81
  if typInfo := c.pkg.TypesInfo.TypeOf(exp.Type); typInfo != nil {
82
- if sliceT, ok := typInfo.Underlying().(*types.Slice); ok {
83
- if basicElem, ok := sliceT.Elem().(*types.Basic); ok && basicElem.Kind() == types.Uint8 {
84
- isByteSliceLiteral = true
85
- }
86
- }
82
+ isByteSliceLiteral = c.isByteSliceType(typInfo)
87
83
  }
88
84
 
89
85
  if isByteSliceLiteral {
@@ -287,96 +283,12 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
287
283
 
288
284
  if isStructLiteral && structType != nil {
289
285
  // --- Struct Literal Handling (Nested) ---
290
- directFields := make(map[string]ast.Expr)
291
- embeddedFields := make(map[string]map[string]ast.Expr) // map[EmbeddedPropName]map[FieldName]ValueExpr
292
- explicitEmbedded := make(map[string]ast.Expr) // Tracks explicitly initialized embedded structs
293
-
294
- // Pre-populate embeddedFields map keys using the correct property name
295
- for i := 0; i < structType.NumFields(); i++ {
296
- field := structType.Field(i)
297
- if field.Anonymous() {
298
- fieldType := field.Type()
299
- if ptr, ok := fieldType.(*types.Pointer); ok {
300
- fieldType = ptr.Elem()
301
- }
302
- if named, ok := fieldType.(*types.Named); ok {
303
- // Use the type name as the property name in TS
304
- embeddedPropName := named.Obj().Name()
305
- embeddedFields[embeddedPropName] = make(map[string]ast.Expr)
306
- }
307
- }
308
- }
309
-
310
- // Group literal elements by direct vs embedded fields
311
- for _, elt := range exp.Elts {
312
- kv, ok := elt.(*ast.KeyValueExpr)
313
- if !ok {
314
- continue
315
- } // Skip non-key-value
316
- keyIdent, ok := kv.Key.(*ast.Ident)
317
- if !ok {
318
- continue
319
- } // Skip non-ident keys
320
- keyName := keyIdent.Name
321
-
322
- // Check if this is an explicit embedded struct initialization
323
- // e.g., Person: Person{...} or Person: personVar
324
- if _, isEmbedded := embeddedFields[keyName]; isEmbedded {
325
- // This is an explicit initialization of an embedded struct
326
- explicitEmbedded[keyName] = kv.Value
327
- continue
328
- }
329
-
330
- isDirectField := false
331
- for i := range structType.NumFields() {
332
- field := structType.Field(i)
333
- if field.Name() == keyName {
334
- isDirectField = true
335
- directFields[keyName] = kv.Value
336
- break
337
- }
338
- }
339
-
340
- // For anonymous structs, all fields are direct fields
341
- if isAnonymousStruct {
342
- directFields[keyName] = kv.Value
343
- isDirectField = true
344
- }
345
-
346
- // If not a direct field, return an error
347
- if !isDirectField {
348
- // This field was not found as a direct field in the struct
349
- return fmt.Errorf("field %s not found in type %s for composite literal",
350
- keyName, litType.String())
351
- }
352
- }
353
-
354
- // Handle the case where an anonymous struct has values without keys
355
- // This block processes non-key-value elements and associates them with struct fields.
356
- if isAnonymousStruct && len(exp.Elts) > 0 && len(directFields) == 0 {
357
- // Check if any elements in the composite literal are not key-value pairs.
358
- hasNonKeyValueElts := false
359
- for _, elt := range exp.Elts {
360
- // If an element is not a key-value pair, set the flag to true.
361
- if _, isKV := elt.(*ast.KeyValueExpr); !isKV {
362
- hasNonKeyValueElts = true
363
- break
364
- }
365
- }
366
-
367
- if hasNonKeyValueElts {
368
- // Get the fields from the struct type
369
- for i := 0; i < structType.NumFields(); i++ {
370
- field := structType.Field(i)
371
- // If we have a value for this field position
372
- if i < len(exp.Elts) {
373
- // Check if it's not a key-value pair
374
- if _, isKV := exp.Elts[i].(*ast.KeyValueExpr); !isKV {
375
- directFields[field.Name()] = exp.Elts[i]
376
- }
377
- }
378
- }
379
- }
286
+ // Categorize fields into direct, embedded, and explicit embedded
287
+ directFields, embeddedFields, explicitEmbedded, err := c.categorizeStructFields(
288
+ exp, structType, litType, isAnonymousStruct,
289
+ )
290
+ if err != nil {
291
+ return err
380
292
  }
381
293
 
382
294
  // Write the object literal
@@ -388,107 +300,9 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
388
300
  c.tsw.WriteLiterally("({")
389
301
  }
390
302
 
391
- firstFieldWritten := false
392
-
393
- // Write direct fields that aren't embedded struct names
394
- directKeys := make([]string, 0, len(directFields))
395
- for k := range directFields {
396
- // Skip embedded struct names - we'll handle those separately
397
- if _, isEmbedded := embeddedFields[k]; !isEmbedded {
398
- directKeys = append(directKeys, k)
399
- }
400
- }
401
- slices.Sort(directKeys)
402
- for _, keyName := range directKeys {
403
- if firstFieldWritten {
404
- c.tsw.WriteLiterally(", ")
405
- }
406
-
407
- // Convert field name for protobuf types
408
- fieldName := c.convertProtobufFieldNameInLiteral(keyName, litType)
409
-
410
- c.tsw.WriteLiterally(fieldName)
411
- c.tsw.WriteLiterally(": ")
412
- if err := c.WriteVarRefedValue(directFields[keyName]); err != nil {
413
- return err
414
- }
415
- firstFieldWritten = true
416
- }
417
-
418
- // Write explicitly initialized embedded structs
419
- explicitKeys := make([]string, 0, len(explicitEmbedded))
420
- for k := range explicitEmbedded {
421
- explicitKeys = append(explicitKeys, k)
422
- }
423
- slices.Sort(explicitKeys)
424
- for _, embeddedName := range explicitKeys {
425
- if firstFieldWritten {
426
- c.tsw.WriteLiterally(", ")
427
- }
428
- c.tsw.WriteLiterally(embeddedName)
429
- c.tsw.WriteLiterally(": ")
430
-
431
- // Check if the embedded value is a composite literal for a struct
432
- // If so, extract the fields and write them directly
433
- if compLit, ok := explicitEmbedded[embeddedName].(*ast.CompositeLit); ok {
434
- // Write initialization fields directly without the 'new Constructor'
435
- c.tsw.WriteLiterally("{")
436
- for i, elem := range compLit.Elts {
437
- if i > 0 {
438
- c.tsw.WriteLiterally(", ")
439
- }
440
- if err := c.WriteVarRefedValue(elem); err != nil {
441
- return err
442
- }
443
- }
444
- c.tsw.WriteLiterally("}")
445
- } else {
446
- // Not a composite literal, write it normally
447
- if err := c.WriteVarRefedValue(explicitEmbedded[embeddedName]); err != nil {
448
- return err
449
- }
450
- }
451
- firstFieldWritten = true
452
- }
453
-
454
- // Write embedded fields for structs that weren't explicitly initialized
455
- embeddedKeys := make([]string, 0, len(embeddedFields))
456
- for k := range embeddedFields {
457
- // Skip embedded structs that were explicitly initialized
458
- if _, wasExplicit := explicitEmbedded[k]; !wasExplicit {
459
- embeddedKeys = append(embeddedKeys, k)
460
- }
461
- }
462
- slices.Sort(embeddedKeys)
463
- for _, embeddedPropName := range embeddedKeys {
464
- fieldsMap := embeddedFields[embeddedPropName]
465
- if len(fieldsMap) == 0 {
466
- continue
467
- } // Skip empty embedded initializers
468
-
469
- if firstFieldWritten {
470
- c.tsw.WriteLiterally(", ")
471
- }
472
- c.tsw.WriteLiterally(embeddedPropName) // Use the Type name as the property key
473
- c.tsw.WriteLiterally(": {")
474
-
475
- innerKeys := make([]string, 0, len(fieldsMap))
476
- for k := range fieldsMap {
477
- innerKeys = append(innerKeys, k)
478
- }
479
- slices.Sort(innerKeys)
480
- for i, keyName := range innerKeys {
481
- if i > 0 {
482
- c.tsw.WriteLiterally(", ")
483
- }
484
- c.tsw.WriteLiterally(keyName) // Field name within the embedded struct
485
- c.tsw.WriteLiterally(": ")
486
- if err := c.WriteVarRefedValue(fieldsMap[keyName]); err != nil {
487
- return err
488
- }
489
- }
490
- c.tsw.WriteLiterally("}")
491
- firstFieldWritten = true
303
+ // Write all fields
304
+ if err := c.writeStructLiteralFields(directFields, embeddedFields, explicitEmbedded, litType); err != nil {
305
+ return err
492
306
  }
493
307
 
494
308
  // Close the object literal
@@ -714,3 +528,226 @@ func (c *GoToTSCompiler) evaluateConstantExpr(expr ast.Expr) interface{} {
714
528
  }
715
529
  return nil
716
530
  }
531
+
532
+ // categorizeStructFields organizes the elements of a struct composite literal into
533
+ // three categories: direct fields, embedded fields, and explicitly initialized embedded structs.
534
+ // Returns maps for direct fields, embedded fields (nested map), and explicit embedded initializations.
535
+ func (c *GoToTSCompiler) categorizeStructFields(
536
+ exp *ast.CompositeLit,
537
+ structType *types.Struct,
538
+ litType types.Type,
539
+ isAnonymousStruct bool,
540
+ ) (
541
+ directFields map[string]ast.Expr,
542
+ embeddedFields map[string]map[string]ast.Expr,
543
+ explicitEmbedded map[string]ast.Expr,
544
+ err error,
545
+ ) {
546
+ directFields = make(map[string]ast.Expr)
547
+ embeddedFields = make(map[string]map[string]ast.Expr)
548
+ explicitEmbedded = make(map[string]ast.Expr)
549
+
550
+ // Pre-populate embeddedFields map keys using the correct property name
551
+ for i := 0; i < structType.NumFields(); i++ {
552
+ field := structType.Field(i)
553
+ if field.Anonymous() {
554
+ fieldType := field.Type()
555
+ if ptr, ok := fieldType.(*types.Pointer); ok {
556
+ fieldType = ptr.Elem()
557
+ }
558
+ if named, ok := fieldType.(*types.Named); ok {
559
+ // Use the type name as the property name in TS
560
+ embeddedPropName := named.Obj().Name()
561
+ embeddedFields[embeddedPropName] = make(map[string]ast.Expr)
562
+ }
563
+ }
564
+ }
565
+
566
+ // Group literal elements by direct vs embedded fields
567
+ for _, elt := range exp.Elts {
568
+ kv, ok := elt.(*ast.KeyValueExpr)
569
+ if !ok {
570
+ continue
571
+ } // Skip non-key-value
572
+ keyIdent, ok := kv.Key.(*ast.Ident)
573
+ if !ok {
574
+ continue
575
+ } // Skip non-ident keys
576
+ keyName := keyIdent.Name
577
+
578
+ // Check if this is an explicit embedded struct initialization
579
+ // e.g., Person: Person{...} or Person: personVar
580
+ if _, isEmbedded := embeddedFields[keyName]; isEmbedded {
581
+ // This is an explicit initialization of an embedded struct
582
+ explicitEmbedded[keyName] = kv.Value
583
+ continue
584
+ }
585
+
586
+ isDirectField := false
587
+ for i := range structType.NumFields() {
588
+ field := structType.Field(i)
589
+ if field.Name() == keyName {
590
+ isDirectField = true
591
+ directFields[keyName] = kv.Value
592
+ break
593
+ }
594
+ }
595
+
596
+ // For anonymous structs, all fields are direct fields
597
+ if isAnonymousStruct {
598
+ directFields[keyName] = kv.Value
599
+ isDirectField = true
600
+ }
601
+
602
+ // If not a direct field, return an error
603
+ if !isDirectField {
604
+ return nil, nil, nil, fmt.Errorf("field %s not found in type %s for composite literal",
605
+ keyName, litType.String())
606
+ }
607
+ }
608
+
609
+ // Handle the case where an anonymous struct has values without keys
610
+ // This block processes non-key-value elements and associates them with struct fields.
611
+ if isAnonymousStruct && len(exp.Elts) > 0 && len(directFields) == 0 {
612
+ // Check if any elements in the composite literal are not key-value pairs.
613
+ hasNonKeyValueElts := false
614
+ for _, elt := range exp.Elts {
615
+ // If an element is not a key-value pair, set the flag to true.
616
+ if _, isKV := elt.(*ast.KeyValueExpr); !isKV {
617
+ hasNonKeyValueElts = true
618
+ break
619
+ }
620
+ }
621
+
622
+ if hasNonKeyValueElts {
623
+ // Get the fields from the struct type
624
+ for i := 0; i < structType.NumFields(); i++ {
625
+ field := structType.Field(i)
626
+ // If we have a value for this field position
627
+ if i < len(exp.Elts) {
628
+ // Check if it's not a key-value pair
629
+ if _, isKV := exp.Elts[i].(*ast.KeyValueExpr); !isKV {
630
+ directFields[field.Name()] = exp.Elts[i]
631
+ }
632
+ }
633
+ }
634
+ }
635
+ }
636
+
637
+ return directFields, embeddedFields, explicitEmbedded, nil
638
+ }
639
+
640
+ // writeStructLiteralFields writes the field initializations for a struct composite literal.
641
+ // It handles direct fields, explicitly initialized embedded structs, and implicitly initialized
642
+ // embedded fields, writing them in sorted order.
643
+ func (c *GoToTSCompiler) writeStructLiteralFields(
644
+ directFields map[string]ast.Expr,
645
+ embeddedFields map[string]map[string]ast.Expr,
646
+ explicitEmbedded map[string]ast.Expr,
647
+ litType types.Type,
648
+ ) error {
649
+ firstFieldWritten := false
650
+
651
+ // Write direct fields that aren't embedded struct names
652
+ directKeys := make([]string, 0, len(directFields))
653
+ for k := range directFields {
654
+ // Skip embedded struct names - we'll handle those separately
655
+ if _, isEmbedded := embeddedFields[k]; !isEmbedded {
656
+ directKeys = append(directKeys, k)
657
+ }
658
+ }
659
+ slices.Sort(directKeys)
660
+ for _, keyName := range directKeys {
661
+ if firstFieldWritten {
662
+ c.tsw.WriteLiterally(", ")
663
+ }
664
+
665
+ // Convert field name for protobuf types
666
+ fieldName := c.convertProtobufFieldNameInLiteral(keyName, litType)
667
+
668
+ c.tsw.WriteLiterally(fieldName)
669
+ c.tsw.WriteLiterally(": ")
670
+ if err := c.WriteVarRefedValue(directFields[keyName]); err != nil {
671
+ return err
672
+ }
673
+ firstFieldWritten = true
674
+ }
675
+
676
+ // Write explicitly initialized embedded structs
677
+ explicitKeys := make([]string, 0, len(explicitEmbedded))
678
+ for k := range explicitEmbedded {
679
+ explicitKeys = append(explicitKeys, k)
680
+ }
681
+ slices.Sort(explicitKeys)
682
+ for _, embeddedName := range explicitKeys {
683
+ if firstFieldWritten {
684
+ c.tsw.WriteLiterally(", ")
685
+ }
686
+ c.tsw.WriteLiterally(embeddedName)
687
+ c.tsw.WriteLiterally(": ")
688
+
689
+ // Check if the embedded value is a composite literal for a struct
690
+ // If so, extract the fields and write them directly
691
+ if compLit, ok := explicitEmbedded[embeddedName].(*ast.CompositeLit); ok {
692
+ // Write initialization fields directly without the 'new Constructor'
693
+ c.tsw.WriteLiterally("{")
694
+ for i, elem := range compLit.Elts {
695
+ if i > 0 {
696
+ c.tsw.WriteLiterally(", ")
697
+ }
698
+ if err := c.WriteVarRefedValue(elem); err != nil {
699
+ return err
700
+ }
701
+ }
702
+ c.tsw.WriteLiterally("}")
703
+ } else {
704
+ // Not a composite literal, write it normally
705
+ if err := c.WriteVarRefedValue(explicitEmbedded[embeddedName]); err != nil {
706
+ return err
707
+ }
708
+ }
709
+ firstFieldWritten = true
710
+ }
711
+
712
+ // Write embedded fields for structs that weren't explicitly initialized
713
+ embeddedKeys := make([]string, 0, len(embeddedFields))
714
+ for k := range embeddedFields {
715
+ // Skip embedded structs that were explicitly initialized
716
+ if _, wasExplicit := explicitEmbedded[k]; !wasExplicit {
717
+ embeddedKeys = append(embeddedKeys, k)
718
+ }
719
+ }
720
+ slices.Sort(embeddedKeys)
721
+ for _, embeddedPropName := range embeddedKeys {
722
+ fieldsMap := embeddedFields[embeddedPropName]
723
+ if len(fieldsMap) == 0 {
724
+ continue
725
+ } // Skip empty embedded initializers
726
+
727
+ if firstFieldWritten {
728
+ c.tsw.WriteLiterally(", ")
729
+ }
730
+ c.tsw.WriteLiterally(embeddedPropName) // Use the Type name as the property key
731
+ c.tsw.WriteLiterally(": {")
732
+
733
+ innerKeys := make([]string, 0, len(fieldsMap))
734
+ for k := range fieldsMap {
735
+ innerKeys = append(innerKeys, k)
736
+ }
737
+ slices.Sort(innerKeys)
738
+ for i, keyName := range innerKeys {
739
+ if i > 0 {
740
+ c.tsw.WriteLiterally(", ")
741
+ }
742
+ c.tsw.WriteLiterally(keyName) // Field name within the embedded struct
743
+ c.tsw.WriteLiterally(": ")
744
+ if err := c.WriteVarRefedValue(fieldsMap[keyName]); err != nil {
745
+ return err
746
+ }
747
+ }
748
+ c.tsw.WriteLiterally("}")
749
+ firstFieldWritten = true
750
+ }
751
+
752
+ return nil
753
+ }
@@ -0,0 +1,88 @@
1
+ package compiler
2
+
3
+ import "go/types"
4
+
5
+ // ConstraintInfo holds information about types found in an interface constraint
6
+ type ConstraintInfo struct {
7
+ HasMap bool
8
+ HasSlice bool
9
+ HasString bool
10
+ HasByteSlice bool
11
+ MapValueType types.Type
12
+ SliceElemType types.Type
13
+ }
14
+
15
+ // analyzeConstraint analyzes an interface constraint and returns information about the types it contains
16
+ func analyzeConstraint(iface *types.Interface) ConstraintInfo {
17
+ info := ConstraintInfo{}
18
+
19
+ for i := 0; i < iface.NumEmbeddeds(); i++ {
20
+ embedded := iface.EmbeddedType(i)
21
+ if union, ok := embedded.(*types.Union); ok {
22
+ for j := 0; j < union.Len(); j++ {
23
+ term := union.Term(j)
24
+ checkType(term.Type(), &info)
25
+ }
26
+ } else {
27
+ checkType(embedded, &info)
28
+ }
29
+ }
30
+
31
+ return info
32
+ }
33
+
34
+ func checkType(t types.Type, info *ConstraintInfo) {
35
+ underlying := t.Underlying()
36
+
37
+ if mapType, isMap := underlying.(*types.Map); isMap {
38
+ info.HasMap = true
39
+ if info.MapValueType == nil {
40
+ info.MapValueType = mapType.Elem()
41
+ }
42
+ return
43
+ }
44
+
45
+ if sliceType, isSlice := underlying.(*types.Slice); isSlice {
46
+ info.HasSlice = true
47
+ if info.SliceElemType == nil {
48
+ info.SliceElemType = sliceType.Elem()
49
+ }
50
+
51
+ if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
52
+ info.HasByteSlice = true
53
+ }
54
+ return
55
+ }
56
+
57
+ if basicType, isBasic := underlying.(*types.Basic); isBasic {
58
+ if (basicType.Info() & types.IsString) != 0 {
59
+ info.HasString = true
60
+ }
61
+ }
62
+ }
63
+
64
+ // hasMapConstraint checks if an interface constraint includes map types
65
+ func hasMapConstraint(iface *types.Interface) bool {
66
+ return analyzeConstraint(iface).HasMap
67
+ }
68
+
69
+ // hasSliceConstraint checks if an interface constraint includes slice types
70
+ func hasSliceConstraint(iface *types.Interface) bool {
71
+ return analyzeConstraint(iface).HasSlice
72
+ }
73
+
74
+ // hasMixedStringByteConstraint checks if an interface constraint includes both string and []byte types
75
+ func hasMixedStringByteConstraint(iface *types.Interface) bool {
76
+ info := analyzeConstraint(iface)
77
+ return info.HasString && info.HasByteSlice
78
+ }
79
+
80
+ // getMapValueTypeFromConstraint extracts the value type from a map constraint
81
+ func getMapValueTypeFromConstraint(iface *types.Interface) types.Type {
82
+ return analyzeConstraint(iface).MapValueType
83
+ }
84
+
85
+ // getSliceElementTypeFromConstraint extracts the element type from a slice constraint
86
+ func getSliceElementTypeFromConstraint(iface *types.Interface) types.Type {
87
+ return analyzeConstraint(iface).SliceElemType
88
+ }