goscript 0.0.58 → 0.0.59

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.
Files changed (44) hide show
  1. package/README.md +40 -33
  2. package/compiler/analysis.go +115 -19
  3. package/compiler/assignment.go +163 -217
  4. package/compiler/compiler.go +35 -31
  5. package/compiler/composite-lit.go +233 -196
  6. package/compiler/constraint.go +88 -0
  7. package/compiler/decl.go +82 -24
  8. package/compiler/expr-call-async.go +20 -34
  9. package/compiler/expr-call-builtins.go +19 -0
  10. package/compiler/expr-call-helpers.go +0 -28
  11. package/compiler/expr-call-make.go +93 -343
  12. package/compiler/expr-call-type-conversion.go +221 -249
  13. package/compiler/expr-call.go +70 -69
  14. package/compiler/expr-selector.go +21 -24
  15. package/compiler/expr.go +3 -60
  16. package/compiler/protobuf.go +180 -36
  17. package/compiler/spec-value.go +132 -24
  18. package/compiler/spec.go +14 -55
  19. package/compiler/stmt-assign.go +338 -356
  20. package/compiler/stmt-range.go +4 -24
  21. package/compiler/stmt.go +92 -203
  22. package/compiler/type-utils.go +185 -0
  23. package/compiler/type.go +26 -80
  24. package/dist/gs/builtin/slice.d.ts +1 -1
  25. package/dist/gs/builtin/slice.js +3 -0
  26. package/dist/gs/builtin/slice.js.map +1 -1
  27. package/dist/gs/builtin/type.js +8 -2
  28. package/dist/gs/builtin/type.js.map +1 -1
  29. package/dist/gs/fmt/fmt.js +113 -16
  30. package/dist/gs/fmt/fmt.js.map +1 -1
  31. package/dist/gs/runtime/runtime.d.ts +1 -1
  32. package/dist/gs/runtime/runtime.js +1 -1
  33. package/dist/gs/slices/slices.d.ts +23 -0
  34. package/dist/gs/slices/slices.js +61 -0
  35. package/dist/gs/slices/slices.js.map +1 -1
  36. package/go.mod +8 -8
  37. package/go.sum +14 -14
  38. package/gs/builtin/slice.ts +5 -2
  39. package/gs/builtin/type.ts +13 -6
  40. package/gs/fmt/fmt.test.ts +176 -0
  41. package/gs/fmt/fmt.ts +109 -18
  42. package/gs/runtime/runtime.ts +1 -1
  43. package/gs/slices/slices.ts +68 -0
  44. package/package.json +3 -3
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## What is GoScript?
11
11
 
12
- GoScript is a **Go to TypeScript compiler** that translates Go code to TypeScript at the AST level. Perfect for sharing algorithms and business logic between Go backends and TypeScript frontends.
12
+ GoScript is an experimental **Go to TypeScript compiler** that translates Go code to TypeScript at the AST level. The goal is to enable sharing algorithms and business logic between Go backends and TypeScript frontends.
13
13
 
14
14
  > Right now goscript looks pretty cool if you problem is "I want this self-sufficient algorithm be available in Go and JS runtimes". gopherjs's ambition, however, has always been "any valid Go program can run in a browser". There is a lot that goes on in gopherjs that is necessary for supporting the standard library, which goes beyond cross-language translation.
15
15
  >
@@ -17,33 +17,46 @@ GoScript is a **Go to TypeScript compiler** that translates Go code to TypeScrip
17
17
 
18
18
  ### 🎯 Why GoScript?
19
19
 
20
- **Write once, run everywhere.** Share your Go algorithms, business logic, and data structures seamlessly between your backend and frontend without maintaining two codebases.
20
+ Write once, run everywhere. Share your Go algorithms, business logic, and data structures seamlessly between your backend and frontend without maintaining two codebases.
21
21
 
22
- **Perfect for:**
22
+ 🔬 **Experimental features being developed:**
23
23
  - Sharing business logic between Go services and web apps
24
24
  - Porting Go algorithms to run in browsers
25
25
  - Building TypeScript libraries from existing Go code
26
- - Full-stack teams that love Go's simplicity
27
26
 
