goscript 0.0.22 → 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.
@@ -4,7 +4,6 @@ import (
4
4
  "fmt"
5
5
  "go/ast"
6
6
  "go/token"
7
- "go/types"
8
7
  "strings"
9
8
  )
10
9
 
@@ -46,418 +45,165 @@ func (c *GoToTSCompiler) writeTypeAssert(lhs []ast.Expr, typeAssertExpr *ast.Typ
46
45
  return fmt.Errorf("type assertion assignment requires exactly 2 variables on LHS, got %d", len(lhs))
47
46
  }
48
47
 
49
- // Get variable names, handling blank identifiers
50
- valueIsBlank := false
51
- okIsBlank := false
52
- var valueName string
48
+ var okIsBlank bool
53
49
  var okName string
54
- var valueIdent *ast.Ident
55
- var okIdent *ast.Ident
56
50
 
57
- if valId, ok := lhs[0].(*ast.Ident); ok {
58
- valueIdent = valId
59
- if valId.Name == "_" {
60
- valueIsBlank = true
61
- } else {
62
- valueName = valId.Name
63
- }
64
- } else {
65
- return fmt.Errorf("unhandled LHS expression type for value in type assertion: %T", lhs[0])
51
+ okExpr := lhs[1]
52
+ okIdent, ok := okExpr.(*ast.Ident)
53
+ if !ok {
54
+ return fmt.Errorf("ok expression is not an identifier: %T", okExpr)
66
55
  }
56
+ okIsBlank = okIdent.Name == "_"
57
+ okName = okIdent.Name
67
58
 
68
- if okId, ok := lhs[1].(*ast.Ident); ok {
69
- okIdent = okId
70
- if okId.Name == "_" {
71
- okIsBlank = true
72
- } else {
73
- okName = okId.Name
59
+ valueExpr := lhs[0]
60
+
61
+ // Determine if 'ok' variable is new in 'tok == token.DEFINE' context.
62
+ // This uses types.Info.Defs to see if the identifier is defined by this statement.
63
+ var okIsNewInDefine bool
64
+ if tok == token.DEFINE && !okIsBlank {
65
+ if c.pkg.TypesInfo.Defs[okIdent] != nil {
66
+ okIsNewInDefine = true
74
67
  }
75
- } else {
76
- return fmt.Errorf("unhandled LHS expression type for ok in type assertion: %T", lhs[1])
77
68
  }
78
69
 
79
- // For token.DEFINE (:=), we need to check if any of the variables are already declared
80
- // In Go, := can be used for redeclaration if at least one variable is new
81
- writeEndParen := false
82
- if tok == token.DEFINE {
83
- // Identify which variables are new vs existing
84
- valueIsNew := true
85
- okIsNew := true
86
- anyNewVars := false
87
- allNewVars := true
70
+ switch vLHS := valueExpr.(type) {
71
+ case *ast.Ident:
72
+ var valueIsBlank bool
73
+ var valueName string
74
+ valueIdent := vLHS
75
+ valueIsBlank = (valueIdent.Name == "_")
76
+ valueName = valueIdent.Name
88
77
 
89
- // Check if variables are already in scope
90
- if !valueIsBlank {
91
- if obj := c.pkg.TypesInfo.Uses[valueIdent]; obj != nil {
92
- // If it's in Uses, it's referenced elsewhere, so it exists
93
- valueIsNew = false
94
- allNewVars = false
95
- }
96
- if valueIsNew {
97
- anyNewVars = true
78
+ var valueIsNewInDefine bool
79
+ if tok == token.DEFINE && !valueIsBlank {
80
+ if c.pkg.TypesInfo.Defs[valueIdent] != nil { // valueIdent is defined by this statement
81
+ valueIsNewInDefine = true
98
82
  }
99
83
  }
100
84
 
101
- if !okIsBlank {
102
- if obj := c.pkg.TypesInfo.Uses[okIdent]; obj != nil {
103
- // If it's in Uses, it's referenced elsewhere, so it exists
104
- okIsNew = false
105
- allNewVars = false
106
- }
107
- if okIsNew {
108
- anyNewVars = true
109
- }
110
- }
85
+ writeEndParen := false // For wrapping assignment in parens to make it an expression
86
+ letDestructure := false // True if 'let { value: v, ok: o } = ...' is appropriate
111
87
 
112
- if allNewVars && anyNewVars {
113
- c.tsw.WriteLiterally("let ")
114
- } else if anyNewVars {
115
- // If only some variables are new, declare them separately
116
- if !valueIsBlank && valueIsNew {
117
- c.tsw.WriteLiterally("let ")
118
- c.tsw.WriteLiterally(valueName)
119
- // Add type annotation if possible
120
- if tv, ok := c.pkg.TypesInfo.Types[assertedType]; ok {
88
+ if tok == token.DEFINE {
89
+ anyNewVars := (valueIsNewInDefine && !valueIsBlank) || (okIsNewInDefine && !okIsBlank)
90
+ // allVarsNewOrBlank means suitable for a single `let {v,o} = ...` destructuring
91
+ allVarsNewOrBlank := (valueIsBlank || valueIsNewInDefine) && (okIsBlank || okIsNewInDefine)
92
+
93
+ if allVarsNewOrBlank && anyNewVars {
94
+ letDestructure = true
95
+ } else if anyNewVars { // Mixed: some new, some existing. Declare new ones separately.
96
+ if !valueIsBlank && valueIsNewInDefine {
97
+ c.tsw.WriteLiterally("let ")
98
+ c.tsw.WriteLiterally(valueName)
121
99
  c.tsw.WriteLiterally(": ")
122
- c.WriteGoType(tv.Type)
100
+ c.WriteTypeExpr(assertedType) // Use WriteTypeExpr for TS type annotation
101
+ c.tsw.WriteLine("")
123
102
  }
124
- c.tsw.WriteLine("")
125
- }
126
- if !okIsBlank && okIsNew {
127
- c.tsw.WriteLiterally("let ")
128
- c.tsw.WriteLiterally(okName)
129
- c.tsw.WriteLiterally(": boolean") // ok is always boolean
130
- c.tsw.WriteLine("")
131
- }
132
- // Use parenthesized destructuring assignment for existing variables
133
- c.tsw.WriteLiterally(";(")
134
- writeEndParen = true
135
- } else {
136
- // All variables exist, use parenthesized destructuring assignment
137
- c.tsw.WriteLiterally(";(")
103
+ if !okIsBlank && okIsNewInDefine {
104
+ c.tsw.WriteLiterally("let ")
105
+ c.tsw.WriteLiterally(okName)
106
+ c.tsw.WriteLiterally(": boolean")
107
+ c.tsw.WriteLine("")
108
+ }
109
+ c.tsw.WriteLiterally("(") // Parenthesize the assignment part
110
+ writeEndParen = true
111
+ } else { // All variables exist
112
+ c.tsw.WriteLiterally("(")
113
+ writeEndParen = true
114
+ }
115
+ } else { // tok == token.ASSIGN
116
+ c.tsw.WriteLiterally("(")
138
117
  writeEndParen = true
139
118
  }
140
- } else {
141
- c.tsw.WriteLiterally("(")
142
- }
143
-
144
- c.tsw.WriteLiterally("{ ")
145
- // Dynamically build the destructuring pattern
146
- parts := []string{}
147
- if !valueIsBlank {
148
- parts = append(parts, fmt.Sprintf("value: %s", valueName))
149
- }
150
- if !okIsBlank {
151
- parts = append(parts, fmt.Sprintf("ok: %s", okName))
152
- }
153
- c.tsw.WriteLiterally(strings.Join(parts, ", "))
154
- c.tsw.WriteLiterally(" } = $.typeAssert<")
155
-
156
- // Write the asserted type for the generic
157
- c.WriteTypeExpr(assertedType)
158
- c.tsw.WriteLiterally(">(")
159
-
160
- // Write the interface expression
161
- if err := c.WriteValueExpr(interfaceExpr); err != nil {
162
- return fmt.Errorf("failed to write interface expression in type assertion call: %w", err)
163
- }
164
- c.tsw.WriteLiterally(", ")
165
-
166
- // Use structured type information for all types
167
- switch typeExpr := assertedType.(type) {
168
- case *ast.MapType:
169
- c.tsw.WriteLiterally("{")
170
- c.tsw.WriteLiterally("kind: $.TypeKind.Map, ")
171
-
172
- c.tsw.WriteLiterally("keyType: ")
173
- if ident, ok := typeExpr.Key.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
174
- if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
175
- c.tsw.WriteLiterallyf("'%s'", tsType)
176
- } else {
177
- c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
178
- }
179
- } else {
180
- c.writeTypeDescription(typeExpr.Key)
181
- }
182
-
183
- c.tsw.WriteLiterally(", ")
184
-
185
- // Add element type
186
- c.tsw.WriteLiterally("elemType: ")
187
- if ident, ok := typeExpr.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
188
- if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
189
- c.tsw.WriteLiterallyf("'%s'", tsType)
190
- } else {
191
- c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
192
- }
193
- } else {
194
- c.writeTypeDescription(typeExpr.Value)
195
- }
196
-
197
- c.tsw.WriteLiterally("}")
198
- case *ast.ArrayType:
199
- // Determine if it's a slice or array
200
- typeKind := "$.TypeKind.Slice"
201
- if typeExpr.Len != nil {
202
- typeKind = "$.TypeKind.Array"
203
- }
204
-
205
- // Create a type descriptor object
206
- c.tsw.WriteLiterally("{")
207
- c.tsw.WriteLiterallyf("kind: %s, ", typeKind)
208
-
209
- // Add element type
210
- c.tsw.WriteLiterally("elemType: ")
211
- if ident, ok := typeExpr.Elt.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
212
- if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
213
- c.tsw.WriteLiterallyf("'%s'", tsType)
214
- } else {
215
- c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
216
- }
217
- } else {
218
- c.writeTypeDescription(typeExpr.Elt)
219
- }
220
-
221
- c.tsw.WriteLiterally("}")
222
- case *ast.StructType:
223
- // For struct types, create a type descriptor object
224
- c.tsw.WriteLiterally("{")
225
- c.tsw.WriteLiterally("kind: $.TypeKind.Struct")
226
-
227
- // Get the type name if available
228
- typeName := c.getTypeNameString(assertedType)
229
- if typeName != "unknown" {
230
- c.tsw.WriteLiterallyf(", name: '%s'", typeName)
231
- }
232
-
233
- if typeExpr.Fields != nil && typeExpr.Fields.List != nil {
234
- // Add fields property to provide type information
235
- c.tsw.WriteLiterally(", fields: {")
236
-
237
- hasFields := false
238
- for _, field := range typeExpr.Fields.List {
239
- if len(field.Names) > 0 {
240
- for _, name := range field.Names {
241
- if hasFields {
242
- c.tsw.WriteLiterally(", ")
243
- }
244
- c.tsw.WriteLiterally(fmt.Sprintf("'%s': ", name.Name))
245
- c.writeTypeDescription(field.Type)
246
- hasFields = true
247
- }
248
- }
249
- }
250
119
 
251
- c.tsw.WriteLiterally("}")
252
- } else {
253
- c.tsw.WriteLiterally(", fields: {}")
120
+ if letDestructure {
121
+ c.tsw.WriteLiterally("let ")
254
122
  }
255
123
 
256
- // Add empty methods set to satisfy StructTypeInfo interface
257
- c.tsw.WriteLiterally(", methods: []")
258
-
259
- c.tsw.WriteLiterally("}")
260
- case *ast.InterfaceType:
261
- c.tsw.WriteLiterally("{")
262
- c.tsw.WriteLiterally("kind: $.TypeKind.Interface")
263
-
264
- // Get the type name if available
265
- typeName := c.getTypeNameString(assertedType)
266
- if typeName != "unknown" {
267
- c.tsw.WriteLiterallyf(", name: '%s'", typeName)
124
+ // Write the destructuring part: { value: v, ok: o }
125
+ c.tsw.WriteLiterally("{ ")
126
+ parts := []string{}
127
+ if !valueIsBlank {
128
+ parts = append(parts, fmt.Sprintf("value: %s", valueName))
268
129
  }
269
-
270
- // Add methods if available
271
- c.tsw.WriteLiterally(", methods: []")
272
-
273
- c.tsw.WriteLiterally("}")
274
- case *ast.StarExpr:
275
- c.tsw.WriteLiterally("{")
276
- c.tsw.WriteLiterally("kind: $.TypeKind.Pointer")
277
-
278
- // Add element type if it's a struct type or named type
279
- if structType, ok := typeExpr.X.(*ast.StructType); ok {
280
- c.tsw.WriteLiterally(", elemType: ")
281
- c.writeTypeDescription(structType)
282
- } else if ident, ok := typeExpr.X.(*ast.Ident); ok {
283
- c.tsw.WriteLiterallyf(", elemType: '%s'", ident.Name)
130
+ if !okIsBlank {
131
+ parts = append(parts, fmt.Sprintf("ok: %s", okName))
284
132
  }
285
-
286
- c.tsw.WriteLiterally("}")
287
- case *ast.ChanType:
288
- c.tsw.WriteLiterally("{")
289
- c.tsw.WriteLiterally("kind: $.TypeKind.Channel")
290
-
291
- // Add element type
292
- c.tsw.WriteLiterally(", elemType: ")
293
- if ident, ok := typeExpr.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
294
- if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
295
- c.tsw.WriteLiterallyf("'%s'", tsType)
296
- } else {
297
- c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
298
- }
299
- } else {
300
- c.writeTypeDescription(typeExpr.Value)
133
+ c.tsw.WriteLiterally(strings.Join(parts, ", "))
134
+ c.tsw.WriteLiterally(" } = $.typeAssert<")
135
+ c.WriteTypeExpr(assertedType) // Generic: <AssertedTypeTS>
136
+ c.tsw.WriteLiterally(">(")
137
+ if err := c.WriteValueExpr(interfaceExpr); err != nil { // Arg1: interfaceExpr
138
+ return fmt.Errorf("failed to write interface expression in type assertion call: %w", err)
301
139
  }
140
+ c.tsw.WriteLiterally(", ")
141
+ c.writeTypeDescription(assertedType) // Arg2: type info for runtime
142
+ c.tsw.WriteLiterally(")")
302
143
 
303
- c.tsw.WriteLiterally(", direction: ")
304
- switch typeExpr.Dir {
305
- case ast.SEND:
306
- c.tsw.WriteLiterally("'send'")
307
- case ast.RECV:
308
- c.tsw.WriteLiterally("'receive'")
309
- case ast.SEND | ast.RECV: // bidirectional
310
- c.tsw.WriteLiterally("'both'")
311
- default:
312
- // This should not happen, but just in case
313
- c.tsw.WriteLiterally("'both'")
144
+ if writeEndParen {
145
+ c.tsw.WriteLiterally(")")
314
146
  }
147
+ c.tsw.WriteLine("")
315
148
 
316
- c.tsw.WriteLiterally("}")
317
- case *ast.FuncType:
318
- // For function types, create a type descriptor object with params and results
319
- c.tsw.WriteLiterally("{")
320
- c.tsw.WriteLiterally("kind: $.TypeKind.Function")
321
-
322
- // Add name if this is a named function type
323
- if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
324
- if named, ok := namedType.(*types.Named); ok {
325
- c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
326
- }
149
+ case *ast.SelectorExpr:
150
+ // Handle s.field, ok := expr.(Type)
151
+ tempValName := "_gs_ta_val_" // Fixed name for temporary value
152
+ tempOkName := "_gs_ta_ok_" // Fixed name for temporary ok status
153
+
154
+ // Declare temporary variables:
155
+ // let _gs_ta_val_: AssertedTypeTS;
156
+ c.tsw.WriteLiterally("let ")
157
+ c.tsw.WriteLiterally(tempValName)
158
+ c.tsw.WriteLiterally(": ")
159
+ c.WriteTypeExpr(assertedType) // TypeScript type for assertedType
160
+ c.tsw.WriteLine("")
161
+
162
+ // let _gs_ta_ok_: boolean;
163
+ c.tsw.WriteLiterally("let ")
164
+ c.tsw.WriteLiterally(tempOkName)
165
+ c.tsw.WriteLiterally(": boolean")
166
+ c.tsw.WriteLine("")
167
+
168
+ // Perform type assertion into temporary variables:
169
+ // ({ value: _gs_ta_val_, ok: _gs_ta_ok_ } = $.typeAssert<AssertedTypeTS>(expr, "GoTypeStr"));
170
+ c.tsw.WriteLiterally("({ value: ")
171
+ c.tsw.WriteLiterally(tempValName)
172
+ c.tsw.WriteLiterally(", ok: ")
173
+ c.tsw.WriteLiterally(tempOkName)
174
+ c.tsw.WriteLiterally(" } = $.typeAssert<")
175
+ c.WriteTypeExpr(assertedType) // Generic: <AssertedTypeTS>
176
+ c.tsw.WriteLiterally(">(")
177
+ if err := c.WriteValueExpr(interfaceExpr); err != nil { // Arg1: interfaceExpr
178
+ return fmt.Errorf("failed to write interface expression in type assertion call: %w", err)
327
179
  }
180
+ c.tsw.WriteLiterally(", ")
181
+ c.writeTypeDescription(assertedType) // Arg2: type info for runtime
182
+ c.tsw.WriteLine("))")
328
183
 
329
- // Add params if present
330
- if typeExpr.Params != nil && len(typeExpr.Params.List) > 0 {
331
- c.tsw.WriteLiterally(", params: [")
332
- for i, param := range typeExpr.Params.List {
333
- if i > 0 {
334
- c.tsw.WriteLiterally(", ")
335
- }
336
- c.writeTypeDescription(param.Type)
337
- }
338
- c.tsw.WriteLiterally("]")
184
+ // Assign temporary value to the selector expression:
185
+ // s.f = _gs_ta_val_;
186
+ if err := c.WriteValueExpr(vLHS); err != nil { // Writes selector expression (e.g., "s.f")
187
+ return fmt.Errorf("failed to write LHS selector expression in type assertion: %w", err)
339
188
  }
189
+ c.tsw.WriteLiterally(" = ")
190
+ c.tsw.WriteLiterally(tempValName)
191
+ c.tsw.WriteLine("")
340
192
 
341
- // Add results if present
342
- if typeExpr.Results != nil && len(typeExpr.Results.List) > 0 {
343
- c.tsw.WriteLiterally(", results: [")
344
- for i, result := range typeExpr.Results.List {
345
- if i > 0 {
346
- c.tsw.WriteLiterally(", ")
347
- }
348
- c.writeTypeDescription(result.Type)
193
+ // Assign temporary ok to the ok variable (e.g., okName = _gs_ta_ok_; or let okName = ...)
194
+ if !okIsBlank {
195
+ if okIsNewInDefine { // okIsNewInDefine was determined earlier based on tok == token.DEFINE and Defs check
196
+ c.tsw.WriteLiterally("let ")
349
197
  }
350
- c.tsw.WriteLiterally("]")
198
+ c.tsw.WriteLiterally(okName)
199
+ c.tsw.WriteLiterally(" = ")
200
+ c.tsw.WriteLiterally(tempOkName)
201
+ c.tsw.WriteLine("")
351
202
  }
352
203
 
353
- c.tsw.WriteLiterally("}")
354
- case *ast.Ident:
355
- if isPrimitiveType(typeExpr.Name) {
356
- c.tsw.WriteLiterally("{")
357
- c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
358
-
359
- // Use TypeScript equivalent if available
360
- if tsType, ok := GoBuiltinToTypescript(typeExpr.Name); ok {
361
- c.tsw.WriteLiterallyf("name: '%s'", tsType) // TODO: use %q?
362
- } else {
363
- c.tsw.WriteLiterallyf("name: '%s'", typeExpr.Name)
364
- }
365
-
366
- c.tsw.WriteLiterally("}")
367
- } else {
368
- // Check if this is a named function type
369
- isFunctionType := false
370
- if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
371
- if named, ok := namedType.(*types.Named); ok {
372
- if _, ok := named.Underlying().(*types.Signature); ok {
373
- // This is a named function type, generate a FunctionTypeInfo
374
- isFunctionType = true
375
- c.tsw.WriteLiterally("{")
376
- c.tsw.WriteLiterally("kind: $.TypeKind.Function")
377
- c.tsw.WriteLiterallyf(", name: '%s'", typeExpr.Name)
378
-
379
- // Get the underlying signature
380
- signature := named.Underlying().(*types.Signature)
381
-
382
- // Add params if present
383
- params := signature.Params()
384
- if params != nil && params.Len() > 0 {
385
- c.tsw.WriteLiterally(", params: [")
386
- for i := 0; i < params.Len(); i++ {
387
- if i > 0 {
388
- c.tsw.WriteLiterally(", ")
389
- }
390
- // Use basic type info for parameters
391
- param := params.At(i)
392
- c.tsw.WriteLiterally("{")
393
- c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
394
-
395
- typeName := param.Type().String()
396
- if tsType, ok := GoBuiltinToTypescript(typeName); ok {
397
- c.tsw.WriteLiterallyf("name: '%s'", tsType)
398
- } else {
399
- c.tsw.WriteLiterallyf("name: '%s'", typeName)
400
- }
401
-
402
- c.tsw.WriteLiterally("}")
403
- }
404
- c.tsw.WriteLiterally("]")
405
- }
406
-
407
- // Add results if present
408
- results := signature.Results()
409
- if results != nil && results.Len() > 0 {
410
- c.tsw.WriteLiterally(", results: [")
411
- for i := 0; i < results.Len(); i++ {
412
- if i > 0 {
413
- c.tsw.WriteLiterally(", ")
414
- }
415
- result := results.At(i)
416
- c.tsw.WriteLiterally("{")
417
- c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
418
-
419
- typeName := result.Type().String()
420
- if tsType, ok := GoBuiltinToTypescript(typeName); ok {
421
- c.tsw.WriteLiterallyf("name: '%s'", tsType)
422
- } else {
423
- c.tsw.WriteLiterallyf("name: '%s'", typeName)
424
- }
425
-
426
- c.tsw.WriteLiterally("}")
427
- }
428
- c.tsw.WriteLiterally("]")
429
- }
430
-
431
- c.tsw.WriteLiterally("}")
432
- }
433
- }
434
- }
435
-
436
- // Default case for non-function named types
437
- if !isFunctionType {
438
- c.tsw.WriteLiterallyf("'%s'", typeExpr.Name)
439
- }
440
- }
441
- case *ast.SelectorExpr:
442
- // For imported types like pkg.Type
443
- if ident, ok := typeExpr.X.(*ast.Ident); ok {
444
- c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, typeExpr.Sel.Name)
445
- } else {
446
- c.tsw.WriteLiterallyf("'%s'", c.getTypeNameString(assertedType))
447
- }
448
204
  default:
449
- // For other types, use the string name as before
450
- typeName := c.getTypeNameString(assertedType)
451
- c.tsw.WriteLiterallyf("'%s'", typeName)
452
- }
453
-
454
- c.tsw.WriteLiterally(")")
455
-
456
- if tok != token.DEFINE || writeEndParen {
457
- c.tsw.WriteLiterally(")")
205
+ return fmt.Errorf("unhandled LHS expression type for value in type assertion: %T", valueExpr)
458
206
  }
459
207
 
460
- c.tsw.WriteLine("") // Add newline after the statement
461
-
462
208
  return nil
463
209
  }