goscript 0.0.83 → 0.1.0
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 +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +27 -7
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +86 -0
- package/dist/gs/builtin/hostio.js +266 -0
- package/dist/gs/builtin/hostio.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/print.d.ts +8 -0
- package/dist/gs/builtin/print.js +111 -0
- package/dist/gs/builtin/print.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +2 -22
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +2 -51
- package/dist/gs/os/types_js.gs.js +67 -105
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +31 -6
- package/gs/builtin/hostio.test.ts +246 -0
- package/gs/builtin/hostio.ts +413 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/print.test.ts +48 -0
- package/gs/builtin/print.ts +154 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/fmt/fmt.test.ts +41 -30
- package/gs/fmt/fmt.ts +2 -22
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +103 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +74 -153
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
package/compiler/spec-value.go
DELETED
|
@@ -1,540 +0,0 @@
|
|
|
1
|
-
package compiler
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"fmt"
|
|
5
|
-
"go/ast"
|
|
6
|
-
"go/token"
|
|
7
|
-
"go/types"
|
|
8
|
-
|
|
9
|
-
"golang.org/x/tools/go/packages"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
// shouldApplyClone determines whether a `.clone()` method call should be appended
|
|
13
|
-
// to the TypeScript translation of a Go expression `rhs` when it appears on the
|
|
14
|
-
// right-hand side of an assignment. This is primarily to emulate Go's value
|
|
15
|
-
// semantics for struct assignments, where assigning one struct variable to another
|
|
16
|
-
// creates a copy of the struct.
|
|
17
|
-
//
|
|
18
|
-
// It uses `go/types` information (`pkg.TypesInfo`) to determine the type of `rhs`.
|
|
19
|
-
// - If `rhs` is identified as a struct type (either directly, as a named type
|
|
20
|
-
// whose underlying type is a struct, or an unnamed type whose underlying type
|
|
21
|
-
// is a struct), it returns `true`.
|
|
22
|
-
// - An optimization: if `rhs` is a composite literal (`*ast.CompositeLit`),
|
|
23
|
-
// it returns `false` because a composite literal already produces a new value,
|
|
24
|
-
// so cloning is unnecessary.
|
|
25
|
-
// - If type information is unavailable or `rhs` is not a struct type, it returns `false`.
|
|
26
|
-
//
|
|
27
|
-
// This function is crucial for ensuring that assignments of struct values in
|
|
28
|
-
// TypeScript behave like copies, as they do in Go, rather than reference assignments.
|
|
29
|
-
func shouldApplyClone(pkg *packages.Package, rhs ast.Expr) bool {
|
|
30
|
-
if pkg == nil || pkg.TypesInfo == nil {
|
|
31
|
-
// Cannot determine type without type info, default to no clone
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Get the type of the RHS expression
|
|
36
|
-
var exprType types.Type
|
|
37
|
-
|
|
38
|
-
// Handle identifiers (variables) directly - the most common case
|
|
39
|
-
if ident, ok := rhs.(*ast.Ident); ok {
|
|
40
|
-
if obj := pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
41
|
-
// Get the type directly from the object
|
|
42
|
-
exprType = obj.Type()
|
|
43
|
-
} else if obj := pkg.TypesInfo.Defs[ident]; obj != nil {
|
|
44
|
-
// Also check Defs map for definitions
|
|
45
|
-
exprType = obj.Type()
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// If we couldn't get the type from Uses/Defs, try getting it from Types
|
|
50
|
-
if exprType == nil {
|
|
51
|
-
if tv, found := pkg.TypesInfo.Types[rhs]; found && tv.Type != nil {
|
|
52
|
-
exprType = tv.Type
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// No type information available
|
|
57
|
-
if exprType == nil {
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Optimization: If it's a composite literal for a struct, no need to clone
|
|
62
|
-
// as it's already a fresh value
|
|
63
|
-
if _, isCompositeLit := rhs.(*ast.CompositeLit); isCompositeLit {
|
|
64
|
-
return false
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Check if it's a struct type (directly, through named type, or underlying)
|
|
68
|
-
if named, ok := exprType.(*types.Named); ok {
|
|
69
|
-
if _, isStruct := named.Underlying().(*types.Struct); isStruct {
|
|
70
|
-
return true // Named struct type
|
|
71
|
-
}
|
|
72
|
-
} else if _, ok := exprType.(*types.Struct); ok {
|
|
73
|
-
return true // Direct struct type
|
|
74
|
-
} else if underlying := exprType.Underlying(); underlying != nil {
|
|
75
|
-
if _, isStruct := underlying.(*types.Struct); isStruct {
|
|
76
|
-
return true // Underlying is a struct
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return false // Not a struct, do not apply clone
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// WriteValueSpec translates a Go value specification (`ast.ValueSpec`),
|
|
84
|
-
// which represents `var` or `const` declarations, into TypeScript `let`
|
|
85
|
-
// declarations.
|
|
86
|
-
//
|
|
87
|
-
// For single variable declarations (`var x T = val` or `var x = val` or `var x T`):
|
|
88
|
-
// - It determines if the variable `x` needs to be varrefed (e.g., if its address is taken)
|
|
89
|
-
// using `c.analysis.NeedsVarRef(obj)`.
|
|
90
|
-
// - If variable referenced: `let x: $.VarRef<T_ts> = $.varRef(initializer_ts_or_zero_ts);`
|
|
91
|
-
// The type annotation is `$.VarRef<T_ts>`, and the initializer is wrapped in `$.varRef()`.
|
|
92
|
-
// - If not variable referenced: `let x: T_ts = initializer_ts_or_zero_ts;`
|
|
93
|
-
// The type annotation is `T_ts`. If the initializer is `&unvarrefedVar`, it becomes `$.varRef(unvarrefedVar_ts)`.
|
|
94
|
-
// - If no initializer is provided, the TypeScript zero value (from `WriteZeroValueForType`)
|
|
95
|
-
// is used.
|
|
96
|
-
// - Type `T` (or `T_ts`) is obtained from `obj.Type()` and translated via `WriteGoType`.
|
|
97
|
-
//
|
|
98
|
-
// For multiple variable declarations (`var a, b = val1, val2` or `a, b := val1, val2`):
|
|
99
|
-
// - It uses TypeScript array destructuring: `let [a, b] = [val1_ts, val2_ts];`.
|
|
100
|
-
// - If initialized from a single multi-return function call (`a, b := func()`),
|
|
101
|
-
// it becomes `let [a, b] = func_ts();`.
|
|
102
|
-
// - If no initializers are provided, it defaults to `let [a,b] = []` (with a TODO
|
|
103
|
-
// to assign correct individual zero values).
|
|
104
|
-
//
|
|
105
|
-
// Documentation comments associated with the `ValueSpec` are preserved.
|
|
106
|
-
func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
107
|
-
if a.Doc != nil {
|
|
108
|
-
c.WriteDoc(a.Doc)
|
|
109
|
-
}
|
|
110
|
-
if a.Comment != nil {
|
|
111
|
-
c.WriteDoc(a.Comment)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Handle single variable declaration
|
|
115
|
-
if len(a.Names) == 1 {
|
|
116
|
-
name := a.Names[0]
|
|
117
|
-
// Skip underscore variables
|
|
118
|
-
if name.Name == "_" {
|
|
119
|
-
return nil
|
|
120
|
-
}
|
|
121
|
-
obj := c.pkg.TypesInfo.Defs[name]
|
|
122
|
-
if obj == nil {
|
|
123
|
-
return fmt.Errorf("could not resolve type: %v", name)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
goType := obj.Type()
|
|
127
|
-
needsVarRef := c.analysis.NeedsVarRef(obj) // Check if address is taken
|
|
128
|
-
|
|
129
|
-
hasInitializer := len(a.Values) > 0
|
|
130
|
-
var initializerExpr ast.Expr
|
|
131
|
-
if hasInitializer {
|
|
132
|
-
initializerExpr = a.Values[0]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Check if the initializer will result in an $.arrayToSlice call in TypeScript
|
|
136
|
-
isSliceConversion := false
|
|
137
|
-
if hasInitializer {
|
|
138
|
-
// Case 1: Direct call to $.arrayToSlice in Go source (less common for typical array literals)
|
|
139
|
-
if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
|
|
140
|
-
if selExpr, isSelExpr := callExpr.Fun.(*ast.SelectorExpr); isSelExpr {
|
|
141
|
-
if pkgIdent, isPkgIdent := selExpr.X.(*ast.Ident); isPkgIdent && pkgIdent.Name == "$" {
|
|
142
|
-
if selExpr.Sel.Name == "arrayToSlice" {
|
|
143
|
-
isSliceConversion = true
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Case 2: Go array or slice literal, which will be compiled to $.arrayToSlice
|
|
150
|
-
// We also check if the original Go type is actually a slice or array.
|
|
151
|
-
if !isSliceConversion { // Only check if not already determined by Case 1
|
|
152
|
-
if _, isCompositeLit := initializerExpr.(*ast.CompositeLit); isCompositeLit {
|
|
153
|
-
switch goType.Underlying().(type) {
|
|
154
|
-
case *types.Slice, *types.Array:
|
|
155
|
-
isSliceConversion = true
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Start declaration - add export for Go-exported symbols (but not if inside a function)
|
|
162
|
-
isInsideFunction := false
|
|
163
|
-
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
164
|
-
isInsideFunction = nodeInfo.IsInsideFunction
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if !isInsideFunction {
|
|
168
|
-
c.tsw.WriteLiterally("export ")
|
|
169
|
-
}
|
|
170
|
-
c.tsw.WriteLiterally("let ")
|
|
171
|
-
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
172
|
-
|
|
173
|
-
// Write type annotation if:
|
|
174
|
-
// 1. Not a slice conversion (normal case), OR
|
|
175
|
-
// 2. Is a slice conversion but needs varRefing (we need explicit type for $.varRef())
|
|
176
|
-
if !isSliceConversion || needsVarRef {
|
|
177
|
-
c.tsw.WriteLiterally(": ")
|
|
178
|
-
// Write type annotation
|
|
179
|
-
if needsVarRef {
|
|
180
|
-
// If varrefed, the variable holds VarRef<OriginalGoType>
|
|
181
|
-
c.tsw.WriteLiterally("$.VarRef<")
|
|
182
|
-
|
|
183
|
-
// Special case: if this is a slice conversion from an array type,
|
|
184
|
-
// we should use the slice type instead of the array type
|
|
185
|
-
if isSliceConversion {
|
|
186
|
-
if arrayType, isArray := goType.Underlying().(*types.Array); isArray {
|
|
187
|
-
// Convert [N]T to $.Slice<T>
|
|
188
|
-
c.tsw.WriteLiterally("$.Slice<")
|
|
189
|
-
c.WriteGoType(arrayType.Elem(), GoTypeContextGeneral)
|
|
190
|
-
c.tsw.WriteLiterally(">")
|
|
191
|
-
} else {
|
|
192
|
-
// For slice types, write as-is (already $.Slice<T>)
|
|
193
|
-
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
196
|
-
c.WriteGoType(goType, GoTypeContextGeneral) // Write the original Go type T
|
|
197
|
-
}
|
|
198
|
-
c.tsw.WriteLiterally(">")
|
|
199
|
-
} else {
|
|
200
|
-
// If not varrefed, the variable holds the translated Go type directly
|
|
201
|
-
// Custom logic for non-var-ref'd pointers to structs/interfaces.
|
|
202
|
-
if ptrType, isPtr := goType.(*types.Pointer); isPtr {
|
|
203
|
-
elemType := ptrType.Elem()
|
|
204
|
-
actualElemType := elemType.Underlying() // Get the true underlying type (e.g., struct, interface, basic)
|
|
205
|
-
|
|
206
|
-
isStruct := false
|
|
207
|
-
if _, ok := actualElemType.(*types.Struct); ok {
|
|
208
|
-
isStruct = true
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
isInterface := false
|
|
212
|
-
if _, ok := actualElemType.(*types.Interface); ok {
|
|
213
|
-
isInterface = true
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if isStruct || isInterface {
|
|
217
|
-
// For non-var-ref'd pointers to structs or interfaces,
|
|
218
|
-
// the type is T | null, not $.VarRef<T> | null.
|
|
219
|
-
c.WriteGoType(elemType, GoTypeContextGeneral) // Write the element type itself (e.g., MyStruct)
|
|
220
|
-
c.tsw.WriteLiterally(" | null")
|
|
221
|
-
} else {
|
|
222
|
-
// For other pointer types (e.g., *int, *string, *[]int, **MyStruct),
|
|
223
|
-
// or pointers to types that are not structs/interfaces,
|
|
224
|
-
// use the standard pointer type translation.
|
|
225
|
-
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
226
|
-
}
|
|
227
|
-
} else {
|
|
228
|
-
// Not a pointer type, write as is.
|
|
229
|
-
// Use AST-based type writing if explicit type is provided, otherwise use WriteGoType
|
|
230
|
-
if a.Type != nil {
|
|
231
|
-
// Explicit type annotation in Go code - use AST to preserve qualified names
|
|
232
|
-
c.WriteTypeExpr(a.Type)
|
|
233
|
-
} else {
|
|
234
|
-
// No explicit type - use type inference from WriteGoType
|
|
235
|
-
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Write initializer
|
|
242
|
-
c.tsw.WriteLiterally(" = ")
|
|
243
|
-
|
|
244
|
-
// Special case for nil pointer to struct type: (*struct{})(nil)
|
|
245
|
-
if hasInitializer {
|
|
246
|
-
if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
|
|
247
|
-
if starExpr, isStarExpr := callExpr.Fun.(*ast.StarExpr); isStarExpr {
|
|
248
|
-
if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
|
|
249
|
-
// Check if the argument is nil
|
|
250
|
-
if len(callExpr.Args) == 1 {
|
|
251
|
-
if nilIdent, isIdent := callExpr.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
|
|
252
|
-
c.tsw.WriteLiterally("null")
|
|
253
|
-
c.tsw.WriteLine("") // Ensure newline after null
|
|
254
|
-
return nil
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if needsVarRef {
|
|
263
|
-
// VarRef variable: let v: VarRef<T> = $.varRef(init_or_zero);
|
|
264
|
-
c.tsw.WriteLiterally("$.varRef(")
|
|
265
|
-
if hasInitializer {
|
|
266
|
-
// Write the compiled initializer expression normally
|
|
267
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
268
|
-
return err
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
// No initializer, varRef the zero value
|
|
272
|
-
c.WriteZeroValueForType(goType)
|
|
273
|
-
}
|
|
274
|
-
c.tsw.WriteLiterally(")")
|
|
275
|
-
} else {
|
|
276
|
-
// Unvarrefed variable: let v: T = init_or_zero;
|
|
277
|
-
if hasInitializer {
|
|
278
|
-
// Handle &v initializer specifically for unvarrefed variables
|
|
279
|
-
if unaryExpr, isUnary := initializerExpr.(*ast.UnaryExpr); isUnary && unaryExpr.Op == token.AND {
|
|
280
|
-
// Initializer is &expr
|
|
281
|
-
// Check if expr is an identifier (variable) or something else (e.g., composite literal)
|
|
282
|
-
if unaryExprXIdent, ok := unaryExpr.X.(*ast.Ident); ok {
|
|
283
|
-
// Case: &variable
|
|
284
|
-
// Check if the variable is varrefed
|
|
285
|
-
innerObj := c.objectOfIdent(unaryExprXIdent)
|
|
286
|
-
needsVarRefOperand := innerObj != nil && c.analysis.NeedsVarRef(innerObj)
|
|
287
|
-
|
|
288
|
-
// If variable is varrefed, assign the varRef itself (variable)
|
|
289
|
-
// If variable is not varrefed, assign $.varRef(variable)
|
|
290
|
-
if needsVarRefOperand {
|
|
291
|
-
// do not write .value here.
|
|
292
|
-
c.WriteIdent(unaryExprXIdent, false)
|
|
293
|
-
} else {
|
|
294
|
-
// &unvarrefedVar -> $.varRef(unvarrefedVar)
|
|
295
|
-
c.tsw.WriteLiterally("$.varRef(")
|
|
296
|
-
if err := c.WriteValueExpr(unaryExpr.X); err != nil { // Write 'variable'
|
|
297
|
-
return err
|
|
298
|
-
}
|
|
299
|
-
c.tsw.WriteLiterally(")")
|
|
300
|
-
}
|
|
301
|
-
} else {
|
|
302
|
-
// Case: &compositeLiteral or &otherExpression
|
|
303
|
-
// Let WriteUnaryExpr handle this properly (note: markAsStructValue is now applied in WriteCompositeLit)
|
|
304
|
-
if err := c.WriteValueExpr(unaryExpr); err != nil {
|
|
305
|
-
return err
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
} else {
|
|
309
|
-
// Check if this is a named type with methods and the initializer is a basic value
|
|
310
|
-
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
311
|
-
// Check if this is a wrapper type first
|
|
312
|
-
if c.isWrapperType(namedType) {
|
|
313
|
-
// For wrapper types, no constructor wrapping needed
|
|
314
|
-
if shouldApplyClone(c.pkg, initializerExpr) {
|
|
315
|
-
// When cloning for value assignment, mark the result as struct value
|
|
316
|
-
c.tsw.WriteLiterally("$.markAsStructValue(")
|
|
317
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
318
|
-
return err
|
|
319
|
-
}
|
|
320
|
-
c.tsw.WriteLiterally(".clone())")
|
|
321
|
-
} else {
|
|
322
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
323
|
-
return err
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
typeName := namedType.Obj().Name()
|
|
328
|
-
if c.hasReceiverMethods(typeName) {
|
|
329
|
-
// Check if the initializer is a basic literal or simple value that needs wrapping
|
|
330
|
-
needsConstructor := false
|
|
331
|
-
switch expr := initializerExpr.(type) {
|
|
332
|
-
case *ast.BasicLit:
|
|
333
|
-
needsConstructor = true
|
|
334
|
-
case *ast.Ident:
|
|
335
|
-
// Check if it's a simple identifier (not a function call or complex expression)
|
|
336
|
-
if expr.Name != "nil" {
|
|
337
|
-
// Check if this identifier refers to a value of the underlying type
|
|
338
|
-
if obj := c.objectOfIdent(expr); obj != nil {
|
|
339
|
-
if objType := obj.Type(); objType != nil {
|
|
340
|
-
// If the identifier's type matches the underlying type, wrap it
|
|
341
|
-
if types.Identical(objType, namedType.Underlying()) {
|
|
342
|
-
needsConstructor = true
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
case *ast.CallExpr:
|
|
348
|
-
// Check if this is a make() call that returns the underlying type
|
|
349
|
-
if funIdent, ok := expr.Fun.(*ast.Ident); ok && funIdent.Name == "make" {
|
|
350
|
-
// Check if the make call returns a type that matches the underlying type
|
|
351
|
-
if exprType := c.pkg.TypesInfo.TypeOf(expr); exprType != nil {
|
|
352
|
-
if types.Identical(exprType, namedType.Underlying()) {
|
|
353
|
-
needsConstructor = true
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if needsConstructor {
|
|
360
|
-
c.tsw.WriteLiterallyf("new %s(", typeName)
|
|
361
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
362
|
-
return err
|
|
363
|
-
}
|
|
364
|
-
c.tsw.WriteLiterally(")")
|
|
365
|
-
} else {
|
|
366
|
-
// Regular initializer for named type (e.g., function call that returns the type)
|
|
367
|
-
if shouldApplyClone(c.pkg, initializerExpr) {
|
|
368
|
-
// When cloning for value assignment, mark the result as struct value
|
|
369
|
-
c.tsw.WriteLiterally("$.markAsStructValue(")
|
|
370
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
371
|
-
return err
|
|
372
|
-
}
|
|
373
|
-
c.tsw.WriteLiterally(".clone())")
|
|
374
|
-
} else {
|
|
375
|
-
if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
|
|
376
|
-
return err
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
} else {
|
|
381
|
-
// Named type without methods, handle normally
|
|
382
|
-
if shouldApplyClone(c.pkg, initializerExpr) {
|
|
383
|
-
// When cloning for value assignment, mark the result as struct value
|
|
384
|
-
c.tsw.WriteLiterally("$.markAsStructValue(")
|
|
385
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
386
|
-
return err
|
|
387
|
-
}
|
|
388
|
-
c.tsw.WriteLiterally(".clone())")
|
|
389
|
-
} else {
|
|
390
|
-
if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
|
|
391
|
-
return err
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
} else {
|
|
397
|
-
// Regular initializer, clone if needed
|
|
398
|
-
if shouldApplyClone(c.pkg, initializerExpr) {
|
|
399
|
-
// When cloning for value assignment, mark the result as struct value
|
|
400
|
-
c.tsw.WriteLiterally("$.markAsStructValue(")
|
|
401
|
-
if err := c.WriteValueExpr(initializerExpr); err != nil {
|
|
402
|
-
return err
|
|
403
|
-
}
|
|
404
|
-
c.tsw.WriteLiterally(".clone())")
|
|
405
|
-
} else {
|
|
406
|
-
// Check if this is a pointer variable assigned to interface
|
|
407
|
-
if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
|
|
408
|
-
return err
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
} else {
|
|
414
|
-
// No initializer, use the zero value directly
|
|
415
|
-
// Check if this is a wrapper type first
|
|
416
|
-
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
417
|
-
if c.isWrapperType(namedType) {
|
|
418
|
-
// For wrapper types, just use zero value directly
|
|
419
|
-
c.WriteZeroValueForType(goType)
|
|
420
|
-
} else {
|
|
421
|
-
typeName := namedType.Obj().Name()
|
|
422
|
-
if c.hasReceiverMethods(typeName) {
|
|
423
|
-
// For named types with methods, create a new instance with zero value
|
|
424
|
-
c.tsw.WriteLiterallyf("new %s(", typeName)
|
|
425
|
-
c.WriteZeroValueForType(namedType.Underlying())
|
|
426
|
-
c.tsw.WriteLiterally(")")
|
|
427
|
-
} else {
|
|
428
|
-
c.WriteZeroValueForType(goType)
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
} else {
|
|
432
|
-
c.WriteZeroValueForType(goType)
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
c.tsw.WriteLine("") // Finish the declaration line
|
|
437
|
-
return nil
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// --- Multi-variable declaration with proper individual declarations ---
|
|
441
|
-
// Instead of using array destructuring which creates undefined types,
|
|
442
|
-
// generate individual variable declarations with proper types and zero values
|
|
443
|
-
if len(a.Values) > 0 {
|
|
444
|
-
// Has initializers - use array destructuring for multiple assignments
|
|
445
|
-
c.tsw.WriteLiterally("let ")
|
|
446
|
-
c.tsw.WriteLiterally("[") // Use array destructuring for multi-assign
|
|
447
|
-
for i, name := range a.Names {
|
|
448
|
-
if i != 0 {
|
|
449
|
-
c.tsw.WriteLiterally(", ")
|
|
450
|
-
}
|
|
451
|
-
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
452
|
-
}
|
|
453
|
-
c.tsw.WriteLiterally("]")
|
|
454
|
-
|
|
455
|
-
c.tsw.WriteLiterally(" = ")
|
|
456
|
-
if len(a.Values) == 1 && len(a.Names) > 1 {
|
|
457
|
-
// Assign from a single multi-return value
|
|
458
|
-
if err := c.WriteValueExpr(a.Values[0]); err != nil {
|
|
459
|
-
return err
|
|
460
|
-
}
|
|
461
|
-
} else {
|
|
462
|
-
// Assign from multiple values
|
|
463
|
-
c.tsw.WriteLiterally("[")
|
|
464
|
-
for i, val := range a.Values {
|
|
465
|
-
if i != 0 {
|
|
466
|
-
c.tsw.WriteLiterally(", ")
|
|
467
|
-
}
|
|
468
|
-
if err := c.WriteValueExpr(val); err != nil { // Initializers are values
|
|
469
|
-
return err
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
c.tsw.WriteLiterally("]")
|
|
473
|
-
}
|
|
474
|
-
c.tsw.WriteLine("")
|
|
475
|
-
} else {
|
|
476
|
-
// No initializers - generate individual variable declarations with zero values
|
|
477
|
-
for _, name := range a.Names {
|
|
478
|
-
// Skip underscore variables
|
|
479
|
-
if name.Name == "_" {
|
|
480
|
-
continue
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
obj := c.pkg.TypesInfo.Defs[name]
|
|
484
|
-
if obj == nil {
|
|
485
|
-
return fmt.Errorf("could not resolve type for variable %v", name.Name)
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
goType := obj.Type()
|
|
489
|
-
|
|
490
|
-
// Check if exported and not inside function
|
|
491
|
-
isInsideFunction := false
|
|
492
|
-
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
493
|
-
isInsideFunction = nodeInfo.IsInsideFunction
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
if !isInsideFunction {
|
|
497
|
-
c.tsw.WriteLiterally("export ")
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
c.tsw.WriteLiterally("let ")
|
|
501
|
-
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
502
|
-
c.tsw.WriteLiterally(": ")
|
|
503
|
-
|
|
504
|
-
// Write type annotation - use AST-based type if available, otherwise infer from goType
|
|
505
|
-
if a.Type != nil {
|
|
506
|
-
c.WriteTypeExpr(a.Type)
|
|
507
|
-
} else {
|
|
508
|
-
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
c.tsw.WriteLiterally(" = ")
|
|
512
|
-
c.WriteZeroValueForType(goType)
|
|
513
|
-
c.tsw.WriteLine("")
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
return nil
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// writeInitializerForInterface handles writing initializer expressions for interface variables,
|
|
520
|
-
// with special handling for pointer variable assignments to avoid automatic .value dereferencing
|
|
521
|
-
func (c *GoToTSCompiler) writeInitializerForInterface(initializerExpr ast.Expr, goType types.Type) error {
|
|
522
|
-
// Check if this is a pointer variable assigned to interface
|
|
523
|
-
if rhsIdent, isIdent := initializerExpr.(*ast.Ident); isIdent {
|
|
524
|
-
if rhsObj := c.objectOfIdent(rhsIdent); rhsObj != nil {
|
|
525
|
-
// Check if LHS is interface and RHS is pointer
|
|
526
|
-
if _, isInterface := goType.Underlying().(*types.Interface); isInterface {
|
|
527
|
-
if _, isPtr := rhsObj.Type().(*types.Pointer); isPtr {
|
|
528
|
-
// For pointer variables that point to varrefed values, write without .value
|
|
529
|
-
// We want to pass the VarRef object itself to the interface, not its .value
|
|
530
|
-
if c.analysis.NeedsVarRefAccess(rhsObj) {
|
|
531
|
-
c.WriteIdent(rhsIdent, false)
|
|
532
|
-
return nil
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
// Default case: use regular WriteValueExpr
|
|
539
|
-
return c.WriteValueExpr(initializerExpr)
|
|
540
|
-
}
|