goscript 0.0.21 → 0.0.23

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.
@@ -0,0 +1,309 @@
1
+ package compiler
2
+
3
+ import (
4
+ "go/ast"
5
+ "go/types"
6
+ )
7
+
8
+ // WriteTypeExpr translates a Go abstract syntax tree (AST) expression (`ast.Expr`)
9
+ // that represents a type into its TypeScript type equivalent using type information.
10
+ //
11
+ // It handles various Go type expressions:
12
+ // - Basic types (e.g., int, string, bool) -> TypeScript primitives (number, string, boolean)
13
+ // - Named types -> TypeScript class/interface names
14
+ // - Pointer types (`*T`) -> `$.Box<T_ts> | null`
15
+ // - Slice types (`[]T`) -> `$.Slice<T_ts>`
16
+ // - Array types (`[N]T`) -> `T_ts[]`
17
+ // - Map types (`map[K]V`) -> `Map<K_ts, V_ts>`
18
+ // - Channel types (`chan T`) -> `$.Channel<T_ts>`
19
+ // - Struct types -> TypeScript object types or class names
20
+ // - Interface types -> TypeScript interface types or "any"
21
+ // - Function types -> TypeScript function signatures
22
+ func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
23
+ // Get type information for the expression and use WriteGoType
24
+ typ := c.pkg.TypesInfo.TypeOf(a)
25
+ c.WriteGoType(typ, GoTypeContextGeneral)
26
+ }
27
+
28
+ // writeTypeDescription writes the TypeInfo for a type expr.
29
+ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
30
+ switch t := typeExpr.(type) {
31
+ case *ast.Ident:
32
+ // Resolve the identifier to its type
33
+ goType := c.pkg.TypesInfo.TypeOf(t)
34
+ if goType != nil {
35
+ if namedType, isNamed := goType.(*types.Named); isNamed {
36
+ if sig, isFuncSig := namedType.Underlying().(*types.Signature); isFuncSig {
37
+ // It's a named function type (e.g. type MyFunc func())
38
+ c.tsw.WriteLiterally("{")
39
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function, ")
40
+ c.tsw.WriteLiterallyf("name: '%s'", namedType.Obj().Name()) // Use the original defined name
41
+
42
+ // Add params if present
43
+ if sig.Params() != nil && sig.Params().Len() > 0 {
44
+ c.tsw.WriteLiterally(", params: [")
45
+ for i := 0; i < sig.Params().Len(); i++ {
46
+ if i > 0 {
47
+ c.tsw.WriteLiterally(", ")
48
+ }
49
+ paramVar := sig.Params().At(i)
50
+ c.writeTypeInfoObject(paramVar.Type())
51
+ }
52
+ c.tsw.WriteLiterally("]")
53
+ } else {
54
+ c.tsw.WriteLiterally(", params: []")
55
+ }
56
+
57
+ // Add results if present
58
+ if sig.Results() != nil && sig.Results().Len() > 0 {
59
+ c.tsw.WriteLiterally(", results: [")
60
+ for i := 0; i < sig.Results().Len(); i++ {
61
+ if i > 0 {
62
+ c.tsw.WriteLiterally(", ")
63
+ }
64
+ resultVar := sig.Results().At(i)
65
+ c.writeTypeInfoObject(resultVar.Type())
66
+ }
67
+ c.tsw.WriteLiterally("]")
68
+ } else {
69
+ c.tsw.WriteLiterally(", results: []")
70
+ }
71
+
72
+ c.tsw.WriteLiterally("}")
73
+ return
74
+ }
75
+ }
76
+ }
77
+
78
+ if isPrimitiveType(t.Name) {
79
+ if tsType, ok := GoBuiltinToTypescript(t.Name); ok {
80
+ c.tsw.WriteLiterally("{")
81
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
82
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
83
+ c.tsw.WriteLiterally("}")
84
+ } else {
85
+ // Fallback for other primitive types
86
+ c.tsw.WriteLiterally("{")
87
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
88
+ c.tsw.WriteLiterallyf("name: '%s'", t.Name)
89
+ c.tsw.WriteLiterally("}")
90
+ }
91
+ } else {
92
+ // For named types, just use the name string
93
+ c.tsw.WriteLiterallyf("'%s'", t.Name)
94
+ }
95
+ case *ast.SelectorExpr:
96
+ if ident, ok := t.X.(*ast.Ident); ok {
97
+ c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
98
+ }
99
+ case *ast.ArrayType:
100
+ typeKind := "$.TypeKind.Slice"
101
+ if t.Len != nil {
102
+ typeKind = "$.TypeKind.Array"
103
+ }
104
+
105
+ c.tsw.WriteLiterally("{")
106
+ c.tsw.WriteLiterallyf("kind: %s, ", typeKind)
107
+ c.tsw.WriteLiterally("elemType: ")
108
+ c.writeTypeDescription(t.Elt)
109
+ c.tsw.WriteLiterally("}")
110
+ case *ast.StructType:
111
+ c.tsw.WriteLiterally("{")
112
+ c.tsw.WriteLiterally("kind: $.TypeKind.Struct, ")
113
+
114
+ // Add field names and types to the struct type info
115
+ if t.Fields != nil && t.Fields.List != nil {
116
+ c.tsw.WriteLiterally("fields: {")
117
+
118
+ hasFields := false
119
+ for _, field := range t.Fields.List {
120
+ if len(field.Names) > 0 {
121
+ for _, name := range field.Names {
122
+ if hasFields {
123
+ c.tsw.WriteLiterally(", ")
124
+ }
125
+ c.tsw.WriteLiterallyf("'%s': ", name.Name)
126
+ c.writeTypeDescription(field.Type)
127
+ hasFields = true
128
+ }
129
+ }
130
+ }
131
+
132
+ c.tsw.WriteLiterally("}, ")
133
+ } else {
134
+ c.tsw.WriteLiterally("fields: {}, ")
135
+ }
136
+
137
+ c.tsw.WriteLiterally("methods: []")
138
+
139
+ c.tsw.WriteLiterally("}")
140
+ case *ast.MapType:
141
+ c.tsw.WriteLiterally("{")
142
+ c.tsw.WriteLiterally("kind: $.TypeKind.Map, ")
143
+ c.tsw.WriteLiterally("keyType: ")
144
+ c.writeTypeDescription(t.Key)
145
+ c.tsw.WriteLiterally(", ")
146
+ c.tsw.WriteLiterally("elemType: ")
147
+ c.writeTypeDescription(t.Value)
148
+ c.tsw.WriteLiterally("}")
149
+ case *ast.StarExpr:
150
+ c.tsw.WriteLiterally("{")
151
+ c.tsw.WriteLiterally("kind: $.TypeKind.Pointer, ")
152
+ c.tsw.WriteLiterally("elemType: ")
153
+ c.writeTypeDescription(t.X)
154
+ c.tsw.WriteLiterally("}")
155
+ case *ast.FuncType:
156
+ // For function types, create a type descriptor object with params and results
157
+ c.tsw.WriteLiterally("{")
158
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function")
159
+
160
+ // Add name if this is a named function type
161
+ // For an anonymous ast.FuncType, typeExpr is the ast.FuncType itself.
162
+ // We need to check if the type information associated with this AST node
163
+ // points to a *types.Named type.
164
+ resolvedGoType := c.pkg.TypesInfo.TypeOf(typeExpr)
165
+ if resolvedGoType != nil {
166
+ if named, ok := resolvedGoType.(*types.Named); ok {
167
+ // Ensure it's actually a function type that's named
168
+ if _, isFuncSig := named.Underlying().(*types.Signature); isFuncSig {
169
+ c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
170
+ }
171
+ }
172
+ }
173
+
174
+ // Add params if present
175
+ if t.Params != nil && len(t.Params.List) > 0 {
176
+ c.tsw.WriteLiterally(", params: [")
177
+ for i, param := range t.Params.List {
178
+ if i > 0 {
179
+ c.tsw.WriteLiterally(", ")
180
+ }
181
+ c.writeTypeDescription(param.Type)
182
+ }
183
+ c.tsw.WriteLiterally("]")
184
+ }
185
+
186
+ // Add results if present
187
+ if t.Results != nil && len(t.Results.List) > 0 {
188
+ c.tsw.WriteLiterally(", results: [")
189
+ for i, result := range t.Results.List {
190
+ if i > 0 {
191
+ c.tsw.WriteLiterally(", ")
192
+ }
193
+ c.writeTypeDescription(result.Type)
194
+ }
195
+ c.tsw.WriteLiterally("]")
196
+ }
197
+
198
+ c.tsw.WriteLiterally("}")
199
+ return
200
+ case *ast.ChanType:
201
+ c.tsw.WriteLiterally("{")
202
+ c.tsw.WriteLiterally("kind: $.TypeKind.Channel, ")
203
+ c.tsw.WriteLiterally("elemType: ")
204
+
205
+ // Add element type
206
+ if ident, ok := t.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
207
+ if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
208
+ c.tsw.WriteLiterallyf("'%s'", tsType)
209
+ } else {
210
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
211
+ }
212
+ } else {
213
+ c.writeTypeDescription(t.Value)
214
+ }
215
+
216
+ // Add direction
217
+ c.tsw.WriteLiterally(", direction: ")
218
+ switch t.Dir {
219
+ case ast.SEND:
220
+ c.tsw.WriteLiterally("'send'")
221
+ case ast.RECV:
222
+ c.tsw.WriteLiterally("'receive'")
223
+ case ast.SEND | ast.RECV: // bidirectional
224
+ c.tsw.WriteLiterally("'both'")
225
+ default:
226
+ // This should not happen, but just in case
227
+ c.tsw.WriteLiterally("'both'")
228
+ }
229
+
230
+ c.tsw.WriteLiterally("}")
231
+ case *ast.InterfaceType:
232
+ // Handle inline interface types like interface{ Method() string }
233
+ c.tsw.WriteLiterally("{")
234
+ c.tsw.WriteLiterally("kind: $.TypeKind.Interface, ")
235
+ c.tsw.WriteLiterally("methods: [")
236
+
237
+ // Add method signatures for each method in the interface
238
+ if t.Methods != nil && t.Methods.List != nil {
239
+ hasMethod := false
240
+ for _, field := range t.Methods.List {
241
+ // Only process method declarations (not embedded interfaces)
242
+ if len(field.Names) > 0 {
243
+ for _, methodName := range field.Names {
244
+ if hasMethod {
245
+ c.tsw.WriteLiterally(", ")
246
+ }
247
+ hasMethod = true
248
+
249
+ // Write method signature in the same format as writeMethodSignatures
250
+ c.tsw.WriteLiterallyf("{ name: '%s', args: [", methodName.Name)
251
+
252
+ // Get the function type for this method
253
+ if funcType, ok := field.Type.(*ast.FuncType); ok {
254
+ // Add parameters
255
+ if funcType.Params != nil && funcType.Params.List != nil {
256
+ paramIndex := 0
257
+ for _, param := range funcType.Params.List {
258
+ // Each parameter field can declare multiple variables of the same type
259
+ if len(param.Names) > 0 {
260
+ for _, paramName := range param.Names {
261
+ if paramIndex > 0 {
262
+ c.tsw.WriteLiterally(", ")
263
+ }
264
+ c.tsw.WriteLiterallyf("{ name: '%s', type: ", paramName.Name)
265
+ c.writeTypeDescription(param.Type)
266
+ c.tsw.WriteLiterally(" }")
267
+ paramIndex++
268
+ }
269
+ } else {
270
+ // No names, create a generic parameter name
271
+ if paramIndex > 0 {
272
+ c.tsw.WriteLiterally(", ")
273
+ }
274
+ c.tsw.WriteLiterallyf("{ name: '_p%d', type: ", paramIndex)
275
+ c.writeTypeDescription(param.Type)
276
+ c.tsw.WriteLiterally(" }")
277
+ paramIndex++
278
+ }
279
+ }
280
+ }
281
+
282
+ c.tsw.WriteLiterally("], returns: [")
283
+
284
+ // Add return types
285
+ if funcType.Results != nil && funcType.Results.List != nil {
286
+ for i, result := range funcType.Results.List {
287
+ if i > 0 {
288
+ c.tsw.WriteLiterally(", ")
289
+ }
290
+ c.tsw.WriteLiterally("{ type: ")
291
+ c.writeTypeDescription(result.Type)
292
+ c.tsw.WriteLiterally(" }")
293
+ }
294
+ }
295
+
296
+ c.tsw.WriteLiterally("] }")
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }
302
+
303
+ c.tsw.WriteLiterally("]")
304
+ c.tsw.WriteLiterally("}")
305
+ default:
306
+ // For other types, use the string representation
307
+ c.tsw.WriteLiterallyf("'%s'", c.getTypeNameString(typeExpr))
308
+ }
309
+ }
@@ -0,0 +1,89 @@
1
+ package compiler
2
+
3
+ import (
4
+ "go/ast"
5
+ )
6
+
7
+ // WriteValueExpr translates a Go abstract syntax tree (AST) expression (`ast.Expr`)
8
+ // that represents a value into its TypeScript value equivalent.
9
+ // This is a central dispatch function for various expression types:
10
+ // - Identifiers (`ast.Ident`): Delegates to `WriteIdent`, potentially adding `.value` for boxed variables.
11
+ // - Selector expressions (`ast.SelectorExpr`, e.g., `obj.Field` or `pkg.Var`): Delegates to `WriteSelectorExpr`.
12
+ // - Pointer dereferences (`ast.StarExpr`, e.g., `*ptr`): Delegates to `WriteStarExpr`.
13
+ // - Function calls (`ast.CallExpr`): Delegates to `WriteCallExpr`.
14
+ // - Unary operations (`ast.UnaryExpr`, e.g., `!cond`, `&val`): Delegates to `WriteUnaryExpr`.
15
+ // - Binary operations (`ast.BinaryExpr`, e.g., `a + b`): Delegates to `WriteBinaryExpr`.
16
+ // - Basic literals (`ast.BasicLit`, e.g., `123`, `"hello"`): Delegates to `WriteBasicLit`.
17
+ // - Composite literals (`ast.CompositeLit`, e.g., `MyStruct{}`): Delegates to `WriteCompositeLit`.
18
+ // - Key-value expressions (`ast.KeyValueExpr`): Delegates to `WriteKeyValueExpr`.
19
+ // - Type assertions in expression context (`ast.TypeAssertExpr`, e.g., `val.(Type)`): Delegates to `WriteTypeAssertExpr`.
20
+ // - Index expressions (`ast.IndexExpr`):
21
+ // - For maps: `myMap[key]` becomes `myMap.get(key) ?? zeroValue`.
22
+ // - For arrays/slices: `myArray[idx]` becomes `myArray![idx]`.
23
+ //
24
+ // - Slice expressions (`ast.SliceExpr`, e.g., `s[low:high:max]`): Translates to `$.slice(s, low, high, max)`.
25
+ // - Parenthesized expressions (`ast.ParenExpr`): Translates `(X)` to `(X)`.
26
+ // - Function literals (`ast.FuncLit`): Delegates to `WriteFuncLitValue`.
27
+ // Unhandled value expressions result in a comment.
28
+ func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
29
+ switch exp := a.(type) {
30
+ case *ast.Ident:
31
+ c.WriteIdent(exp, true) // adds .value accessor
32
+ return nil
33
+ case *ast.SelectorExpr:
34
+ return c.WriteSelectorExpr(exp)
35
+ case *ast.StarExpr:
36
+ return c.WriteStarExpr(exp)
37
+ case *ast.CallExpr:
38
+ return c.WriteCallExpr(exp)
39
+ case *ast.UnaryExpr:
40
+ return c.WriteUnaryExpr(exp)
41
+ case *ast.BinaryExpr:
42
+ return c.WriteBinaryExpr(exp)
43
+ case *ast.BasicLit:
44
+ c.WriteBasicLit(exp)
45
+ return nil
46
+ case *ast.CompositeLit:
47
+ return c.WriteCompositeLit(exp)
48
+ case *ast.KeyValueExpr:
49
+ return c.WriteKeyValueExpr(exp)
50
+ case *ast.TypeAssertExpr:
51
+ // Handle type assertion in an expression context
52
+ return c.WriteTypeAssertExpr(exp)
53
+ case *ast.IndexExpr:
54
+ return c.WriteIndexExpr(exp)
55
+ case *ast.IndexListExpr:
56
+ // Handle generic function instantiation: f[T1, T2](args) -> f<T1, T2>(args)
57
+ return c.WriteIndexListExpr(exp)
58
+ case *ast.SliceExpr:
59
+ return c.WriteSliceExpr(exp)
60
+ case *ast.ParenExpr:
61
+ // Check if this is a nil pointer to struct type cast: (*struct{})(nil)
62
+ if starExpr, isStarExpr := exp.X.(*ast.StarExpr); isStarExpr {
63
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
64
+ c.tsw.WriteLiterally("null")
65
+ return nil
66
+ }
67
+ }
68
+
69
+ // Check if this is a type cast with nil: (SomeType)(nil)
70
+ if ident, isIdent := exp.X.(*ast.Ident); isIdent && ident.Name == "nil" {
71
+ c.tsw.WriteLiterally("null")
72
+ return nil
73
+ }
74
+
75
+ // Translate (X) to (X)
76
+ // If we haven't written anything in this statement yet, prepend ;
77
+ c.tsw.WriteLiterally("(")
78
+ if err := c.WriteValueExpr(exp.X); err != nil {
79
+ return err
80
+ }
81
+ c.tsw.WriteLiterally(")")
82
+ return nil
83
+ case *ast.FuncLit:
84
+ return c.WriteFuncLitValue(exp)
85
+ default:
86
+ c.tsw.WriteCommentLinef("unhandled value expr: %T", exp)
87
+ return nil
88
+ }
89
+ }