28
- ⚠️ **What's supported:**
29
- GoScript compiles a powerful subset of Go:
30
- - Structs, interfaces, methods, and functions
31
- - Channels and goroutines (translated to async/await)
32
- - Slices, maps, and most built-in types
33
- - Basic reflection support
34
- - Standard control flow (if, for, switch, etc.)
27
+ Go has powerful concurrency support and an excellent standard library. GoScript brings these capabilities to TypeScript with as simple and readable of a translation as possible.
35
28
 
36
- **Current limitations:**
29
+ ⚠️ **Current development status:**
30
+ GoScript is working on compiling a subset of Go:
31
+ - ✅ Basic structs, interfaces, methods, and functions
32
+ - ✅ Channels and goroutines (translating to async/await)
33
+ - ✅ Slice semantics, maps, and built-in types
34
+ - ✅ Standard control flow (if, for, switch, select, range, etc.)
35
+ - 🚧 Basic reflection support
36
+ - 🚧 Standard library support
37
+
38
+ **Known limitations in this preview:**
37
39
  - Uses JavaScript `number` type (64-bit float, not Go's int types)
38
40
  - No pointer arithmetic (`uintptr`) or `unsafe` package
39
41
  - No complex numbers
40
- - Limited standard library (growing rapidly)
42
+ - Limited standard library (working on it)
43
+ - Performance not yet optimized
44
+
45
+ **This is a prototype!** Expect bugs and missing features. Please contribute!
46
+
47
+ ### ⚠️ Development Preview
48
+
49
+ **This project is currently in active development and should be considered experimental.** GoScript is a work-in-progress prototype that may have bugs, incomplete features, and breaking changes. We're actively iterating on the compiler and welcome your feedback!
50
+
51
+ 🐛 **Found an issue?** Please [open an issue](https://github.com/aperturerobotics/goscript/issues) and we'll fix it.
41
52
 
42
- If you're building algorithms, business logic, or data processing code, GoScript has you covered! 🚀
53
+ 🤖 **AI** This prototype is heavily AI-written, but I plan to manually rewrite the codebase by hand once it reaches a working state for advanced use cases. AI Producer, human Reducer.
43
54
 
44
55
  📖 **Learn more:** [Design document](./design/DESIGN.md) | [Compliance tests](./compliance/COMPLIANCE.md)
45
56
 
46
- ## 🚀 Get Started in 2 Minutes
57
+ ## 🚀 Try It
58
+
59
+ > **Warning:** This is experimental software. Features may be incomplete or broken. Please report any issues!
47
60
 
48
61
  ### Installation
49
62
 
@@ -52,18 +65,20 @@ If you're building algorithms, business logic, or data processing code, GoScript
52
65
  go install github.com/aperturerobotics/goscript/cmd/goscript@latest
53
66
  ```
54
67
 
55
- **Option 2: NPM**
68
+ **Option 2: NPM** (if available)
56
69
  ```bash
57
70
  npm install -g goscript
58
71
  ```
59
72
 
60
- ### Your First Compilation
73
+ ### Compilation
61
74
 
62
75
  ```bash
63
- # Compile your Go package to TypeScript
76
+ # Try compiling your Go package to TypeScript
64
77
  goscript compile --package . --output ./dist
65
78
  ```
66
79
 
80
+ **Note:** Many Go packages may not compile successfully yet. Start with simple code and gradually test more complex features.
81
+
67
82
  ## 📦 Using Generated Code in Your Project
68
83
 
69
84
  After compiling your Go code to TypeScript, you'll need to set up your project appropriately.
@@ -168,6 +183,8 @@ const searchUser = (email: string) => {
168
183
 
169
184
  ## 💡 See It In Action
170
185
 
186
+ > **Disclaimer:** These examples represent the target functionality. Your mileage may vary with the current development preview.
187
+
171
188
  ### Example: User Management
172
189
 
173
190
  **Go Code** (`user.go`):
@@ -203,7 +220,7 @@ func FindUserByEmail(users []*User, email string) *User {
203
220
  goscript compile --package . --output ./dist
204
221
  ```
205
222
 
206
- **Generated TypeScript** (`user.ts`):
223
+ **Generated TypeScript** (`user.gs.ts`):
207
224
  ```typescript
208
225
  export class User {
209
226
  public ID: number = 0
@@ -298,21 +315,11 @@ async function handleMessages() {
298
315
  }
299
316
  ```
300
317
 
301
- ## 🚀 What's Next?
302
-
303
- **Current Status:**
304
- - ✅ Core language features (structs, methods, interfaces)
305
- - ✅ Async/await for goroutines and channels
306
- - ✅ Basic reflection support
307
- - ✅ Most control flow and data types
308
-
309
- **Coming Soon:**
310
- - 📦 Expanded standard library
311
- - 🧪 Go test → TypeScript test conversion
312
- - ⚡ Performance optimizations
313
- - 🔧 Better tooling integration
318
+ ## 🤝 How You Can Help
314
319
 
315
- Check the [compliance tests](./compliance/COMPLIANCE.md) for detailed progress.
320
+ - Try GoScript on your code and [report issues](https://github.com/aperturerobotics/goscript/issues)
321
+ - Check the [compliance tests](./compliance/COMPLIANCE.md) for current progress
322
+ - Contribute test cases for edge cases you discover
316
323
 
317
324
  ## License
318
325
 
@@ -641,6 +641,22 @@ func (v *analysisVisitor) visitFuncDecl(n *ast.FuncDecl) ast.Visitor {
641
641
  funcInfo := v.analysis.ensureFunctionData(obj)
642
642
  funcInfo.ReceiverUsed = receiverUsed
643
643
  }
644
+
645
+ // If receiver is used, mark all identifiers that refer to the receiver variable
646
+ if receiverUsed && n.Body != nil {
647
+ recvName := ident.Name
648
+ ast.Inspect(n.Body, func(nn ast.Node) bool {
649
+ id, ok := nn.(*ast.Ident)
650
+ if !ok {
651
+ return true
652
+ }
653
+ if obj := v.pkg.TypesInfo.Uses[id]; obj != nil && obj == vr {
654
+ ni := v.analysis.ensureNodeData(id)
655
+ ni.IdentifierMapping = recvName
656
+ }
657
+ return true
658
+ })
659
+ }
644
660
  }
645
661
  }
646
662
  }
