goscript 0.0.14 → 0.0.17

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 (182) hide show
  1. package/README.md +154 -40
  2. package/builtin/builtin.ts +1168 -178
  3. package/compiler/analysis.go +726 -0
  4. package/compiler/compiler.go +5706 -4
  5. package/compiler/compiler_test.go +104 -0
  6. package/compiler/config.go +3 -3
  7. package/compiler/config_test.go +89 -0
  8. package/compiler/output.go +26 -0
  9. package/compiler/write-type-spec.go +506 -0
  10. package/compiler/writer.go +25 -0
  11. package/dist/builtin/builtin.d.ts +204 -67
  12. package/dist/builtin/builtin.js +845 -144
  13. package/dist/builtin/builtin.js.map +1 -1
  14. package/go.mod +4 -7
  15. package/go.sum +6 -11
  16. package/package.json +4 -3
  17. package/compiler/compile.go +0 -190
  18. package/compiler/compile_comment.go +0 -41
  19. package/compiler/compile_decls.go +0 -84
  20. package/compiler/compile_expr.go +0 -1022
  21. package/compiler/compile_field.go +0 -110
  22. package/compiler/compile_spec.go +0 -566
  23. package/compiler/compile_stmt.go +0 -1616
  24. package/compiler/context.go +0 -9
  25. package/compiler/file_compiler.go +0 -80
  26. package/compiler/output_path.go +0 -31
  27. package/compiler/pkg_compiler.go +0 -72
  28. package/compiler/types/tokens.go +0 -66
  29. package/compiler/types/types.go +0 -46
  30. package/dist/compliance/tests/array_literal/array_literal.gs.d.ts +0 -1
  31. package/dist/compliance/tests/array_literal/array_literal.gs.js +0 -15
  32. package/dist/compliance/tests/array_literal/array_literal.gs.js.map +0 -1
  33. package/dist/compliance/tests/async_basic/async_basic.gs.d.ts +0 -1
  34. package/dist/compliance/tests/async_basic/async_basic.gs.js +0 -24
  35. package/dist/compliance/tests/async_basic/async_basic.gs.js.map +0 -1
  36. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.d.ts +0 -1
  37. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js +0 -82
  38. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js.map +0 -1
  39. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.d.ts +0 -1
  40. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js +0 -16
  41. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js.map +0 -1
  42. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.d.ts +0 -1
  43. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js +0 -14
  44. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js.map +0 -1
  45. package/dist/compliance/tests/channel_basic/channel_basic.gs.d.ts +0 -1
  46. package/dist/compliance/tests/channel_basic/channel_basic.gs.js +0 -14
  47. package/dist/compliance/tests/channel_basic/channel_basic.gs.js.map +0 -1
  48. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.d.ts +0 -1
  49. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js +0 -27
  50. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js.map +0 -1
  51. package/dist/compliance/tests/constants/constants.gs.d.ts +0 -1
  52. package/dist/compliance/tests/constants/constants.gs.js +0 -16
  53. package/dist/compliance/tests/constants/constants.gs.js.map +0 -1
  54. package/dist/compliance/tests/copy_independence/copy_independence.gs.d.ts +0 -1
  55. package/dist/compliance/tests/copy_independence/copy_independence.gs.js +0 -33
  56. package/dist/compliance/tests/copy_independence/copy_independence.gs.js.map +0 -1
  57. package/dist/compliance/tests/defer_statement/defer_statement.gs.d.ts +0 -1
  58. package/dist/compliance/tests/defer_statement/defer_statement.gs.js +0 -75
  59. package/dist/compliance/tests/defer_statement/defer_statement.gs.js.map +0 -1
  60. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.d.ts +0 -1
  61. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js +0 -37
  62. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js.map +0 -1
  63. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.d.ts +0 -1
  64. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js +0 -29
  65. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js.map +0 -1
  66. package/dist/compliance/tests/float64/float64.gs.d.ts +0 -1
  67. package/dist/compliance/tests/float64/float64.gs.js +0 -24
  68. package/dist/compliance/tests/float64/float64.gs.js.map +0 -1
  69. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.d.ts +0 -1
  70. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js +0 -10
  71. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js.map +0 -1
  72. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.d.ts +0 -1
  73. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js +0 -11
  74. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js.map +0 -1
  75. package/dist/compliance/tests/for_loop_condition_only/main.gs.d.ts +0 -1
  76. package/dist/compliance/tests/for_loop_condition_only/main.gs.js +0 -10
  77. package/dist/compliance/tests/for_loop_condition_only/main.gs.js.map +0 -1
  78. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.d.ts +0 -1
  79. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js +0 -14
  80. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js.map +0 -1
  81. package/dist/compliance/tests/for_range/for_range.gs.d.ts +0 -1
  82. package/dist/compliance/tests/for_range/for_range.gs.js +0 -39
  83. package/dist/compliance/tests/for_range/for_range.gs.js.map +0 -1
  84. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.d.ts +0 -1
  85. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js +0 -15
  86. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js.map +0 -1
  87. package/dist/compliance/tests/func_literal/func_literal.gs.d.ts +0 -1
  88. package/dist/compliance/tests/func_literal/func_literal.gs.js +0 -10
  89. package/dist/compliance/tests/func_literal/func_literal.gs.js.map +0 -1
  90. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.d.ts +0 -12
  91. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js +0 -30
  92. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js.map +0 -1
  93. package/dist/compliance/tests/if_statement/if_statement.gs.d.ts +0 -1
  94. package/dist/compliance/tests/if_statement/if_statement.gs.js +0 -13
  95. package/dist/compliance/tests/if_statement/if_statement.gs.js.map +0 -1
  96. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.d.ts +0 -1
  97. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js +0 -12
  98. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js.map +0 -1
  99. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.d.ts +0 -1
  100. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js +0 -34
  101. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js.map +0 -1
  102. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.d.ts +0 -1
  103. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js +0 -32
  104. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js.map +0 -1
  105. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.d.ts +0 -1
  106. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js +0 -40
  107. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js.map +0 -1
  108. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.d.ts +0 -1
  109. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js +0 -51
  110. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js.map +0 -1
  111. package/dist/compliance/tests/map_support/map_support.gs.d.ts +0 -1
  112. package/dist/compliance/tests/map_support/map_support.gs.js +0 -88
  113. package/dist/compliance/tests/map_support/map_support.gs.js.map +0 -1
  114. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.d.ts +0 -1
  115. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js +0 -24
  116. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js.map +0 -1
  117. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.d.ts +0 -1
  118. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js +0 -33
  119. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js.map +0 -1
  120. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.d.ts +0 -1
  121. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js +0 -22
  122. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js.map +0 -1
  123. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.d.ts +0 -1
  124. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js +0 -33
  125. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js.map +0 -1
  126. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.d.ts +0 -1
  127. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js +0 -17
  128. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js.map +0 -1
  129. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.d.ts +0 -1
  130. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js +0 -29
  131. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js.map +0 -1
  132. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.d.ts +0 -1
  133. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js +0 -27
  134. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js.map +0 -1
  135. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.d.ts +0 -1
  136. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js +0 -22
  137. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js.map +0 -1
  138. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.d.ts +0 -1
  139. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js +0 -20
  140. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js.map +0 -1
  141. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.d.ts +0 -1
  142. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js +0 -28
  143. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js.map +0 -1
  144. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.d.ts +0 -1
  145. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js +0 -30
  146. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js.map +0 -1
  147. package/dist/compliance/tests/select_statement/select_statement.gs.d.ts +0 -1
  148. package/dist/compliance/tests/select_statement/select_statement.gs.js +0 -207
  149. package/dist/compliance/tests/select_statement/select_statement.gs.js.map +0 -1
  150. package/dist/compliance/tests/simple/simple.gs.d.ts +0 -1
  151. package/dist/compliance/tests/simple/simple.gs.js +0 -6
  152. package/dist/compliance/tests/simple/simple.gs.js.map +0 -1
  153. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.d.ts +0 -1
  154. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js +0 -24
  155. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js.map +0 -1
  156. package/dist/compliance/tests/slices/slices.gs.d.ts +0 -1
  157. package/dist/compliance/tests/slices/slices.gs.js +0 -294
  158. package/dist/compliance/tests/slices/slices.gs.js.map +0 -1
  159. package/dist/compliance/tests/string_conversion/string_conversion.gs.d.ts +0 -1
  160. package/dist/compliance/tests/string_conversion/string_conversion.gs.js +0 -41
  161. package/dist/compliance/tests/string_conversion/string_conversion.gs.js.map +0 -1
  162. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.d.ts +0 -1
  163. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js +0 -17
  164. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js.map +0 -1
  165. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.d.ts +0 -1
  166. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js +0 -48
  167. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js.map +0 -1
  168. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.d.ts +0 -1
  169. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js +0 -19
  170. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js.map +0 -1
  171. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.d.ts +0 -1
  172. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js +0 -26
  173. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js.map +0 -1
  174. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.d.ts +0 -1
  175. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js +0 -30
  176. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js.map +0 -1
  177. package/dist/compliance/tests/switch_statement/switch_statement.gs.d.ts +0 -1
  178. package/dist/compliance/tests/switch_statement/switch_statement.gs.js +0 -76
  179. package/dist/compliance/tests/switch_statement/switch_statement.gs.js.map +0 -1
  180. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.d.ts +0 -1
  181. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js +0 -31
  182. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js.map +0 -1
