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.
- package/README.md +40 -33
- package/compiler/analysis.go +115 -19
- package/compiler/assignment.go +163 -217
- package/compiler/compiler.go +35 -31
- package/compiler/composite-lit.go +233 -196
- package/compiler/constraint.go +88 -0
- package/compiler/decl.go +418 -7
- package/compiler/expr-call-async.go +20 -34
- package/compiler/expr-call-builtins.go +19 -0
- package/compiler/expr-call-helpers.go +0 -28
- package/compiler/expr-call-make.go +93 -343
- package/compiler/expr-call-type-conversion.go +221 -249
- package/compiler/expr-call.go +70 -69
- package/compiler/expr-selector.go +21 -24
- package/compiler/expr.go +3 -60
- package/compiler/protobuf.go +180 -36
- package/compiler/spec-value.go +132 -24
- package/compiler/spec.go +14 -55
- package/compiler/stmt-assign.go +338 -356
- package/compiler/stmt-range.go +4 -24
- package/compiler/stmt.go +99 -172
- package/compiler/type-utils.go +185 -0
- package/compiler/type.go +26 -80
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +3 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -2
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/fmt/fmt.js +113 -16
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/runtime/runtime.d.ts +1 -1
- package/dist/gs/runtime/runtime.js +1 -1
- package/dist/gs/slices/slices.d.ts +23 -0
- package/dist/gs/slices/slices.js +61 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +8 -8
- package/go.sum +14 -14
- package/gs/builtin/slice.ts +5 -2
- package/gs/builtin/type.ts +13 -6
- package/gs/fmt/fmt.test.ts +176 -0
- package/gs/fmt/fmt.ts +109 -18
- package/gs/runtime/runtime.ts +1 -1
- package/gs/slices/slices.ts +68 -0
- package/package.json +3 -3
package/compiler/stmt-range.go
CHANGED
|
@@ -55,7 +55,7 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
|
|
|
55
55
|
|
|
56
56
|
// Handle basic types (string, integer)
|
|
57
57
|
if basic, ok := underlying.(*types.Basic); ok {
|
|
58
|
-
if
|
|
58
|
+
if c.isStringType(iterType) {
|
|
59
59
|
return c.writeStringRange(exp)
|
|
60
60
|
} else if basic.Info()&types.IsInteger != 0 {
|
|
61
61
|
return c.writeIntegerRange(exp)
|
|
@@ -96,28 +96,6 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
|
|
|
96
96
|
|
|
97
97
|
// Helper functions
|
|
98
98
|
|
|
99
|
-
func (c *GoToTSCompiler) isMapType(iterType, underlying types.Type) bool {
|
|
100
|
-
if _, ok := underlying.(*types.Map); ok {
|
|
101
|
-
return true
|
|
102
|
-
}
|
|
103
|
-
if typeParam, isTypeParam := iterType.(*types.TypeParam); isTypeParam {
|
|
104
|
-
constraint := typeParam.Constraint()
|
|
105
|
-
if constraint != nil {
|
|
106
|
-
constraintUnderlying := constraint.Underlying()
|
|
107
|
-
if iface, isInterface := constraintUnderlying.(*types.Interface); isInterface {
|
|
108
|
-
return hasMapConstraint(iface)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return false
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
func (c *GoToTSCompiler) isArrayOrSlice(underlying types.Type) bool {
|
|
116
|
-
_, isSlice := underlying.(*types.Slice)
|
|
117
|
-
_, isArray := underlying.(*types.Array)
|
|
118
|
-
return isArray || isSlice
|
|
119
|
-
}
|
|
120
|
-
|
|
121
99
|
func (c *GoToTSCompiler) isIteratorSignature(sig *types.Signature) bool {
|
|
122
100
|
params := sig.Params()
|
|
123
101
|
if params.Len() != 1 {
|
|
@@ -195,7 +173,9 @@ func (c *GoToTSCompiler) writeStringRange(exp *ast.RangeStmt) error {
|
|
|
195
173
|
if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
|
|
196
174
|
c.tsw.WriteLiterally("const ")
|
|
197
175
|
c.WriteIdent(ident, false)
|
|
198
|
-
c.tsw.WriteLiterally(" = _runes[
|
|
176
|
+
c.tsw.WriteLiterally(" = _runes[")
|
|
177
|
+
c.tsw.WriteLiterally(indexVarName)
|
|
178
|
+
c.tsw.WriteLiterally("]")
|
|
199
179
|
c.tsw.WriteLine("")
|
|
200
180
|
}
|
|
201
181
|
}
|
package/compiler/stmt.go
CHANGED
|
@@ -139,7 +139,7 @@ func (c *GoToTSCompiler) WriteStmtDecl(stmt *ast.DeclStmt) error {
|
|
|
139
139
|
return fmt.Errorf("failed to write type spec in declaration statement: %w", err)
|
|
140
140
|
}
|
|
141
141
|
} else {
|
|
142
|
-
|
|
142
|
+
return fmt.Errorf("unhandled spec in DeclStmt: %T", spec)
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
} else {
|
|
@@ -213,7 +213,7 @@ func (c *GoToTSCompiler) WriteStmtGo(exp *ast.GoStmt) error {
|
|
|
213
213
|
case *ast.Ident:
|
|
214
214
|
// Handle named functions: go namedFunc(args)
|
|
215
215
|
// Get the object for this function
|
|
216
|
-
obj := c.
|
|
216
|
+
obj := c.objectOfIdent(fun)
|
|
217
217
|
if obj == nil {
|
|
218
218
|
return errors.Errorf("could not find object for function: %s", fun.Name)
|
|
219
219
|
}
|
|
@@ -255,7 +255,7 @@ func (c *GoToTSCompiler) WriteStmtGo(exp *ast.GoStmt) error {
|
|
|
255
255
|
case *ast.SelectorExpr:
|
|
256
256
|
// Handle selector expressions: go x.Method(args)
|
|
257
257
|
// Get the object for the selected method
|
|
258
|
-
obj := c.
|
|
258
|
+
obj := c.objectOfIdent(fun.Sel)
|
|
259
259
|
if obj == nil {
|
|
260
260
|
return errors.Errorf("could not find object for selected method: %s", fun.Sel.Name)
|
|
261
261
|
}
|
|
@@ -447,64 +447,22 @@ func (c *GoToTSCompiler) WriteStmtSend(exp *ast.SendStmt) error {
|
|
|
447
447
|
func (c *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
|
|
448
448
|
// Handle optional initialization statement
|
|
449
449
|
if exp.Init != nil {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
for varName, tempVarName := range shadowingInfo.TempVariables {
|
|
456
|
-
c.tsw.WriteLiterally("const ")
|
|
457
|
-
c.tsw.WriteLiterally(tempVarName)
|
|
458
|
-
c.tsw.WriteLiterally(" = ")
|
|
459
|
-
|
|
460
|
-
// Check if this is a built-in function and handle it directly
|
|
461
|
-
if c.isBuiltinFunction(varName) {
|
|
462
|
-
c.tsw.WriteLiterally("$.")
|
|
463
|
-
c.tsw.WriteLiterally(varName)
|
|
464
|
-
} else {
|
|
465
|
-
// Get the original object for this shadowed variable
|
|
466
|
-
if originalObj, exists := shadowingInfo.ShadowedVariables[varName]; exists {
|
|
467
|
-
// Create an identifier with the original name and use WriteValueExpr to properly resolve it
|
|
468
|
-
originalIdent := &ast.Ident{Name: varName}
|
|
469
|
-
// Set the identifier in the Uses map so WriteValueExpr can find the object
|
|
470
|
-
c.pkg.TypesInfo.Uses[originalIdent] = originalObj
|
|
471
|
-
c.WriteValueExpr(originalIdent)
|
|
472
|
-
} else {
|
|
473
|
-
// Fallback to literal name if no object found (shouldn't happen in normal cases)
|
|
474
|
-
c.tsw.WriteLiterally(varName)
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
c.tsw.WriteLine("")
|
|
478
|
-
}
|
|
479
|
-
}
|
|
450
|
+
shadowingInfo := c.analysis.GetShadowingInfo(exp)
|
|
451
|
+
|
|
452
|
+
// Write temp variables if shadowing detected
|
|
453
|
+
if shadowingInfo != nil {
|
|
454
|
+
c.writeShadowingTempVars(shadowingInfo)
|
|
480
455
|
}
|
|
481
456
|
|
|
482
457
|
c.tsw.WriteLine("{")
|
|
483
458
|
c.tsw.Indent(1)
|
|
484
459
|
|
|
485
|
-
//
|
|
486
|
-
if
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
// Handle the initialization with shadowing support
|
|
490
|
-
if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok {
|
|
491
|
-
if err := c.writeShadowedAssignmentWithoutTempVars(assignStmt, shadowingInfo); err != nil {
|
|
492
|
-
return fmt.Errorf("failed to write shadowed assignment in if init: %w", err)
|
|
493
|
-
}
|
|
494
|
-
} else {
|
|
495
|
-
// Non-assignment initialization statement
|
|
496
|
-
if err := c.WriteStmt(exp.Init); err != nil {
|
|
497
|
-
return fmt.Errorf("failed to write if initialization statement: %w", err)
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
} else {
|
|
501
|
-
// No shadowing info, write normally
|
|
502
|
-
if err := c.WriteStmt(exp.Init); err != nil {
|
|
503
|
-
return fmt.Errorf("failed to write if initialization statement: %w", err)
|
|
504
|
-
}
|
|
460
|
+
// Write initialization with shadowing support if needed
|
|
461
|
+
if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok && shadowingInfo != nil {
|
|
462
|
+
if err := c.writeAssignmentWithShadowing(assignStmt, shadowingInfo); err != nil {
|
|
463
|
+
return fmt.Errorf("failed to write shadowed assignment in if init: %w", err)
|
|
505
464
|
}
|
|
506
465
|
} else {
|
|
507
|
-
// No variable shadowing, write initialization normally
|
|
508
466
|
if err := c.WriteStmt(exp.Init); err != nil {
|
|
509
467
|
return fmt.Errorf("failed to write if initialization statement: %w", err)
|
|
510
468
|
}
|
|
@@ -675,11 +633,20 @@ func (c *GoToTSCompiler) WriteStmtBlock(exp *ast.BlockStmt, suppressNewline bool
|
|
|
675
633
|
hasAsyncDefer := false
|
|
676
634
|
for _, stmt := range exp.List {
|
|
677
635
|
if deferStmt, ok := stmt.(*ast.DeferStmt); ok {
|
|
636
|
+
if deferStmt.Call == nil || deferStmt.Call.Fun == nil {
|
|
637
|
+
continue
|
|
638
|
+
}
|
|
678
639
|
if funcLit, ok := deferStmt.Call.Fun.(*ast.FuncLit); ok {
|
|
679
640
|
if c.analysis.IsFuncLitAsync(funcLit) {
|
|
680
641
|
hasAsyncDefer = true
|
|
681
642
|
break
|
|
682
643
|
}
|
|
644
|
+
} else {
|
|
645
|
+
// Check if the deferred call is to an async function
|
|
646
|
+
if c.isCallExprAsync(deferStmt.Call) {
|
|
647
|
+
hasAsyncDefer = true
|
|
648
|
+
break
|
|
649
|
+
}
|
|
683
650
|
}
|
|
684
651
|
}
|
|
685
652
|
}
|
|
@@ -848,7 +815,7 @@ func (c *GoToTSCompiler) WriteStmtSwitch(exp *ast.SwitchStmt) error {
|
|
|
848
815
|
return fmt.Errorf("failed to write case clause in switch statement: %w", err)
|
|
849
816
|
}
|
|
850
817
|
} else {
|
|
851
|
-
|
|
818
|
+
return fmt.Errorf("unhandled statement in switch body: %T", stmt)
|
|
852
819
|
}
|
|
853
820
|
}
|
|
854
821
|
|
|
@@ -877,6 +844,9 @@ func (c *GoToTSCompiler) WriteStmtDefer(exp *ast.DeferStmt) error {
|
|
|
877
844
|
isAsyncDeferred := false
|
|
878
845
|
if funcLit, ok := exp.Call.Fun.(*ast.FuncLit); ok {
|
|
879
846
|
isAsyncDeferred = c.analysis.IsFuncLitAsync(funcLit)
|
|
847
|
+
} else {
|
|
848
|
+
// Check if the deferred call is to an async function
|
|
849
|
+
isAsyncDeferred = c.isCallExprAsync(exp.Call)
|
|
880
850
|
}
|
|
881
851
|
|
|
882
852
|
// Set async prefix based on pre-computed async status
|
|
@@ -954,10 +924,10 @@ func (c *GoToTSCompiler) WriteStmtLabeled(stmt *ast.LabeledStmt) error {
|
|
|
954
924
|
return nil
|
|
955
925
|
}
|
|
956
926
|
|
|
957
|
-
//
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
927
|
+
// ============ Variable Shadowing Support ============
|
|
928
|
+
|
|
929
|
+
// writeShadowingTempVars creates temporary variables for shadowed variables
|
|
930
|
+
func (c *GoToTSCompiler) writeShadowingTempVars(shadowingInfo *ShadowingInfo) {
|
|
961
931
|
for varName, tempVarName := range shadowingInfo.TempVariables {
|
|
962
932
|
c.tsw.WriteLiterally("const ")
|
|
963
933
|
c.tsw.WriteLiterally(tempVarName)
|
|
@@ -982,94 +952,20 @@ func (c *GoToTSCompiler) writeShadowedAssignment(stmt *ast.AssignStmt, shadowing
|
|
|
982
952
|
}
|
|
983
953
|
c.tsw.WriteLine("")
|
|
984
954
|
}
|
|
985
|
-
|
|
986
|
-
// Now write the LHS variables (these are new declarations)
|
|
987
|
-
for i, lhsExpr := range stmt.Lhs {
|
|
988
|
-
if i > 0 {
|
|
989
|
-
c.tsw.WriteLiterally(", ")
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
if ident, ok := lhsExpr.(*ast.Ident); ok {
|
|
993
|
-
if ident.Name == "_" {
|
|
994
|
-
c.tsw.WriteLiterally("_")
|
|
995
|
-
} else {
|
|
996
|
-
c.tsw.WriteLiterally("let ")
|
|
997
|
-
c.WriteIdent(ident, false) // Don't use temp variable for LHS
|
|
998
|
-
}
|
|
999
|
-
} else {
|
|
1000
|
-
// For non-identifier LHS (shouldn't happen in := assignments), write normally
|
|
1001
|
-
if err := c.WriteValueExpr(lhsExpr); err != nil {
|
|
1002
|
-
return err
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
c.tsw.WriteLiterally(" = ")
|
|
1008
|
-
|
|
1009
|
-
// Write RHS expressions - but we need to replace shadowed variables with temporary variables
|
|
1010
|
-
for i, rhsExpr := range stmt.Rhs {
|
|
1011
|
-
if i > 0 {
|
|
1012
|
-
c.tsw.WriteLiterally(", ")
|
|
1013
|
-
}
|
|
1014
|
-
if err := c.writeShadowedRHSExpression(rhsExpr, shadowingInfo); err != nil {
|
|
1015
|
-
return err
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
c.tsw.WriteLine("")
|
|
1020
|
-
return nil
|
|
1021
955
|
}
|
|
1022
956
|
|
|
1023
|
-
//
|
|
1024
|
-
//
|
|
1025
|
-
func (c *GoToTSCompiler)
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
valueExpr := stmt.Lhs[0]
|
|
1032
|
-
okExpr := stmt.Lhs[1]
|
|
1033
|
-
valueIdent, valueIsIdent := valueExpr.(*ast.Ident)
|
|
1034
|
-
okIdent, okIsIdent := okExpr.(*ast.Ident)
|
|
1035
|
-
if valueIsIdent && okIsIdent {
|
|
1036
|
-
valueName := valueIdent.Name
|
|
1037
|
-
okName := okIdent.Name
|
|
1038
|
-
valueIsBlank := valueName == "_"
|
|
1039
|
-
okIsBlank := okName == "_"
|
|
1040
|
-
if valueIsBlank && okIsBlank {
|
|
1041
|
-
// Both blank, evaluate RHS for side effects
|
|
1042
|
-
if err := c.writeShadowedRHSExpression(typeAssert.X, shadowingInfo); err != nil {
|
|
1043
|
-
return err
|
|
1044
|
-
}
|
|
1045
|
-
c.tsw.WriteLine("")
|
|
1046
|
-
return nil
|
|
1047
|
-
}
|
|
1048
|
-
c.tsw.WriteLiterally("let { ")
|
|
1049
|
-
var parts []string
|
|
1050
|
-
if !valueIsBlank {
|
|
1051
|
-
parts = append(parts, "value: "+valueName)
|
|
1052
|
-
}
|
|
1053
|
-
if !okIsBlank {
|
|
1054
|
-
parts = append(parts, "ok: "+okName)
|
|
1055
|
-
}
|
|
1056
|
-
c.tsw.WriteLiterally(strings.Join(parts, ", "))
|
|
1057
|
-
c.tsw.WriteLiterally(" } = $.typeAssert<")
|
|
1058
|
-
c.WriteTypeExpr(typeAssert.Type)
|
|
1059
|
-
c.tsw.WriteLiterally(">(")
|
|
1060
|
-
if err := c.writeShadowedRHSExpression(typeAssert.X, shadowingInfo); err != nil {
|
|
1061
|
-
return err
|
|
1062
|
-
}
|
|
1063
|
-
c.tsw.WriteLiterally(", ")
|
|
1064
|
-
c.writeTypeDescription(typeAssert.Type)
|
|
1065
|
-
c.tsw.WriteLiterally(")")
|
|
1066
|
-
c.tsw.WriteLine("")
|
|
1067
|
-
return nil
|
|
1068
|
-
}
|
|
957
|
+
// writeAssignmentWithShadowing writes an assignment statement that has variable shadowing.
|
|
958
|
+
// Handles both regular assignments and type assertions, with optional temp variable creation.
|
|
959
|
+
func (c *GoToTSCompiler) writeAssignmentWithShadowing(stmt *ast.AssignStmt, shadowingInfo *ShadowingInfo) error {
|
|
960
|
+
// Check for type assertion special case
|
|
961
|
+
if len(stmt.Rhs) == 1 && len(stmt.Lhs) == 2 {
|
|
962
|
+
if typeAssert, ok := stmt.Rhs[0].(*ast.TypeAssertExpr); ok {
|
|
963
|
+
return c.writeTypeAssertWithShadowing(stmt, typeAssert, shadowingInfo)
|
|
1069
964
|
}
|
|
1070
965
|
}
|
|
1071
966
|
|
|
1072
|
-
|
|
967
|
+
// Regular assignment: write LHS declarations
|
|
968
|
+
firstDecl := true
|
|
1073
969
|
for i, lhsExpr := range stmt.Lhs {
|
|
1074
970
|
if i > 0 {
|
|
1075
971
|
c.tsw.WriteLiterally(", ")
|
|
@@ -1090,21 +986,69 @@ func (c *GoToTSCompiler) writeShadowedAssignmentWithoutTempVars(stmt *ast.Assign
|
|
|
1090
986
|
}
|
|
1091
987
|
}
|
|
1092
988
|
}
|
|
989
|
+
|
|
990
|
+
// Write RHS with shadowed variable substitution
|
|
1093
991
|
c.tsw.WriteLiterally(" = ")
|
|
1094
992
|
for i, rhsExpr := range stmt.Rhs {
|
|
1095
993
|
if i > 0 {
|
|
1096
994
|
c.tsw.WriteLiterally(", ")
|
|
1097
995
|
}
|
|
1098
|
-
if err := c.
|
|
996
|
+
if err := c.substituteExprForShadowing(rhsExpr, shadowingInfo); err != nil {
|
|
997
|
+
return err
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
c.tsw.WriteLine("")
|
|
1001
|
+
return nil
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// writeTypeAssertWithShadowing writes a type assertion assignment (v, ok := x.(T)) with shadowing support
|
|
1005
|
+
func (c *GoToTSCompiler) writeTypeAssertWithShadowing(stmt *ast.AssignStmt, typeAssert *ast.TypeAssertExpr, shadowingInfo *ShadowingInfo) error {
|
|
1006
|
+
valueIdent, valueIsIdent := stmt.Lhs[0].(*ast.Ident)
|
|
1007
|
+
okIdent, okIsIdent := stmt.Lhs[1].(*ast.Ident)
|
|
1008
|
+
|
|
1009
|
+
if !valueIsIdent || !okIsIdent {
|
|
1010
|
+
return fmt.Errorf("type assertion LHS must be identifiers")
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
valueName := valueIdent.Name
|
|
1014
|
+
okName := okIdent.Name
|
|
1015
|
+
valueIsBlank := valueName == "_"
|
|
1016
|
+
okIsBlank := okName == "_"
|
|
1017
|
+
|
|
1018
|
+
if valueIsBlank && okIsBlank {
|
|
1019
|
+
// Both blank, evaluate RHS for side effects only
|
|
1020
|
+
if err := c.substituteExprForShadowing(typeAssert.X, shadowingInfo); err != nil {
|
|
1099
1021
|
return err
|
|
1100
1022
|
}
|
|
1023
|
+
c.tsw.WriteLine("")
|
|
1024
|
+
return nil
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// Destructure into value and ok
|
|
1028
|
+
c.tsw.WriteLiterally("let { ")
|
|
1029
|
+
var parts []string
|
|
1030
|
+
if !valueIsBlank {
|
|
1031
|
+
parts = append(parts, "value: "+valueName)
|
|
1101
1032
|
}
|
|
1033
|
+
if !okIsBlank {
|
|
1034
|
+
parts = append(parts, "ok: "+okName)
|
|
1035
|
+
}
|
|
1036
|
+
c.tsw.WriteLiterally(strings.Join(parts, ", "))
|
|
1037
|
+
c.tsw.WriteLiterally(" } = $.typeAssert<")
|
|
1038
|
+
c.WriteTypeExpr(typeAssert.Type)
|
|
1039
|
+
c.tsw.WriteLiterally(">(")
|
|
1040
|
+
if err := c.substituteExprForShadowing(typeAssert.X, shadowingInfo); err != nil {
|
|
1041
|
+
return err
|
|
1042
|
+
}
|
|
1043
|
+
c.tsw.WriteLiterally(", ")
|
|
1044
|
+
c.writeTypeDescription(typeAssert.Type)
|
|
1045
|
+
c.tsw.WriteLiterally(")")
|
|
1102
1046
|
c.tsw.WriteLine("")
|
|
1103
1047
|
return nil
|
|
1104
1048
|
}
|
|
1105
1049
|
|
|
1106
|
-
//
|
|
1107
|
-
func (c *GoToTSCompiler)
|
|
1050
|
+
// substituteExprForShadowing writes an expression, replacing shadowed variables with temporary variables
|
|
1051
|
+
func (c *GoToTSCompiler) substituteExprForShadowing(expr ast.Expr, shadowingInfo *ShadowingInfo) error {
|
|
1108
1052
|
switch e := expr.(type) {
|
|
1109
1053
|
case *ast.Ident:
|
|
1110
1054
|
// Check if this identifier is a shadowed variable
|
|
@@ -1119,7 +1063,7 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1119
1063
|
|
|
1120
1064
|
case *ast.CallExpr:
|
|
1121
1065
|
// Handle function calls - replace identifiers in arguments with temp variables
|
|
1122
|
-
if err := c.
|
|
1066
|
+
if err := c.substituteExprForShadowing(e.Fun, shadowingInfo); err != nil {
|
|
1123
1067
|
return err
|
|
1124
1068
|
}
|
|
1125
1069
|
|
|
@@ -1131,7 +1075,7 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1131
1075
|
if i > 0 {
|
|
1132
1076
|
c.tsw.WriteLiterally(", ")
|
|
1133
1077
|
}
|
|
1134
|
-
if err := c.
|
|
1078
|
+
if err := c.substituteExprForShadowing(arg, shadowingInfo); err != nil {
|
|
1135
1079
|
return err
|
|
1136
1080
|
}
|
|
1137
1081
|
}
|
|
@@ -1140,7 +1084,7 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1140
1084
|
|
|
1141
1085
|
case *ast.SelectorExpr:
|
|
1142
1086
|
// Handle selector expressions (e.g., obj.Method)
|
|
1143
|
-
if err := c.
|
|
1087
|
+
if err := c.substituteExprForShadowing(e.X, shadowingInfo); err != nil {
|
|
1144
1088
|
return err
|
|
1145
1089
|
}
|
|
1146
1090
|
c.tsw.WriteLiterally(".")
|
|
@@ -1149,11 +1093,11 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1149
1093
|
|
|
1150
1094
|
case *ast.IndexExpr:
|
|
1151
1095
|
// Handle index expressions (e.g., arr[i])
|
|
1152
|
-
if err := c.
|
|
1096
|
+
if err := c.substituteExprForShadowing(e.X, shadowingInfo); err != nil {
|
|
1153
1097
|
return err
|
|
1154
1098
|
}
|
|
1155
1099
|
c.tsw.WriteLiterally("[")
|
|
1156
|
-
if err := c.
|
|
1100
|
+
if err := c.substituteExprForShadowing(e.Index, shadowingInfo); err != nil {
|
|
1157
1101
|
return err
|
|
1158
1102
|
}
|
|
1159
1103
|
c.tsw.WriteLiterally("]")
|
|
@@ -1162,22 +1106,22 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1162
1106
|
case *ast.UnaryExpr:
|
|
1163
1107
|
// Handle unary expressions (e.g., &x, -x)
|
|
1164
1108
|
c.tsw.WriteLiterally(e.Op.String())
|
|
1165
|
-
return c.
|
|
1109
|
+
return c.substituteExprForShadowing(e.X, shadowingInfo)
|
|
1166
1110
|
|
|
1167
1111
|
case *ast.BinaryExpr:
|
|
1168
1112
|
// Handle binary expressions (e.g., x + y)
|
|
1169
|
-
if err := c.
|
|
1113
|
+
if err := c.substituteExprForShadowing(e.X, shadowingInfo); err != nil {
|
|
1170
1114
|
return err
|
|
1171
1115
|
}
|
|
1172
1116
|
c.tsw.WriteLiterally(" ")
|
|
1173
1117
|
c.tsw.WriteLiterally(e.Op.String())
|
|
1174
1118
|
c.tsw.WriteLiterally(" ")
|
|
1175
|
-
return c.
|
|
1119
|
+
return c.substituteExprForShadowing(e.Y, shadowingInfo)
|
|
1176
1120
|
|
|
1177
1121
|
case *ast.ParenExpr:
|
|
1178
1122
|
// Handle parenthesized expressions
|
|
1179
1123
|
c.tsw.WriteLiterally("(")
|
|
1180
|
-
if err := c.
|
|
1124
|
+
if err := c.substituteExprForShadowing(e.X, shadowingInfo); err != nil {
|
|
1181
1125
|
return err
|
|
1182
1126
|
}
|
|
1183
1127
|
c.tsw.WriteLiterally(")")
|
|
@@ -1191,22 +1135,5 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
|
|
|
1191
1135
|
|
|
1192
1136
|
// isBuiltinFunction checks if the given name is a Go built-in function
|
|
1193
1137
|
func (c *GoToTSCompiler) isBuiltinFunction(name string) bool {
|
|
1194
|
-
|
|
1195
|
-
"len": true,
|
|
1196
|
-
"cap": true,
|
|
1197
|
-
"make": true,
|
|
1198
|
-
"new": true,
|
|
1199
|
-
"append": true,
|
|
1200
|
-
"copy": true,
|
|
1201
|
-
"delete": true,
|
|
1202
|
-
"complex": true,
|
|
1203
|
-
"real": true,
|
|
1204
|
-
"imag": true,
|
|
1205
|
-
"close": true,
|
|
1206
|
-
"panic": true,
|
|
1207
|
-
"recover": true,
|
|
1208
|
-
"print": true,
|
|
1209
|
-
"println": true,
|
|
1210
|
-
}
|
|
1211
|
-
return builtins[name]
|
|
1138
|
+
return builtinFunctions[name]
|
|
1212
1139
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"go/ast"
|
|
5
|
+
"go/types"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// isByteSliceType checks if a type is []byte (slice of uint8)
|
|
9
|
+
func (c *GoToTSCompiler) isByteSliceType(t types.Type) bool {
|
|
10
|
+
if sliceType, isSlice := t.Underlying().(*types.Slice); isSlice {
|
|
11
|
+
if basicElem, isBasic := sliceType.Elem().(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// isRuneSliceType checks if a type is []rune (slice of int32)
|
|
19
|
+
func (c *GoToTSCompiler) isRuneSliceType(t types.Type) bool {
|
|
20
|
+
if sliceType, isSlice := t.Underlying().(*types.Slice); isSlice {
|
|
21
|
+
if basicElem, isBasic := sliceType.Elem().(*types.Basic); isBasic && basicElem.Kind() == types.Int32 {
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// isStringType checks if a type is string
|
|
29
|
+
func (c *GoToTSCompiler) isStringType(t types.Type) bool {
|
|
30
|
+
if basic, isBasic := t.Underlying().(*types.Basic); isBasic {
|
|
31
|
+
return basic.Kind() == types.String || basic.Kind() == types.UntypedString
|
|
32
|
+
}
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// isPointerType checks if a type expression represents a pointer type
|
|
37
|
+
func (c *GoToTSCompiler) isPointerType(expr ast.Expr) bool {
|
|
38
|
+
_, isPointer := expr.(*ast.StarExpr)
|
|
39
|
+
return isPointer
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// isProtobufType checks if a given type is a protobuf type by examining its methods
|
|
43
|
+
// and, when available, by verifying it implements the protobuf-go-lite Message interface.
|
|
44
|
+
func (c *GoToTSCompiler) isProtobufType(typ types.Type) bool {
|
|
45
|
+
// Normalize to a named type if possible
|
|
46
|
+
var named *types.Named
|
|
47
|
+
switch t := typ.(type) {
|
|
48
|
+
case *types.Named:
|
|
49
|
+
named = t
|
|
50
|
+
case *types.Pointer:
|
|
51
|
+
if n, ok := t.Elem().(*types.Named); ok {
|
|
52
|
+
named = n
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if named == nil {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Prefer interface-based detection when the protobuf-go-lite package is loaded
|
|
60
|
+
if iface := c.getProtobufMessageInterface(); iface != nil {
|
|
61
|
+
if types.Implements(named, iface) || types.Implements(types.NewPointer(named), iface) {
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Fallback: method-set detection for common protobuf-go-lite methods
|
|
67
|
+
// Check both value and pointer method sets
|
|
68
|
+
if c.typeHasMethods(named, "MarshalVT", "UnmarshalVT") || c.typeHasMethods(types.NewPointer(named), "MarshalVT", "UnmarshalVT") {
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// isNamedNumericType checks if a given type is a named type with an underlying numeric type.
|
|
76
|
+
func (c *GoToTSCompiler) isNamedNumericType(t types.Type) bool {
|
|
77
|
+
finalType, wasNamed := c.getFinalUnderlyingType(t)
|
|
78
|
+
if !wasNamed {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if basicType, isBasic := finalType.(*types.Basic); isBasic {
|
|
83
|
+
info := basicType.Info()
|
|
84
|
+
return (info&types.IsInteger) != 0 || (info&types.IsFloat) != 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// isWrapperType checks if a type should be treated as a wrapper type (type alias with basic underlying type).
|
|
91
|
+
// Wrapper types are rendered as TypeScript type aliases rather than classes with constructors.
|
|
92
|
+
// Examples: os.FileMode (uint32), MyString (string), etc.
|
|
93
|
+
func (c *GoToTSCompiler) isWrapperType(t types.Type) bool {
|
|
94
|
+
// Check analysis cache first (for types with methods in analyzed packages)
|
|
95
|
+
if c.analysis.IsNamedBasicType(t) {
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// For external package types, check if it's a named type with a basic underlying type
|
|
100
|
+
if namedType, ok := t.(*types.Named); ok {
|
|
101
|
+
if _, ok := namedType.Underlying().(*types.Basic); ok {
|
|
102
|
+
return true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Also check for type aliases with basic underlying types
|
|
107
|
+
if aliasType, ok := t.(*types.Alias); ok {
|
|
108
|
+
if _, ok := aliasType.Underlying().(*types.Basic); ok {
|
|
109
|
+
return true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// isStructValueType checks if a type is a named struct type
|
|
117
|
+
func (c *GoToTSCompiler) isStructValueType(fieldType types.Type) bool {
|
|
118
|
+
if named, ok := fieldType.(*types.Named); ok {
|
|
119
|
+
if _, isStruct := named.Underlying().(*types.Struct); isStruct {
|
|
120
|
+
return true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// isImportedBasicType checks if a type is an imported named type with a basic underlying type
|
|
127
|
+
func (c *GoToTSCompiler) isImportedBasicType(fieldType types.Type) bool {
|
|
128
|
+
// Handle named types
|
|
129
|
+
if named, isNamed := fieldType.(*types.Named); isNamed {
|
|
130
|
+
obj := named.Obj()
|
|
131
|
+
if obj == nil || obj.Pkg() == nil || obj.Pkg() == c.pkg.Types {
|
|
132
|
+
return false // Not imported or is local
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
underlying := named.Underlying()
|
|
136
|
+
if underlying == nil {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_, isBasic := underlying.(*types.Basic)
|
|
141
|
+
return isBasic
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Handle type aliases (like os.FileMode = fs.FileMode)
|
|
145
|
+
if alias, isAlias := fieldType.(*types.Alias); isAlias {
|
|
146
|
+
obj := alias.Obj()
|
|
147
|
+
if obj == nil || obj.Pkg() == nil || obj.Pkg() == c.pkg.Types {
|
|
148
|
+
return false // Not imported or is local
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
underlying := alias.Underlying()
|
|
152
|
+
if underlying == nil {
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
_, isBasic := underlying.(*types.Basic)
|
|
157
|
+
return isBasic
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// isMapType checks if a type is a map type (including type parameters constrained to maps)
|
|
164
|
+
func (c *GoToTSCompiler) isMapType(iterType, underlying types.Type) bool {
|
|
165
|
+
if _, ok := underlying.(*types.Map); ok {
|
|
166
|
+
return true
|
|
167
|
+
}
|
|
168
|
+
if typeParam, isTypeParam := iterType.(*types.TypeParam); isTypeParam {
|
|
169
|
+
constraint := typeParam.Constraint()
|
|
170
|
+
if constraint != nil {
|
|
171
|
+
constraintUnderlying := constraint.Underlying()
|
|
172
|
+
if iface, isInterface := constraintUnderlying.(*types.Interface); isInterface {
|
|
173
|
+
return hasMapConstraint(iface)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// isArrayOrSlice checks if a type is an array or slice type
|
|
181
|
+
func (c *GoToTSCompiler) isArrayOrSlice(underlying types.Type) bool {
|
|
182
|
+
_, isSlice := underlying.(*types.Slice)
|
|
183
|
+
_, isArray := underlying.(*types.Array)
|
|
184
|
+
return isArray || isSlice
|
|
185
|
+
}
|