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.
- package/cmd/goscript/cmd_compile.go +2 -2
- package/compiler/analysis.go +229 -51
- package/compiler/assignment.go +412 -0
- package/compiler/compiler.go +185 -5885
- package/compiler/compiler_test.go +40 -8
- package/compiler/composite-lit.go +552 -0
- package/compiler/config.go +3 -0
- package/compiler/decl.go +259 -0
- package/compiler/expr-call.go +479 -0
- package/compiler/expr-selector.go +125 -0
- package/compiler/expr-star.go +90 -0
- package/compiler/expr-type.go +309 -0
- package/compiler/expr-value.go +89 -0
- package/compiler/expr.go +591 -0
- package/compiler/field.go +169 -0
- package/compiler/lit.go +131 -0
- package/compiler/primitive.go +148 -0
- package/compiler/{write-type-spec.go → spec-struct.go} +211 -204
- package/compiler/spec-value.go +226 -0
- package/compiler/spec.go +272 -0
- package/compiler/stmt-assign.go +439 -0
- package/compiler/stmt-for.go +178 -0
- package/compiler/stmt-range.go +235 -0
- package/compiler/stmt-select.go +211 -0
- package/compiler/stmt-type-switch.go +147 -0
- package/compiler/stmt.go +792 -0
- package/compiler/type-assert.go +209 -0
- package/compiler/type-info.go +141 -0
- package/compiler/type.go +618 -0
- package/go.mod +2 -1
- package/go.sum +4 -2
- package/package.json +6 -6
- package/builtin/builtin.go +0 -11
- package/builtin/builtin.ts +0 -2114
- package/dist/builtin/builtin.d.ts +0 -495
- package/dist/builtin/builtin.js +0 -1490
- package/dist/builtin/builtin.js.map +0 -1
- /package/compiler/{writer.go → code-writer.go} +0 -0
|
@@ -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
|
+
}
|