@@ -1,1022 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "errors"
5
- "fmt"
6
- "go/ast"
7
- "go/token"
8
- gtypes "go/types"
9
- "strconv"
10
- "strings"
11
-
12
- gstypes "github.com/aperturerobotics/goscript/compiler/types"
13
- )
14
-
15
- // WriteTypeExpr writes an expression that represents a type.
16
- func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
17
- switch exp := a.(type) {
18
- case *ast.Ident:
19
- c.WriteIdentType(exp)
20
- case *ast.SelectorExpr:
21
- if err := c.WriteSelectorExprType(exp); err != nil {
22
- c.tsw.WriteCommentInline(fmt.Sprintf("error writing selector expr type: %v", err))
23
- }
24
- case *ast.StarExpr:
25
- c.WriteStarExprType(exp)
26
- case *ast.StructType:
27
- c.WriteStructType(exp)
28
- case *ast.InterfaceType:
29
- c.WriteInterfaceType(exp)
30
- case *ast.FuncType:
31
- c.WriteFuncType(exp, false) // Function types are not async
32
- case *ast.ArrayType:
33
- // Translate [N]T to T[]
34
- c.WriteTypeExpr(exp.Elt)
35
- c.tsw.WriteLiterally("[]")
36
- case *ast.MapType:
37
- // Map<K,V> → TS object type { [key: K]: V }
38
- c.tsw.WriteLiterally("{ [key: ")
39
- c.WriteTypeExpr(exp.Key)
40
- c.tsw.WriteLiterally("]: ")
41
- c.WriteTypeExpr(exp.Value)
42
- c.tsw.WriteLiterally(" }")
43
- case *ast.ChanType:
44
- // Translate channel types to goscript.Channel<T>
45
- c.tsw.WriteLiterally("goscript.Channel<")
46
- c.WriteTypeExpr(exp.Value) // Write the element type
47
- c.tsw.WriteLiterally(">")
48
- default:
49
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled type expr: %T (map/chan support pending)", exp))
50
- }
51
- }
52
-
53
- // WriteValueExpr writes an expression that represents a value.
54
- func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
55
- switch exp := a.(type) {
56
- case *ast.Ident:
57
- c.WriteIdentValue(exp)
58
- return nil
59
- case *ast.SelectorExpr:
60
- return c.WriteSelectorExprValue(exp)
61
- case *ast.StarExpr:
62
- return c.WriteStarExprValue(exp)
63
- case *ast.CallExpr:
64
- return c.WriteCallExpr(exp)
65
- case *ast.UnaryExpr:
66
- return c.WriteUnaryExprValue(exp)
67
- case *ast.BinaryExpr:
68
- return c.WriteBinaryExprValue(exp)
69
- case *ast.BasicLit:
70
- c.WriteBasicLitValue(exp)
71
- return nil
72
- case *ast.CompositeLit:
73
- return c.WriteCompositeLitValue(exp)
74
- case *ast.KeyValueExpr:
75
- return c.WriteKeyValueExprValue(exp)
76
- case *ast.TypeAssertExpr:
77
- // Handle type assertion in an expression context
78
- return c.WriteTypeAssertExpr(exp)
79
- case *ast.IndexExpr:
80
- // Handle map access: use Map.get() instead of brackets for reading values
81
- if tv, ok := c.pkg.TypesInfo.Types[exp.X]; ok {
82
- // Check if it's a map type
83
- if _, isMap := tv.Type.Underlying().(*gtypes.Map); isMap {
84
- if err := c.WriteValueExpr(exp.X); err != nil {
85
- return err
86
- }
87
- c.tsw.WriteLiterally(".get(")
88
- if err := c.WriteValueExpr(exp.Index); err != nil {
89
- return err
90
- }
91
- // Note: For map access (reading), Go returns the zero value if the key doesn't exist.
92
- // We need to handle this in TS. For now, default to 0 or null based on type.
93
- // A more robust solution would involve checking the expected type of the context.
94
- // For simplicity, let's add a comment indicating this might need refinement.
95
- c.tsw.WriteLiterally(")") // No ?? 0 here, get() returns undefined if not found
96
- // c.tsw.WriteCommentInline("map access might need zero value handling")
97
- return nil
98
- }
99
- }
100
-
101
- // Regular array/slice access: use brackets
102
- if err := c.WriteValueExpr(exp.X); err != nil {
103
- return err
104
- }
105
- c.tsw.WriteLiterally("[")
106
- if err := c.WriteValueExpr(exp.Index); err != nil {
107
- return err
108
- }
109
- c.tsw.WriteLiterally("]")
110
- return nil
111
- case *ast.SliceExpr:
112
- // Translate Go slice expression to goscript.slice(x, low, high, max)
113
- c.tsw.WriteLiterally("goscript.slice(")
114
- if err := c.WriteValueExpr(exp.X); err != nil {
115
- return err
116
- }
117
- // low argument
118
- c.tsw.WriteLiterally(", ")
119
- if exp.Low != nil {
120
- if err := c.WriteValueExpr(exp.Low); err != nil {
121
- return err
122
- }
123
- } else {
124
- c.tsw.WriteLiterally("undefined")
125
- }
126
- // high argument
127
- c.tsw.WriteLiterally(", ")
128
- if exp.High != nil {
129
- if err := c.WriteValueExpr(exp.High); err != nil {
130
- return err
131
- }
132
- } else {
133
- c.tsw.WriteLiterally("undefined")
134
- }
135
- // max argument (only for full slice expressions)
136
- if exp.Slice3 {
137
- c.tsw.WriteLiterally(", ")
138
- if exp.Max != nil {
139
- if err := c.WriteValueExpr(exp.Max); err != nil {
140
- return err
141
- }
142
- } else {
143
- c.tsw.WriteLiterally("undefined")
144
- }
145
- }
146
- c.tsw.WriteLiterally(")")
147
- return nil
148
- case *ast.ParenExpr:
149
- // Translate (X) to (X)
150
- c.tsw.WriteLiterally("(")
151
- if err := c.WriteValueExpr(exp.X); err != nil {
152
- return err
153
- }
154
- c.tsw.WriteLiterally(")")
155
- return nil
156
- case *ast.FuncLit:
157
- return c.WriteFuncLitValue(exp)
158
- // Add cases for SliceExpr etc.
159
- default:
160
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled value expr: %T", exp))
161
- return nil
162
- }
163
- }
164
-
165
- // WriteTypeAssertExpr writes a type assertion expression.
166
- func (c *GoToTSCompiler) WriteTypeAssertExpr(exp *ast.TypeAssertExpr) error {
167
- // Get the type name string for the asserted type
168
- typeName := c.getTypeNameString(exp.Type)
169
-
170
- // Generate a call to goscript.typeAssert
171
- c.tsw.WriteLiterally("goscript.typeAssert<")
172
- c.WriteTypeExpr(exp.Type) // Write the asserted type for the generic
173
- c.tsw.WriteLiterally(">(")
174
- if err := c.WriteValueExpr(exp.X); err != nil { // The interface expression
175
- return fmt.Errorf("failed to write interface expression in type assertion expression: %w", err)
176
- }
177
- c.tsw.WriteLiterally(", ")
178
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", typeName))
179
- c.tsw.WriteLiterally(").value") // Access the value field directly in expression context
180
- return nil
181
- }
182
-
183
- // getTypeNameString returns the string representation of a type name
184
- func (c *GoToTSCompiler) getTypeNameString(typeExpr ast.Expr) string {
185
- switch t := typeExpr.(type) {
186
- case *ast.Ident:
187
- return t.Name
188
- case *ast.SelectorExpr:
189
- // For imported types like pkg.Type
190
- if ident, ok := t.X.(*ast.Ident); ok {
191
- return fmt.Sprintf("%s.%s", ident.Name, t.Sel.Name)
192
- }
193
- }
194
- // Default case, use a placeholder for complex types
195
- return "unknown"
196
- }
197
-
198
- // --- Exported Node-Specific Writers ---
199
-
200
- // WriteIdentType writes an identifier used as a type.
201
- func (c *GoToTSCompiler) WriteIdentType(exp *ast.Ident) {
202
- name := exp.Name
203
-
204
- // Special case for the built-in error interface
205
- if name == "error" {
206
- c.tsw.WriteLiterally("goscript.Error")
207
- return
208
- }
209
-
210
- if tsname, ok := gstypes.GoBuiltinToTypescript(name); ok {
211
- name = tsname
212
- } else {
213
- // Not a Go builtin. Could be a custom type in the current package,
214
- // an imported type, or potentially an error.
215
- // Robust checking requires type information.
216
- if obj := exp.Obj; obj != nil && obj.Kind != ast.Typ {
217
- c.tsw.WriteCommentInline(fmt.Sprintf("ident %q used as type? kind=%s", name, obj.Kind))
218
- }
219
-
220
- // TODO use type information to check
221
-
222
- //else if obj == nil {
223
- // If obj is nil, it might be a type from an import or undefined.
224
- // Type checking pass should resolve this.
225
- // c.tsw.WriteCommentInline(fmt.Sprintf("unresolved ident %q used as type", name))
226
- //}
227
-
228
- // Assume it's a valid custom type name for now.
229
- }
230
-
231
- c.tsw.WriteLiterally(name)
232
- }
233
-
234
- // WriteIdentValue writes an identifier used as a value (variable, function name, nil).
235
- func (c *GoToTSCompiler) WriteIdentValue(exp *ast.Ident) {
236
- if exp.Name == "nil" {
237
- c.tsw.WriteLiterally("null")
238
- } else {
239
- c.tsw.WriteLiterally(exp.Name)
240
- }
241
- }
242
-
243
- // WriteSelectorExprType writes a selector expression used as a type (e.g., pkg.Type).
244
- func (c *GoToTSCompiler) WriteSelectorExprType(exp *ast.SelectorExpr) error {
245
- // Assuming X is a package identifier. Needs refinement with type info.
246
- if err := c.WriteValueExpr(exp.X); err != nil { // Package name is treated as a value
247
- return fmt.Errorf("failed to write selector expression package identifier: %w", err)
248
- }
249
- c.tsw.WriteLiterally(".")
250
- c.WriteTypeExpr(exp.Sel) // The selected identifier is treated as a type
251
- return nil
252
- }
253
-
254
- // WriteSelectorExprValue writes a selector expression used as a value (e.g., obj.Field).
255
- func (c *GoToTSCompiler) WriteSelectorExprValue(exp *ast.SelectorExpr) error {
256
- if err := c.WriteValueExpr(exp.X); err != nil {
257
- return fmt.Errorf("failed to write selector expression object: %w", err)
258
- }
259
- c.tsw.WriteLiterally(".")
260
- c.WriteIdentValue(exp.Sel)
261
- return nil
262
- }
263
-
264
- // WriteStarExprType writes a pointer type (e.g., *MyStruct).
265
- func (c *GoToTSCompiler) WriteStarExprType(exp *ast.StarExpr) {
266
- // Map pointer types to T | null
267
- c.WriteTypeExpr(exp.X)
268
- c.tsw.WriteLiterally(" | null")
269
- }
270
-
271
- // WriteStarExprValue writes a pointer dereference value (e.g., *myVar).
272
- func (c *GoToTSCompiler) WriteStarExprValue(exp *ast.StarExpr) error {
273
- // Dereferencing a pointer in Go (*p) gets the value.
274
- // In TS, if p is MyStruct | null, accessing the value means just using p.
275
- // Cloning to emulate value semantics happens during assignment (see WriteStmtAssign).
276
- if err := c.WriteValueExpr(exp.X); err != nil {
277
- return fmt.Errorf("failed to write star expression operand: %w", err)
278
- }
279
- return nil
280
- }
281
-
282
- // WriteStructType writes a struct type definition.
283
- func (c *GoToTSCompiler) WriteStructType(exp *ast.StructType) {
284
- if exp.Fields == nil || exp.Fields.NumFields() == 0 {
285
- c.tsw.WriteLiterally("{}")
286
- return
287
- }
288
- c.WriteFieldList(exp.Fields, false) // false = not arguments
289
- }
290
-
291
- // WriteInterfaceType writes an interface type definition.
292
- func (c *GoToTSCompiler) WriteInterfaceType(exp *ast.InterfaceType) {
293
- var embeddedInterfaces []string
294
- var methods []*ast.Field
295
-
296
- if exp.Methods != nil {
297
- for _, method := range exp.Methods.List {
298
- if len(method.Names) > 0 {
299
- // Named method
300
- methods = append(methods, method)
301
- } else {
302
- // Embedded interface - collect the type name using type info
303
- if tv, ok := c.pkg.TypesInfo.Types[method.Type]; ok && tv.Type != nil {
304
- if namedType, ok := tv.Type.(*gtypes.Named); ok {
305
- embeddedInterfaces = append(embeddedInterfaces, namedType.Obj().Name())
306
- } else {
307
- c.tsw.WriteCommentLine(fmt.Sprintf("// Unhandled embedded interface type: %T", tv.Type))
308
- }
309
- } else {
310
- c.tsw.WriteCommentLine("// Could not resolve embedded interface type")
311
- }
312
- }
313
- }
314
- }
315
-
316
- // If there are embedded interfaces, write the extends clause
317
- if len(embeddedInterfaces) > 0 {
318
- c.tsw.WriteLiterally("extends ")
319
- c.tsw.WriteLiterally(strings.Join(embeddedInterfaces, ", "))
320
- c.tsw.WriteLiterally(" ")
321
- }
322
-
323
- // Write the interface body on the same line
324
- c.tsw.WriteLiterally("{")
325
- c.tsw.WriteLine("") // Newline after opening brace
326
- c.tsw.Indent(1)
327
-
328
- // Write named methods
329
- for _, method := range methods {
330
- if err := c.WriteInterfaceMethodSignature(method); err != nil {
331
- c.tsw.WriteCommentInline(fmt.Sprintf("error writing interface method signature: %v", err))
332
- }
333
- }
334
-
335
- c.tsw.Indent(-1)
336
- c.tsw.WriteLine("}")
337
- }
338
-
339
- // WriteFuncType writes a function type signature.
340
- func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
341
- c.tsw.WriteLiterally("(")
342
- c.WriteFieldList(exp.Params, true) // true = arguments
343
- c.tsw.WriteLiterally(")")
344
- if exp.Results != nil && len(exp.Results.List) > 0 {
345
- // Use colon for return type annotation
346
- c.tsw.WriteLiterally(": ")
347
- if isAsync {
348
- c.tsw.WriteLiterally("Promise<")
349
- }
350
- if len(exp.Results.List) == 1 && len(exp.Results.List[0].Names) == 0 {
351
- // Single unnamed return type
352
- c.WriteTypeExpr(exp.Results.List[0].Type)
353
- } else {
354
- // Multiple or named return types -> tuple
355
- c.tsw.WriteLiterally("[")
356
- for i, field := range exp.Results.List {
357
- if i > 0 {
358
- c.tsw.WriteLiterally(", ")
359
- }
360
- c.WriteTypeExpr(field.Type)
361
- }
362
- c.tsw.WriteLiterally("]")
363
- }
364
- if isAsync {
365
- c.tsw.WriteLiterally(">")
366
- }
367
- } else {
368
- // No return value -> void
369
- if isAsync {
370
- c.tsw.WriteLiterally(": Promise<void>")
371
- } else {
372
- c.tsw.WriteLiterally(": void")
373
- }
374
- }
375
- }
376
-
377
- // WriteCallExpr writes a function call.
378
- func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
379
- expFun := exp.Fun
380
-
381
- // Handle array type conversions like []rune(string)
382
- if arrayType, isArrayType := expFun.(*ast.ArrayType); isArrayType {
383
- // Check if it's a []rune type
384
- if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
385
- // Check if the argument is a string
386
- if len(exp.Args) == 1 {
387
- arg := exp.Args[0]
388
- if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
389
- if basic, isBasic := tv.Type.Underlying().(*gtypes.Basic); isBasic && basic.Kind() == gtypes.String {
390
- // Translate []rune(stringValue) to goscript.stringToRunes(stringValue)
391
- c.tsw.WriteLiterally("goscript.stringToRunes(")
392
- if err := c.WriteValueExpr(arg); err != nil {
393
- return fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
394
- }
395
- c.tsw.WriteLiterally(")")
396
- return nil // Handled []rune(string)
397
- }
398
- }
399
- }
400
- }
401
- }
402
-
403
- if funIdent, funIsIdent := expFun.(*ast.Ident); funIsIdent {
404
- switch funIdent.String() {
405
- case "println":
406
- c.tsw.WriteLiterally("console.log(")
407
- for i, arg := range exp.Args {
408
- if i != 0 {
409
- c.tsw.WriteLiterally(", ")
410
- }
411
- if err := c.WriteValueExpr(arg); err != nil {
412
- return err
413
- }
414
- }
415
- c.tsw.WriteLiterally(")")
416
- return nil
417
- case "len":
418
- // Translate len(arg) to goscript.len(arg)
419
- if len(exp.Args) == 1 {
420
- c.tsw.WriteLiterally("goscript.len(")
421
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
422
- return err
423
- }
424
- c.tsw.WriteLiterally(")")
425
- return nil // Handled len
426
- }
427
- return errors.New("unhandled len call with incorrect number of arguments")
428
- case "cap":
429
- // Translate cap(arg) to goscript.cap(arg)
430
- if len(exp.Args) == 1 {
431
- c.tsw.WriteLiterally("goscript.cap(")
432
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
433
- return err
434
- }
435
- c.tsw.WriteLiterally(")")
436
- return nil // Handled cap
437
- }
438
- return errors.New("unhandled cap call with incorrect number of arguments")
439
- case "delete":
440
- // Translate delete(map, key) to goscript.deleteMapEntry(map, key)
441
- if len(exp.Args) == 2 {
442
- c.tsw.WriteLiterally("goscript.deleteMapEntry(")
443
- if err := c.WriteValueExpr(exp.Args[0]); err != nil { // Map
444
- return err
445
- }
446
- c.tsw.WriteLiterally(", ")
447
- if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Key
448
- return err
449
- }
450
- c.tsw.WriteLiterally(")")
451
- return nil // Handled delete
452
- }
453
- return errors.New("unhandled delete call with incorrect number of arguments")
454
- case "make":
455
- // First check if we have a channel type
456
- if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
457
- if chanType, ok := typ.Underlying().(*gtypes.Chan); ok {
458
- // Handle channel creation: make(chan T, bufferSize) or make(chan T)
459
- c.tsw.WriteLiterally("goscript.makeChannel<")
460
- c.WriteGoType(chanType.Elem())
461
- c.tsw.WriteLiterally(">(")
462
-
463
- // If buffer size is provided, add it
464
- if len(exp.Args) >= 2 {
465
- if err := c.WriteValueExpr(exp.Args[1]); err != nil {
466
- return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
467
- }
468
- } else {
469
- // Default to 0 (unbuffered channel)
470
- c.tsw.WriteLiterally("0")
471
- }
472
-
473
- c.tsw.WriteLiterally(", ") // Add comma for zero value argument
474
-
475
- // Write the zero value for the channel's element type
476
- c.WriteZeroValueForType(chanType.Elem())
477
-
478
- c.tsw.WriteLiterally(")")
479
- return nil // Handled make for channel
480
- }
481
- }
482
- // Handle make for slices: make([]T, len, cap) or make([]T, len)
483
- if len(exp.Args) >= 1 {
484
- // Handle map creation: make(map[K]V)
485
- if mapType, ok := exp.Args[0].(*ast.MapType); ok {
486
- c.tsw.WriteLiterally("goscript.makeMap<")
487
- c.WriteTypeExpr(mapType.Key) // Write the key type
488
- c.tsw.WriteLiterally(", ")
489
- c.WriteTypeExpr(mapType.Value) // Write the value type
490
- c.tsw.WriteLiterally(">()")
491
- return nil // Handled make for map
492
- }
493
-
494
- // Handle slice creation
495
- if _, ok := exp.Args[0].(*ast.ArrayType); ok {
496
- // Get the slice type information
497
- sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
498
- if sliceType == nil {
499
- return errors.New("could not get type information for slice in make call")
500
- }
501
- goElemType, ok := sliceType.Underlying().(*gtypes.Slice)
502
- if !ok {
503
- return errors.New("expected slice type for make call")
504
- }
505
-
506
- c.tsw.WriteLiterally("goscript.makeSlice<")
507
- c.WriteGoType(goElemType.Elem()) // Write the element type
508
- c.tsw.WriteLiterally(">(")
509
-
510
- if len(exp.Args) >= 2 {
511
- if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
512
- return err
513
- }
514
- if len(exp.Args) == 3 {
515
- c.tsw.WriteLiterally(", ")
516
- if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
517
- return err
518
- }
519
- } else if len(exp.Args) > 3 {
520
- return errors.New("makeSlice expects 2 or 3 arguments")
521
- }
522
- } else {
523
- // If no length is provided, default to 0
524
- c.tsw.WriteLiterally("0")
525
- }
526
- c.tsw.WriteLiterally(")")
527
- return nil // Handled make for slice
528
- }
529
- }
530
- // Fallthrough for unhandled make calls (e.g., channels)
531
- return errors.New("unhandled make call")
532
- case "string":
533
- // Handle string() conversion
534
- if len(exp.Args) == 1 {
535
- arg := exp.Args[0]
536
-
537
- // Case 1: Argument is a string literal string("...")
538
- if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
539
- // Translate string("...") to "..." (no-op)
540
- c.WriteBasicLitValue(basicLit)
541
- return nil // Handled string literal conversion
542
- }
543
-
544
- // Case 2: Argument is a rune (int32) or a call to rune()
545
- innerCall, isCallExpr := arg.(*ast.CallExpr)
546
-
547
- if isCallExpr {
548
- // Check if it's a call to rune()
549
- if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
550
- // Translate string(rune(val)) to String.fromCharCode(val)
551
- if len(innerCall.Args) == 1 {
552
- c.tsw.WriteLiterally("String.fromCharCode(")
553
- if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
554
- return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
555
- }
556
- c.tsw.WriteLiterally(")")
557
- return nil // Handled string(rune)
558
- }
559
- }
560
- }
561
-
562
- // Handle direct string(int32) conversion
563
- // This assumes 'rune' is int32
564
- if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
565
- if basic, isBasic := tv.Type.Underlying().(*gtypes.Basic); isBasic && basic.Kind() == gtypes.Int32 {
566
- // Translate string(rune_val) to String.fromCharCode(rune_val)
567
- c.tsw.WriteLiterally("String.fromCharCode(")
568
- if err := c.WriteValueExpr(arg); err != nil {
569
- return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
570
- }
571
- c.tsw.WriteLiterally(")")
572
- return nil // Handled string(int32)
573
- }
574
-
575
- // Case 3: Argument is a slice of runes string([]rune{...})
576
- if sliceType, isSlice := tv.Type.Underlying().(*gtypes.Slice); isSlice {
577
- if basic, isBasic := sliceType.Elem().Underlying().(*gtypes.Basic); isBasic && basic.Kind() == gtypes.Int32 {
578
- // Translate string([]rune) to goscript.runesToString(...)
579
- c.tsw.WriteLiterally("goscript.runesToString(")
580
- if err := c.WriteValueExpr(arg); err != nil {
581
- return fmt.Errorf("failed to write argument for string([]rune) conversion: %w", err)
582
- }
583
- c.tsw.WriteLiterally(")")
584
- return nil // Handled string([]rune)
585
- }
586
- }
587
- }
588
- }
589
- // Return error for other unhandled string conversions
590
- return fmt.Errorf("unhandled string conversion: %s", exp.Fun)
591
- case "close":
592
- // Translate close(ch) to ch.close()
593
- if len(exp.Args) == 1 {
594
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
595
- return fmt.Errorf("failed to write channel in close call: %w", err)
596
- }
597
- c.tsw.WriteLiterally(".close()")
598
- return nil // Handled close
599
- }
600
- return errors.New("unhandled close call with incorrect number of arguments")
601
- case "append":
602
- // Translate append(slice, elements...) to goscript.append(slice, elements...)
603
- if len(exp.Args) >= 1 {
604
- c.tsw.WriteLiterally("goscript.append(")
605
- // The first argument is the slice
606
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
607
- return fmt.Errorf("failed to write slice in append call: %w", err)
608
- }
609
- // The remaining arguments are the elements to append
610
- for i, arg := range exp.Args[1:] {
611
- if i > 0 || len(exp.Args) > 1 { // Add comma before elements if there are any
612
- c.tsw.WriteLiterally(", ")
613
- }
614
- if err := c.WriteValueExpr(arg); err != nil {
615
- return fmt.Errorf("failed to write argument %d in append call: %w", i+1, err)
616
- }
617
- }
618
- c.tsw.WriteLiterally(")")
619
- return nil // Handled append
620
- }
621
- return errors.New("unhandled append call with incorrect number of arguments")
622
- default:
623
- // Check if this is an async function call
624
- if funIdent != nil && c.isAsyncFunc(funIdent.Name) {
625
- c.tsw.WriteLiterally("await ")
626
- }
627
-
628
- // Not a special built-in, treat as a regular function call
629
- if err := c.WriteValueExpr(expFun); err != nil {
630
- return fmt.Errorf("failed to write function expression in call: %w", err)
631
- }
632
- c.tsw.WriteLiterally("(")
633
- for i, arg := range exp.Args {
634
- if i != 0 {
635
- c.tsw.WriteLiterally(", ")
636
- }
637
- if err := c.WriteValueExpr(arg); err != nil {
638
- return fmt.Errorf("failed to write argument %d in call: %w", i, err)
639
- }
640
- }
641
- c.tsw.WriteLiterally(")")
642
- return nil // Handled regular function call
643
- }
644
- } else {
645
- // Not an identifier (e.g., method call on a value)
646
- if err := c.WriteValueExpr(expFun); err != nil {
647
- return fmt.Errorf("failed to write method expression in call: %w", err)
648
- }
649
- }
650
- c.tsw.WriteLiterally("(")
651
- for i, arg := range exp.Args {
652
- if i != 0 {
653
- c.tsw.WriteLiterally(", ")
654
- }
655
- if err := c.WriteValueExpr(arg); err != nil {
656
- return fmt.Errorf("failed to write argument %d in call: %w", i, err)
657
- }
658
- }
659
- c.tsw.WriteLiterally(")")
660
- return nil
661
- }
662
-
663
- // WriteUnaryExprValue writes a unary operation on a value.
664
- func (c *GoToTSCompiler) WriteUnaryExprValue(exp *ast.UnaryExpr) error {
665
- if exp.Op == token.ARROW {
666
- // Channel receive: <-ch becomes await ch.receive()
667
- c.tsw.WriteLiterally("await ")
668
- if err := c.WriteValueExpr(exp.X); err != nil {
669
- return fmt.Errorf("failed to write channel receive operand: %w", err)
670
- }
671
- c.tsw.WriteLiterally(".receive()")
672
- return nil
673
- }
674
-
675
- if exp.Op == token.AND {
676
- // Address-of operator (&) might translate to just the value in TS,
677
- // or potentially involve reference objects if complex pointer logic is needed.
678
- // For now, just write the operand.
679
- if err := c.WriteValueExpr(exp.X); err != nil {
680
- return fmt.Errorf("failed to write unary expression operand for address-of: %w", err)
681
- }
682
- return nil
683
- }
684
-
685
- tokStr, ok := gstypes.TokenToTs(exp.Op)
686
- if !ok {
687
- c.tsw.WriteCommentInline(fmt.Sprintf("unhandled unary op: %s", exp.Op.String()))
688
- } else {
689
- c.tsw.WriteLiterally(tokStr)
690
- }
691
- if err := c.WriteValueExpr(exp.X); err != nil {
692
- return fmt.Errorf("failed to write unary expression operand: %w", err)
693
- }
694
- return nil
695
- }
696
-
697
- // WriteBinaryExprValue writes a binary operation on values.
698
- func (c *GoToTSCompiler) WriteBinaryExprValue(exp *ast.BinaryExpr) error {
699
- // Handle special cases like channel send
700
- if exp.Op == token.ARROW {
701
- // Channel send: ch <- val becomes await ch.send(val)
702
- c.tsw.WriteLiterally("await ")
703
- if err := c.WriteValueExpr(exp.X); err != nil {
704
- return fmt.Errorf("failed to write channel send target: %w", err)
705
- }
706
- c.tsw.WriteLiterally(".send(")
707
- if err := c.WriteValueExpr(exp.Y); err != nil {
708
- return fmt.Errorf("failed to write channel send value: %w", err)
709
- }
710
- c.tsw.WriteLiterally(")")
711
- return nil
712
- }
713
-
714
- // Check if the operator is a bitwise operator
715
- isBitwise := false
716
- switch exp.Op {
717
- case token.AND, token.OR, token.XOR, token.SHL, token.SHR, token.AND_NOT:
718
- isBitwise = true
719
- }
720
-
721
- if isBitwise {
722
- c.tsw.WriteLiterally("(") // Add opening parenthesis for bitwise operations
723
- }
724
-
725
- if err := c.WriteValueExpr(exp.X); err != nil {
726
- return fmt.Errorf("failed to write binary expression left operand: %w", err)
727
- }
728
- c.tsw.WriteLiterally(" ")
729
- tokStr, ok := gstypes.TokenToTs(exp.Op)
730
- if !ok {
731
- c.tsw.WriteCommentInline(fmt.Sprintf("unhandled binary op: %s", exp.Op.String()))
732
- c.tsw.WriteLiterally(" /* op */ ")
733
- } else {
734
- c.tsw.WriteLiterally(tokStr)
735
- }
736
- c.tsw.WriteLiterally(" ")
737
- if err := c.WriteValueExpr(exp.Y); err != nil {
738
- return fmt.Errorf("failed to write binary expression right operand: %w", err)
739
- }
740
-
741
- if isBitwise {
742
- c.tsw.WriteLiterally(")") // Add closing parenthesis for bitwise operations
743
- }
744
-
745
- return nil
746
- }
747
-
748
- // WriteBasicLitValue writes a basic literal value.
749
- func (c *GoToTSCompiler) WriteBasicLitValue(exp *ast.BasicLit) {
750
- if exp.Kind == token.CHAR {
751
- // Go char literal 'x' is a rune (int32). Translate to its numeric code point.
752
- // Use strconv.UnquoteChar to handle escape sequences correctly.
753
- val, _, _, err := strconv.UnquoteChar(exp.Value[1:len(exp.Value)-1], '\'')
754
- if err != nil {
755
- c.tsw.WriteCommentInline(fmt.Sprintf("error parsing char literal %s: %v", exp.Value, err))
756
- c.tsw.WriteLiterally("0") // Default to 0 on error
757
- } else {
758
- c.tsw.WriteLiterally(fmt.Sprintf("%d", val))
759
- }
760
- } else {
761
- // Other literals (INT, FLOAT, STRING, IMAG)
762
- c.tsw.WriteLiterally(exp.Value)
763
- }
764
- }
765
-
766
- /*
767
- WriteCompositeLitValue writes a composite literal value.
768
- For array literals, uses type information to determine array length and element type,
769
- and fills uninitialized elements with the correct zero value.
770
- For map literals, creates a new Map with entries.
771
- */
772
- func (c *GoToTSCompiler) WriteCompositeLitValue(exp *ast.CompositeLit) error {
773
- if exp.Type != nil {
774
- // Handle map literals: map[K]V{k1: v1, k2: v2}
775
- if _, isMapType := exp.Type.(*ast.MapType); isMapType {
776
- c.tsw.WriteLiterally("new Map([")
777
-
778
- // Add each key-value pair as an entry
779
- for i, elm := range exp.Elts {
780
- if i > 0 {
781
- c.tsw.WriteLiterally(", ")
782
- }
783
-
784
- if kv, ok := elm.(*ast.KeyValueExpr); ok {
785
- c.tsw.WriteLiterally("[")
786
- if err := c.WriteValueExpr(kv.Key); err != nil {
787
- return fmt.Errorf("failed to write map literal key: %w", err)
788
- }
789
- c.tsw.WriteLiterally(", ")
790
- if err := c.WriteValueExpr(kv.Value); err != nil {
791
- return fmt.Errorf("failed to write map literal value: %w", err)
792
- }
793
- c.tsw.WriteLiterally("]")
794
- } else {
795
- return fmt.Errorf("map literal elements must be key-value pairs")
796
- }
797
- }
798
-
799
- c.tsw.WriteLiterally("])")
800
- return nil
801
- }
802
-
803
- // Handle array literals
804
- if arrType, isArrayType := exp.Type.(*ast.ArrayType); isArrayType {
805
- // Special case: empty slice literal
806
- if len(exp.Elts) == 0 {
807
- // Generate: ([] as ElementType[])
808
- c.tsw.WriteLiterally("([] as ")
809
- // Write the element type using the existing function
810
- c.WriteTypeExpr(arrType.Elt)
811
- c.tsw.WriteLiterally("[])") // Close the type assertion
812
- return nil // Handled empty slice literal
813
- }
814
-
815
- c.tsw.WriteLiterally("[")
816
- // Use type info to get array length and element type
817
- var arrayLen int
818
- var elemType ast.Expr
819
- var goElemType interface{}
820
- if typ := c.pkg.TypesInfo.TypeOf(exp.Type); typ != nil {
821
- if at, ok := typ.Underlying().(*gtypes.Array); ok {
822
- arrayLen = int(at.Len())
823
- goElemType = at.Elem()
824
- }
825
- }
826
- if arrType.Len != nil {
827
- // Try to evaluate the length from the AST if not available from type info
828
- if bl, ok := arrType.Len.(*ast.BasicLit); ok && bl.Kind == token.INT {
829
- if _, err := fmt.Sscan(bl.Value, &arrayLen); err != nil {
830
- return fmt.Errorf("failed to parse array length from basic literal: %w", err)
831
- }
832
- }
833
- }
834
- elemType = arrType.Elt
835
-
836
- // Map of index -> value
837
- elements := make(map[int]ast.Expr)
838
- orderedCount := 0
839
- maxIndex := -1
840
- hasKeyedElements := false
841
-
842
- for _, elm := range exp.Elts {
843
- if kv, ok := elm.(*ast.KeyValueExpr); ok {
844
- if lit, ok := kv.Key.(*ast.BasicLit); ok && lit.Kind == token.INT {
845
- var index int
846
- if _, err := fmt.Sscan(lit.Value, &index); err != nil {
847
- return fmt.Errorf("failed to parse array index from basic literal: %w", err)
848
- }
849
- elements[index] = kv.Value
850
- if index > maxIndex {
851
- maxIndex = index
852
- }
853
- hasKeyedElements = true
854
- } else {
855
- c.tsw.WriteCommentInline("unhandled keyed array literal key type")
856
- if err := c.WriteValueExpr(elm); err != nil {
857
- return fmt.Errorf("failed to write keyed array literal element with unhandled key type: %w", err)
858
- }
859
- }
860
- } else {
861
- elements[orderedCount] = elm
862
- if orderedCount > maxIndex {
863
- maxIndex = orderedCount
864
- }
865
- orderedCount++
866
- }
867
- }
868
-
869
- // Determine array length
870
- if arrayLen == 0 {
871
- // If length is not set, infer from max index or number of elements
872
- if hasKeyedElements {
873
- arrayLen = maxIndex + 1
874
- } else {
875
- arrayLen = len(exp.Elts)
876
- }
877
- }
878
-
879
- for i := 0; i < arrayLen; i++ {
880
- if i > 0 {
881
- c.tsw.WriteLiterally(", ")
882
- }
883
- if elm, ok := elements[i]; ok && elm != nil {
884
- if err := c.WriteValueExpr(elm); err != nil {
885
- return fmt.Errorf("failed to write array literal element: %w", err)
886
- }
887
- } else {
888
- // Write zero value for element type
889
- if goElemType != nil {
890
- c.WriteZeroValueForType(goElemType)
891
- } else {
892
- c.WriteZeroValueForType(elemType)
893
- }
894
- }
895
- }
896
- c.tsw.WriteLiterally("]")
897
- return nil
898
- } else {
899
- // Typed literal, likely a struct: new Type({...})
900
- c.tsw.WriteLiterally("new ")
901
- c.WriteTypeExpr(exp.Type)
902
- c.tsw.WriteLiterally("({")
903
- for i, elm := range exp.Elts {
904
- if i != 0 {
905
- c.tsw.WriteLiterally(", ")
906
- }
907
- if err := c.WriteValueExpr(elm); err != nil {
908
- return fmt.Errorf("failed to write struct literal field: %w", err)
909
- }
910
- }
911
- c.tsw.WriteLiterally("})")
912
- return nil
913
- }
914
- }
915
-
916
- // Untyped composite literal. Could be array, slice, map.
917
- // Requires type information for accurate translation.
918
- // Defaulting to an object literal {} as a slightly safer guess than array []
919
- // if it contains KeyValueExpr, otherwise default to array.
920
- isLikelyObject := false
921
- if len(exp.Elts) > 0 {
922
- if _, ok := exp.Elts[0].(*ast.KeyValueExpr); ok {
923
- isLikelyObject = true
924
- }
925
- }
926
-
927
- if isLikelyObject {
928
- c.tsw.WriteLiterally("{ ")
929
- } else {
930
- c.tsw.WriteLiterally("[ ")
931
- }
932
-
933
- for i, elm := range exp.Elts {
934
- if i != 0 {
935
- c.tsw.WriteLiterally(", ")
936
- }
937
- if err := c.WriteValueExpr(elm); err != nil {
938
- return fmt.Errorf("failed to write untyped composite literal element: %w", err)
939
- }
940
- }
941
- if isLikelyObject {
942
- c.tsw.WriteLiterally(" }")
943
- } else {
944
- c.tsw.WriteLiterally(" ]")
945
- }
946
- // c.tsw.WriteCommentInline("untyped composite literal, type guessed")
947
- return nil
948
- }
949
-
950
- // WriteKeyValueExprValue writes a key-value pair.
951
- // Returns an error if writing the key or value fails.
952
- func (c *GoToTSCompiler) WriteKeyValueExprValue(exp *ast.KeyValueExpr) error {
953
- // Keep original Go casing for keys
954
- if err := c.WriteValueExpr(exp.Key); err != nil {
955
- return fmt.Errorf("failed to write key-value expression key: %w", err)
956
- }
957
- c.tsw.WriteLiterally(": ")
958
- if err := c.WriteValueExpr(exp.Value); err != nil {
959
- return fmt.Errorf("failed to write key-value expression value: %w", err)
960
- }
961
- return nil
962
- }
963
-
964
- // WriteFuncLitValue writes a function literal as a TypeScript arrow function.
965
- func (c *GoToTSCompiler) WriteFuncLitValue(exp *ast.FuncLit) error {
966
- // Determine if the function literal should be async
967
- isAsync := c.containsAsyncOperations(exp.Body)
968
-
969
- if isAsync {
970
- c.tsw.WriteLiterally("async ")
971
- }
972
-
973
- // Write arrow function: (params) => { body }
974
- c.tsw.WriteLiterally("(")
975
- c.WriteFieldList(exp.Type.Params, true) // true = arguments
976
- c.tsw.WriteLiterally(")")
977
-
978
- // Handle return type for function literals
979
- if exp.Type.Results != nil && len(exp.Type.Results.List) > 0 {
980
- c.tsw.WriteLiterally(": ")
981
- if isAsync {
982
- c.tsw.WriteLiterally("Promise<")
983
- }
984
- if len(exp.Type.Results.List) == 1 && len(exp.Type.Results.List[0].Names) == 0 {
985
- c.WriteTypeExpr(exp.Type.Results.List[0].Type)
986
- } else {
987
- c.tsw.WriteLiterally("[")
988
- for i, field := range exp.Type.Results.List {
989
- if i > 0 {
990
- c.tsw.WriteLiterally(", ")
991
- }
992
- c.WriteTypeExpr(field.Type)
993
- }
994
- c.tsw.WriteLiterally("]")
995
- }
996
- if isAsync {
997
- c.tsw.WriteLiterally(">")
998
- }
999
- } else {
1000
- if isAsync {
1001
- c.tsw.WriteLiterally(": Promise<void>")
1002
- } else {
1003
- c.tsw.WriteLiterally(": void")
1004
- }
1005
- }
1006
-
1007
- c.tsw.WriteLiterally(" => ")
1008
-
1009
- // Save previous async state and set current state based on isAsync
1010
- previousAsyncState := c.inAsyncFunction
1011
- c.inAsyncFunction = isAsync
1012
-
1013
- // Write function body
1014
- if err := c.WriteStmt(exp.Body); err != nil {
1015
- c.inAsyncFunction = previousAsyncState // Restore state before returning error
1016
- return fmt.Errorf("failed to write function literal body: %w", err)
1017
- }
1018
-
1019
- // Restore previous async state
1020
- c.inAsyncFunction = previousAsyncState
1021
- return nil
1022
- }