@@ -759,9 +775,92 @@ func (v *analysisVisitor) visitCallExpr(n *ast.CallExpr) ast.Visitor {
759
775
  // Track interface implementations from function call arguments
760
776
  v.trackInterfaceCallArguments(n)
761
777
 
778
+ // Check for implicit address-taking in method calls with pointer receivers
779
+ v.checkImplicitAddressTaking(n)
780
+
762
781
  return v
763
782
  }
764
783
 
784
+ // checkImplicitAddressTaking detects when a method call with a pointer receiver
785
+ // is called on a non-pointer variable, which requires implicit address-taking.
786
+ // Example: var s MySlice; s.Add(10) where Add has receiver *MySlice
787
+ // This is equivalent to (&s).Add(10), so s needs to be marked as NeedsVarRef
788
+ func (v *analysisVisitor) checkImplicitAddressTaking(callExpr *ast.CallExpr) {
789
+ // Check if this is a method call (selector expression)
790
+ selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
791
+ if !ok {
792
+ return
793
+ }
794
+
795
+ // Get the selection information
796
+ selection := v.pkg.TypesInfo.Selections[selExpr]
797
+ if selection == nil || selection.Kind() != types.MethodVal {
798
+ return
799
+ }
800
+
801
+ // Get the method object
802
+ methodObj := selection.Obj()
803
+ if methodObj == nil {
804
+ return
805
+ }
806
+
807
+ // Get the method's signature to check the receiver type
808
+ methodFunc, ok := methodObj.(*types.Func)
809
+ if !ok {
810
+ return
811
+ }
812
+
813
+ sig := methodFunc.Type().(*types.Signature)
814
+ recv := sig.Recv()
815
+ if recv == nil {
816
+ return
817
+ }
818
+
819
+ // Check if the method has a pointer receiver
820
+ recvType := recv.Type()
821
+ _, hasPointerReceiver := recvType.(*types.Pointer)
822
+ if !hasPointerReceiver {
823
+ return
824
+ }
825
+
826
+ // Get the type of the receiver expression (the thing before the dot)
827
+ exprType := v.pkg.TypesInfo.TypeOf(selExpr.X)
828
+ if exprType == nil {
829
+ return
830
+ }
831
+
832
+ // Check if the receiver expression is NOT already a pointer
833
+ _, exprIsPointer := exprType.(*types.Pointer)
834
+ if exprIsPointer {
835
+ // Expression is already a pointer, no implicit address-taking needed
836
+ return
837
+ }
838
+
839
+ // At this point, we have:
840
+ // - A method with a pointer receiver
841
+ // - Being called on a non-pointer expression
842
+ // This means Go will implicitly take the address
843
+
844
+ // Check if the receiver expression is an identifier (variable)
845
+ ident, ok := selExpr.X.(*ast.Ident)
846
+ if !ok {
847
+ return
848
+ }
849
+
850
+ // Get the variable object
851
+ obj := v.pkg.TypesInfo.ObjectOf(ident)
852
+ if obj == nil {
853
+ return
854
+ }
855
+
856
+ // Mark this variable as needing VarRef (its address is being taken)
857
+ usageInfo := v.getOrCreateUsageInfo(obj)
858
+ usageInfo.Destinations = append(usageInfo.Destinations, AssignmentInfo{
859
+ Object: nil, // No specific destination for method calls
860
+ Type: AddressOfAssignment,
861
+ })
862
+ }
863
+
765
864
  // visitSelectorExpr handles selector expression analysis
