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.
- package/README.md +154 -40
- package/builtin/builtin.ts +1168 -178
- package/compiler/analysis.go +726 -0
- package/compiler/compiler.go +5706 -4
- package/compiler/compiler_test.go +104 -0
- package/compiler/config.go +3 -3
- package/compiler/config_test.go +89 -0
- package/compiler/output.go +26 -0
- package/compiler/write-type-spec.go +506 -0
- package/compiler/writer.go +25 -0
- package/dist/builtin/builtin.d.ts +204 -67
- package/dist/builtin/builtin.js +845 -144
- package/dist/builtin/builtin.js.map +1 -1
- package/go.mod +4 -7
- package/go.sum +6 -11
- package/package.json +4 -3
- package/compiler/compile.go +0 -190
- package/compiler/compile_comment.go +0 -41
- package/compiler/compile_decls.go +0 -84
- package/compiler/compile_expr.go +0 -1022
- package/compiler/compile_field.go +0 -110
- package/compiler/compile_spec.go +0 -566
- package/compiler/compile_stmt.go +0 -1616
- package/compiler/context.go +0 -9
- package/compiler/file_compiler.go +0 -80
- package/compiler/output_path.go +0 -31
- package/compiler/pkg_compiler.go +0 -72
- package/compiler/types/tokens.go +0 -66
- package/compiler/types/types.go +0 -46
- package/dist/compliance/tests/array_literal/array_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/array_literal/array_literal.gs.js +0 -15
- package/dist/compliance/tests/array_literal/array_literal.gs.js.map +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.js +0 -24
- package/dist/compliance/tests/async_basic/async_basic.gs.js.map +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js +0 -82
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.d.ts +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js +0 -16
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js.map +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.d.ts +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js +0 -14
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js.map +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js +0 -14
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js.map +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/constants/constants.gs.d.ts +0 -1
- package/dist/compliance/tests/constants/constants.gs.js +0 -16
- package/dist/compliance/tests/constants/constants.gs.js.map +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.d.ts +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js +0 -33
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js.map +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js +0 -75
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js +0 -37
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.d.ts +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js +0 -29
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js.map +0 -1
- package/dist/compliance/tests/float64/float64.gs.d.ts +0 -1
- package/dist/compliance/tests/float64/float64.gs.js +0 -24
- package/dist/compliance/tests/float64/float64.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js +0 -10
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js +0 -11
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js +0 -10
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js +0 -14
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js.map +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.js +0 -39
- package/dist/compliance/tests/for_range/for_range.gs.js.map +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js +0 -15
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js.map +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.js +0 -10
- package/dist/compliance/tests/func_literal/func_literal.gs.js.map +0 -1
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.d.ts +0 -12
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js +0 -30
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.js +0 -13
- package/dist/compliance/tests/if_statement/if_statement.gs.js.map +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js +0 -12
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js.map +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js +0 -34
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js.map +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js +0 -32
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js +0 -40
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js +0 -51
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js.map +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.d.ts +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.js +0 -88
- package/dist/compliance/tests/map_support/map_support.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js +0 -24
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js +0 -22
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js.map +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.d.ts +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js +0 -17
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js +0 -29
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js +0 -22
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js +0 -20
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js.map +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.d.ts +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js +0 -28
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js.map +0 -1
- 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
- package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js +0 -30
- 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
- package/dist/compliance/tests/select_statement/select_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/select_statement/select_statement.gs.js +0 -207
- package/dist/compliance/tests/select_statement/select_statement.gs.js.map +0 -1
- package/dist/compliance/tests/simple/simple.gs.d.ts +0 -1
- package/dist/compliance/tests/simple/simple.gs.js +0 -6
- package/dist/compliance/tests/simple/simple.gs.js.map +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js +0 -24
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/slices/slices.gs.d.ts +0 -1
- package/dist/compliance/tests/slices/slices.gs.js +0 -294
- package/dist/compliance/tests/slices/slices.gs.js.map +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js +0 -41
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js +0 -17
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js +0 -48
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js.map +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js +0 -19
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js.map +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js +0 -26
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js.map +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js +0 -30
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js.map +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js +0 -76
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js.map +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.d.ts +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js +0 -31
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js.map +0 -1
package/compiler/compile_expr.go
DELETED
|
@@ -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
|
-
}
|