goscript 0.0.22 → 0.0.24
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 +1 -1
- package/cmd/goscript/cmd_compile.go +3 -3
- package/compiler/analysis.go +302 -182
- package/compiler/analysis_test.go +220 -0
- package/compiler/assignment.go +42 -43
- package/compiler/builtin_test.go +102 -0
- package/compiler/compiler.go +117 -29
- package/compiler/compiler_test.go +36 -8
- package/compiler/composite-lit.go +133 -53
- package/compiler/config.go +7 -3
- package/compiler/config_test.go +6 -33
- package/compiler/decl.go +36 -0
- package/compiler/expr-call.go +116 -60
- package/compiler/expr-selector.go +88 -43
- package/compiler/expr-star.go +57 -65
- package/compiler/expr-type.go +132 -5
- package/compiler/expr-value.go +8 -38
- package/compiler/expr.go +326 -30
- package/compiler/field.go +3 -3
- package/compiler/lit.go +34 -2
- package/compiler/primitive.go +19 -12
- package/compiler/spec-struct.go +140 -9
- package/compiler/spec-value.go +119 -41
- package/compiler/spec.go +21 -6
- package/compiler/stmt-assign.go +65 -3
- package/compiler/stmt-for.go +11 -0
- package/compiler/stmt-range.go +119 -11
- package/compiler/stmt-select.go +211 -0
- package/compiler/stmt-type-switch.go +147 -0
- package/compiler/stmt.go +175 -238
- package/compiler/type-assert.go +125 -379
- package/compiler/type.go +216 -129
- package/dist/gs/builtin/builtin.js +37 -0
- package/dist/gs/builtin/builtin.js.map +1 -0
- package/dist/gs/builtin/channel.js +471 -0
- package/dist/gs/builtin/channel.js.map +1 -0
- package/dist/gs/builtin/defer.js +54 -0
- package/dist/gs/builtin/defer.js.map +1 -0
- package/dist/gs/builtin/io.js +15 -0
- package/dist/gs/builtin/io.js.map +1 -0
- package/dist/gs/builtin/map.js +44 -0
- package/dist/gs/builtin/map.js.map +1 -0
- package/dist/gs/builtin/slice.js +799 -0
- package/dist/gs/builtin/slice.js.map +1 -0
- package/dist/gs/builtin/type.js +745 -0
- package/dist/gs/builtin/type.js.map +1 -0
- package/dist/gs/builtin/varRef.js +14 -0
- package/dist/gs/builtin/varRef.js.map +1 -0
- package/dist/gs/context/context.js +55 -0
- package/dist/gs/context/context.js.map +1 -0
- package/dist/gs/context/index.js +2 -0
- package/dist/gs/context/index.js.map +1 -0
- package/dist/gs/runtime/index.js +2 -0
- package/dist/gs/runtime/index.js.map +1 -0
- package/dist/gs/runtime/runtime.js +158 -0
- package/dist/gs/runtime/runtime.js.map +1 -0
- package/dist/gs/time/index.js +2 -0
- package/dist/gs/time/index.js.map +1 -0
- package/dist/gs/time/time.js +115 -0
- package/dist/gs/time/time.js.map +1 -0
- package/package.json +7 -6
- package/builtin/builtin.go +0 -11
- package/builtin/builtin.ts +0 -2379
- package/dist/builtin/builtin.d.ts +0 -513
- package/dist/builtin/builtin.js +0 -1686
- package/dist/builtin/builtin.js.map +0 -1
package/compiler/expr-star.go
CHANGED
|
@@ -1,89 +1,81 @@
|
|
|
1
1
|
package compiler
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
"fmt"
|
|
5
4
|
"go/ast"
|
|
5
|
+
"go/types"
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
// WriteStarExpr translates a Go pointer dereference expression (`ast.StarExpr`, e.g., `*p`)
|
|
9
9
|
// into its TypeScript equivalent. This involves careful handling of Go's pointers
|
|
10
|
-
// and TypeScript's
|
|
10
|
+
// and TypeScript's varRefing mechanism for emulating pointer semantics.
|
|
11
11
|
//
|
|
12
|
-
// The translation depends on whether the pointer variable `p` itself is
|
|
12
|
+
// The translation depends on whether the pointer variable `p` itself is varrefed and
|
|
13
13
|
// what type of value it points to:
|
|
14
|
-
// 1. If `p` is not
|
|
15
|
-
// (`p` holds a
|
|
16
|
-
// 2. If `p` is not
|
|
14
|
+
// 1. If `p` is not varrefed and points to a primitive or another pointer: `*p` -> `p!.value`.
|
|
15
|
+
// (`p` holds a varRef, so dereference accesses its `value` field).
|
|
16
|
+
// 2. If `p` is not varrefed and points to a struct: `*p` -> `p!`.
|
|
17
17
|
// (`p` holds the struct instance directly; structs are reference types in TS).
|
|
18
|
-
// 3. If `p` is
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// (First `.value` unboxes `p` to get the struct instance).
|
|
18
|
+
// 3. If `p` is variable referenced (i.e., `p` is `$.VarRef<PointerType>`) and points to a primitive/pointer:
|
|
19
|
+
// `p.value!.value` (access the variable reference, then dereference the pointer)
|
|
20
|
+
// 4. If `p` is varrefed and points to a struct: `p.value!`.
|
|
21
|
+
// (First `.value` unvarRefes `p` to get the struct instance).
|
|
23
22
|
//
|
|
24
|
-
// `WriteValueExpr(operand)` handles the initial
|
|
23
|
+
// `WriteValueExpr(operand)` handles the initial unvarRefing of `p` if `p` itself is a varrefed variable.
|
|
25
24
|
// A non-null assertion `!` is always added as pointers can be nil.
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
25
|
+
// The function determines if `.value` access is needed by checking what the Go pointer operand points to.
|
|
26
|
+
//
|
|
27
|
+
// For multi-level dereferences like `***p`, this function is called recursively, with each level
|
|
28
|
+
// adding the appropriate `!.value` suffix.
|
|
29
|
+
//
|
|
30
|
+
// Examples:
|
|
31
|
+
// - Simple pointer to primitive: `p!.value` (where p is *int)
|
|
32
|
+
// - Variable referenced pointer to primitive: `p.value!.value` (where p is VarRef<*int>)
|
|
33
|
+
// Example: let p = $.varRef(x) (where x is another variable reference) => p.value!.value
|
|
34
|
+
// - Pointer to struct: `p!` (where p is *MyStruct)
|
|
35
|
+
// Example: let p = $.varRef(new MyStruct()) => p.value!
|
|
36
|
+
// - Variable referenced pointer to struct: `p.value!` (where p is VarRef<*MyStruct>)
|
|
37
|
+
// - Triple pointer: `p3!.value!.value!.value` (where p3 is VarRef<VarRef<VarRef<number> | null> | null> | null)
|
|
29
38
|
func (c *GoToTSCompiler) WriteStarExpr(exp *ast.StarExpr) error {
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Example: let p = x (where x is a box) => p!.value
|
|
36
|
-
//
|
|
37
|
-
// 2. p! - when p is not boxed and points to a struct
|
|
38
|
-
// Example: let p = new MyStruct() => p! (structs are reference types)
|
|
39
|
-
//
|
|
40
|
-
// 3. p.value!.value - when p is boxed and points to a primitive/pointer
|
|
41
|
-
// Example: let p = $.box(x) (where x is another box) => p.value!.value
|
|
42
|
-
//
|
|
43
|
-
// 4. p.value! - when p is boxed and points to a struct
|
|
44
|
-
// Example: let p = $.box(new MyStruct()) => p.value!
|
|
45
|
-
//
|
|
46
|
-
// Critical bug fix: We must handle each case correctly to avoid over-dereferencing
|
|
47
|
-
// (adding too many .value) or under-dereferencing (missing .value where needed)
|
|
48
|
-
//
|
|
49
|
-
// NOTE: This logic aligns with design/BOXES_POINTERS.md.
|
|
50
|
-
|
|
51
|
-
// Get the operand expression and its type information
|
|
52
|
-
operand := exp.X
|
|
53
|
-
|
|
54
|
-
// Get the type of the operand (the pointer being dereferenced)
|
|
55
|
-
ptrType := c.pkg.TypesInfo.TypeOf(operand)
|
|
56
|
-
|
|
57
|
-
// Special case for handling multi-level dereferencing:
|
|
58
|
-
// Check if the operand is itself a StarExpr (e.g., **p or ***p)
|
|
59
|
-
// We need to handle these specially to correctly generate nested .value accesses
|
|
60
|
-
if starExpr, isStarExpr := operand.(*ast.StarExpr); isStarExpr {
|
|
61
|
-
// First, write the inner star expression
|
|
62
|
-
if err := c.WriteStarExpr(starExpr); err != nil {
|
|
63
|
-
return fmt.Errorf("failed to write inner star expression: %w", err)
|
|
39
|
+
// Check if the operand is an identifier that is varrefed
|
|
40
|
+
isVarrefedIdent := false
|
|
41
|
+
if ident, ok := exp.X.(*ast.Ident); ok {
|
|
42
|
+
if obj := c.pkg.TypesInfo.ObjectOf(ident); obj != nil {
|
|
43
|
+
isVarrefedIdent = c.analysis.NeedsVarRef(obj)
|
|
64
44
|
}
|
|
65
|
-
|
|
66
|
-
// Always add .value for multi-level dereferences
|
|
67
|
-
// For expressions like **p, each * adds a .value
|
|
68
|
-
c.tsw.WriteLiterally("!.value")
|
|
69
|
-
return nil
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
47
|
+
// Write the operand
|
|
48
|
+
if isVarrefedIdent {
|
|
49
|
+
// For varrefed identifiers, we need to access the value first
|
|
50
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
51
|
+
return err
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
// For non-varrefed identifiers and other expressions
|
|
55
|
+
switch operand := exp.X.(type) {
|
|
56
|
+
case *ast.Ident:
|
|
57
|
+
// Write identifier without .value access
|
|
58
|
+
c.WriteIdent(operand, false)
|
|
59
|
+
default:
|
|
60
|
+
// For other expressions (like nested star expressions), use WriteValueExpr
|
|
61
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
62
|
+
return err
|
|
63
|
+
}
|
|
64
|
+
}
|
|
77
65
|
}
|
|
78
66
|
|
|
79
|
-
// Add
|
|
67
|
+
// Add non-null assertion for pointer safety
|
|
80
68
|
c.tsw.WriteLiterally("!")
|
|
81
69
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
// Check what the operand points to (not what the result is)
|
|
71
|
+
operandType := c.pkg.TypesInfo.TypeOf(exp.X)
|
|
72
|
+
if ptrType, isPtr := operandType.(*types.Pointer); isPtr {
|
|
73
|
+
elemType := ptrType.Elem()
|
|
74
|
+
// Only add .value if NOT pointing to a struct
|
|
75
|
+
if _, isStruct := elemType.Underlying().(*types.Struct); !isStruct {
|
|
76
|
+
c.tsw.WriteLiterally(".value")
|
|
77
|
+
}
|
|
78
|
+
// If pointing to a struct, don't add .value (structs are reference types in TS)
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
return nil
|
package/compiler/expr-type.go
CHANGED
|
@@ -11,7 +11,7 @@ import (
|
|
|
11
11
|
// It handles various Go type expressions:
|
|
12
12
|
// - Basic types (e.g., int, string, bool) -> TypeScript primitives (number, string, boolean)
|
|
13
13
|
// - Named types -> TypeScript class/interface names
|
|
14
|
-
// - Pointer types (`*T`) -> `$.
|
|
14
|
+
// - Pointer types (`*T`) -> `$.VarRef<T_ts> | null`
|
|
15
15
|
// - Slice types (`[]T`) -> `$.Slice<T_ts>`
|
|
16
16
|
// - Array types (`[N]T`) -> `T_ts[]`
|
|
17
17
|
// - Map types (`map[K]V`) -> `Map<K_ts, V_ts>`
|
|
@@ -22,13 +22,59 @@ import (
|
|
|
22
22
|
func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
|
|
23
23
|
// Get type information for the expression and use WriteGoType
|
|
24
24
|
typ := c.pkg.TypesInfo.TypeOf(a)
|
|
25
|
-
c.WriteGoType(typ)
|
|
25
|
+
c.WriteGoType(typ, GoTypeContextGeneral)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// writeTypeDescription writes the TypeInfo for a type expr.
|
|
29
29
|
func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
|
|
30
30
|
switch t := typeExpr.(type) {
|
|
31
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
|
+
|
|
32
78
|
if isPrimitiveType(t.Name) {
|
|
33
79
|
if tsType, ok := GoBuiltinToTypescript(t.Name); ok {
|
|
34
80
|
c.tsw.WriteLiterally("{")
|
|
@@ -112,9 +158,16 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
|
|
|
112
158
|
c.tsw.WriteLiterally("kind: $.TypeKind.Function")
|
|
113
159
|
|
|
114
160
|
// Add name if this is a named function type
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
+
}
|
|
118
171
|
}
|
|
119
172
|
}
|
|
120
173
|
|
|
@@ -174,6 +227,80 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
|
|
|
174
227
|
c.tsw.WriteLiterally("'both'")
|
|
175
228
|
}
|
|
176
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("]")
|
|
177
304
|
c.tsw.WriteLiterally("}")
|
|
178
305
|
default:
|
|
179
306
|
// For other types, use the string representation
|
package/compiler/expr-value.go
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
package compiler
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import (
|
|
4
|
+
"go/ast"
|
|
5
|
+
)
|
|
4
6
|
|
|
5
7
|
// WriteValueExpr translates a Go abstract syntax tree (AST) expression (`ast.Expr`)
|
|
6
8
|
// that represents a value into its TypeScript value equivalent.
|
|
7
9
|
// This is a central dispatch function for various expression types:
|
|
8
|
-
// - Identifiers (`ast.Ident`): Delegates to `WriteIdent`, potentially adding `.value` for
|
|
10
|
+
// - Identifiers (`ast.Ident`): Delegates to `WriteIdent`, potentially adding `.value` for varrefed variables.
|
|
9
11
|
// - Selector expressions (`ast.SelectorExpr`, e.g., `obj.Field` or `pkg.Var`): Delegates to `WriteSelectorExpr`.
|
|
10
12
|
// - Pointer dereferences (`ast.StarExpr`, e.g., `*ptr`): Delegates to `WriteStarExpr`.
|
|
11
13
|
// - Function calls (`ast.CallExpr`): Delegates to `WriteCallExpr`.
|
|
@@ -50,43 +52,11 @@ func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
|
|
|
50
52
|
return c.WriteTypeAssertExpr(exp)
|
|
51
53
|
case *ast.IndexExpr:
|
|
52
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)
|
|
53
58
|
case *ast.SliceExpr:
|
|
54
|
-
|
|
55
|
-
c.tsw.WriteLiterally("$.goSlice(")
|
|
56
|
-
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
57
|
-
return err
|
|
58
|
-
}
|
|
59
|
-
// low argument
|
|
60
|
-
c.tsw.WriteLiterally(", ")
|
|
61
|
-
if exp.Low != nil {
|
|
62
|
-
if err := c.WriteValueExpr(exp.Low); err != nil {
|
|
63
|
-
return err
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
c.tsw.WriteLiterally("undefined")
|
|
67
|
-
}
|
|
68
|
-
// high argument
|
|
69
|
-
c.tsw.WriteLiterally(", ")
|
|
70
|
-
if exp.High != nil {
|
|
71
|
-
if err := c.WriteValueExpr(exp.High); err != nil {
|
|
72
|
-
return err
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
c.tsw.WriteLiterally("undefined")
|
|
76
|
-
}
|
|
77
|
-
// max argument (only for full slice expressions)
|
|
78
|
-
if exp.Slice3 {
|
|
79
|
-
c.tsw.WriteLiterally(", ")
|
|
80
|
-
if exp.Max != nil {
|
|
81
|
-
if err := c.WriteValueExpr(exp.Max); err != nil {
|
|
82
|
-
return err
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
c.tsw.WriteLiterally("undefined")
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
c.tsw.WriteLiterally(")")
|
|
89
|
-
return nil
|
|
59
|
+
return c.WriteSliceExpr(exp)
|
|
90
60
|
case *ast.ParenExpr:
|
|
91
61
|
// Check if this is a nil pointer to struct type cast: (*struct{})(nil)
|
|
92
62
|
if starExpr, isStarExpr := exp.X.(*ast.StarExpr); isStarExpr {
|