766
865
  func (v *analysisVisitor) visitSelectorExpr(n *ast.SelectorExpr) ast.Visitor {
767
866
  // Check if this is a method value (method being used as a value, not called immediately)
@@ -2234,13 +2333,12 @@ func (v *analysisVisitor) analyzeMethodAsync(funcDecl *ast.FuncDecl, pkg *packag
2234
2333
  isExternalPackage := pkg.Types != v.pkg.Types && v.analysis.AllPackages[pkg.Types.Path()] == nil
2235
2334
 
2236
2335
  if isExternalPackage {
2237
- // Truly external package: check metadata first, fall back to body analysis
2336
+ // Truly external package: check metadata first
2238
2337
  isAsync = v.checkExternalMethodMetadata(methodKey.PackagePath, methodKey.ReceiverType, methodKey.MethodName)
2239
- } else {
2240
- // Local package or package being compiled: analyze method body
2241
- if funcDecl.Body != nil {
2242
- isAsync = v.containsAsyncOperationsComplete(funcDecl.Body, pkg)
2243
- }
2338
+ }
2339
+ // If not determined async yet and body exists, analyze it
2340
+ if !isAsync && funcDecl.Body != nil {
2341
+ isAsync = v.containsAsyncOperationsComplete(funcDecl.Body, pkg)
2244
2342
  }
2245
2343
 
2246
2344
  // Store result in MethodAsyncStatus
@@ -2459,21 +2557,19 @@ func (v *analysisVisitor) isMethodAsyncFromSelection(selExpr *ast.SelectorExpr,
2459
2557
  return status
2460
2558
  }
2461
2559
 
2462
- // Only try to analyze methods for packages that don't have metadata loaded
2463
- // If a package has metadata, we should rely solely on that metadata
2464
- if targetPkg := v.analysis.AllPackages[methodPkgPath]; targetPkg != nil {
2465
- // Check if this package has metadata loaded by checking if any method from this package
2466
- // exists in MethodAsyncStatus. If so, don't analyze - rely on metadata only.
2467
- hasMetadata := false
2468
- for key := range v.analysis.MethodAsyncStatus {
2469
- if key.PackagePath == methodPkgPath {
2470
- hasMetadata = true
2471
- break
2560
+ // Check if this is a method in the same package we're currently analyzing
2561
+ if methodPkgPath == v.pkg.Types.Path() {
2562
+ // This is a method in the same package - we should analyze it if we haven't yet
2563
+ if funcDecl := v.findMethodDecl(receiverType, methodObj.Name(), v.pkg); funcDecl != nil {
2564
+ v.analyzeMethodAsync(funcDecl, v.pkg)
2565
+ if status, exists := v.analysis.MethodAsyncStatus[methodKey]; exists {
2566
+ return status
2472
2567
  }
2473
2568
  }
2474
-
2475
- // Only analyze if no metadata exists for this package
2476
- if !hasMetadata {
2569
+ } else {
2570
+ // For methods in other packages that we're compiling together
2571
+ if targetPkg := v.analysis.AllPackages[methodPkgPath]; targetPkg != nil {
2572
+ // Try to analyze the method if we haven't already
2477
2573
  if funcDecl := v.findMethodDecl(receiverType, methodObj.Name(), targetPkg); funcDecl != nil {
2478
2574
  v.analyzeMethodAsync(funcDecl, targetPkg)
2479
2575
  if status, exists := v.analysis.MethodAsyncStatus[methodKey]; exists {