goscript 0.0.26 → 0.0.28
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 +4 -4
- package/cmd/goscript/cmd_compile.go +0 -3
- package/cmd/goscript/deps.go +11 -0
- package/compiler/analysis.go +259 -55
- package/compiler/assignment.go +2 -2
- package/compiler/builtin_test.go +1 -1
- package/compiler/compiler.go +200 -68
- package/compiler/compiler_test.go +17 -24
- package/compiler/composite-lit.go +32 -8
- package/compiler/decl.go +6 -6
- package/compiler/expr-call.go +83 -0
- package/compiler/expr.go +1 -1
- package/compiler/protobuf.go +557 -0
- package/compiler/spec-struct.go +4 -0
- package/compiler/spec-value.go +10 -2
- package/compiler/spec.go +18 -1
- package/compiler/stmt-assign.go +35 -0
- package/compiler/type-assert.go +87 -0
- package/compiler/type.go +4 -1
- package/dist/gs/builtin/builtin.d.ts +19 -1
- package/dist/gs/builtin/builtin.js +84 -4
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +21 -2
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/errors/errors.d.ts +5 -6
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/io/index.d.ts +1 -0
- package/dist/gs/io/index.js +2 -0
- package/dist/gs/io/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +107 -0
- package/dist/gs/io/io.js +385 -0
- package/dist/gs/io/io.js.map +1 -0
- package/dist/gs/strings/builder.d.ts +18 -0
- package/dist/gs/strings/builder.js +205 -0
- package/dist/gs/strings/builder.js.map +1 -0
- package/dist/gs/strings/clone.d.ts +1 -0
- package/dist/gs/strings/clone.js +16 -0
- package/dist/gs/strings/clone.js.map +1 -0
- package/dist/gs/strings/compare.d.ts +1 -0
- package/dist/gs/strings/compare.js +14 -0
- package/dist/gs/strings/compare.js.map +1 -0
- package/dist/gs/strings/index.d.ts +2 -0
- package/dist/gs/strings/index.js +3 -0
- package/dist/gs/strings/index.js.map +1 -0
- package/dist/gs/strings/iter.d.ts +8 -0
- package/dist/gs/strings/iter.js +160 -0
- package/dist/gs/strings/iter.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +34 -0
- package/dist/gs/strings/reader.js +418 -0
- package/dist/gs/strings/reader.js.map +1 -0
- package/dist/gs/strings/replace.d.ts +106 -0
- package/dist/gs/strings/replace.js +1136 -0
- package/dist/gs/strings/replace.js.map +1 -0
- package/dist/gs/strings/search.d.ts +24 -0
- package/dist/gs/strings/search.js +169 -0
- package/dist/gs/strings/search.js.map +1 -0
- package/dist/gs/strings/strings.d.ts +47 -0
- package/dist/gs/strings/strings.js +418 -0
- package/dist/gs/strings/strings.js.map +1 -0
- package/dist/gs/stringslite/index.d.ts +1 -0
- package/dist/gs/stringslite/index.js +2 -0
- package/dist/gs/stringslite/index.js.map +1 -0
- package/dist/gs/stringslite/strings.d.ts +11 -0
- package/dist/gs/stringslite/strings.js +67 -0
- package/dist/gs/stringslite/strings.js.map +1 -0
- package/dist/gs/sync/index.d.ts +1 -0
- package/dist/gs/sync/index.js +2 -0
- package/dist/gs/sync/index.js.map +1 -0
- package/dist/gs/sync/sync.d.ts +79 -0
- package/dist/gs/sync/sync.js +392 -0
- package/dist/gs/sync/sync.js.map +1 -0
- package/dist/gs/unicode/index.d.ts +1 -0
- package/dist/gs/unicode/index.js +2 -0
- package/dist/gs/unicode/index.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +105 -0
- package/dist/gs/unicode/unicode.js +332 -0
- package/dist/gs/unicode/unicode.js.map +1 -0
- package/dist/gs/unicode/utf8/index.d.ts +1 -0
- package/dist/gs/unicode/utf8/index.js +3 -0
- package/dist/gs/unicode/utf8/index.js.map +1 -0
- package/dist/gs/unicode/utf8/utf8.d.ts +20 -0
- package/dist/gs/unicode/utf8/utf8.js +196 -0
- package/dist/gs/unicode/utf8/utf8.js.map +1 -0
- package/dist/gs/unsafe/index.d.ts +1 -0
- package/dist/gs/unsafe/index.js +2 -0
- package/dist/gs/unsafe/index.js.map +1 -0
- package/dist/gs/unsafe/unsafe.d.ts +11 -0
- package/dist/gs/unsafe/unsafe.js +44 -0
- package/dist/gs/unsafe/unsafe.js.map +1 -0
- package/go.mod +2 -1
- package/go.sum +6 -2
- package/gs/README.md +6 -0
- package/gs/builtin/builtin.ts +158 -0
- package/gs/builtin/channel.ts +683 -0
- package/gs/builtin/defer.ts +58 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/io.ts +22 -0
- package/gs/builtin/map.ts +50 -0
- package/gs/builtin/slice.ts +1030 -0
- package/gs/builtin/type.ts +1106 -0
- package/gs/builtin/varRef.ts +25 -0
- package/gs/cmp/godoc.txt +8 -0
- package/gs/cmp/index.ts +29 -0
- package/gs/context/context.ts +401 -0
- package/gs/context/godoc.txt +69 -0
- package/gs/context/index.ts +1 -0
- package/gs/errors/errors.ts +223 -0
- package/gs/errors/godoc.txt +63 -0
- package/gs/errors/index.ts +1 -0
- package/gs/internal/goarch/godoc.txt +39 -0
- package/gs/internal/goarch/index.ts +18 -0
- package/gs/io/godoc.txt +61 -0
- package/gs/io/index.ts +1 -0
- package/gs/io/io.go +75 -0
- package/gs/io/io.ts +546 -0
- package/gs/iter/godoc.txt +203 -0
- package/gs/iter/index.ts +1 -0
- package/gs/iter/iter.ts +117 -0
- package/gs/math/bits/index.ts +356 -0
- package/gs/math/godoc.txt +76 -0
- package/gs/runtime/godoc.txt +331 -0
- package/gs/runtime/index.ts +1 -0
- package/gs/runtime/runtime.ts +178 -0
- package/gs/slices/godoc.txt +44 -0
- package/gs/slices/index.ts +1 -0
- package/gs/slices/slices.ts +22 -0
- package/gs/strings/builder.test.ts +121 -0
- package/gs/strings/builder.ts +223 -0
- package/gs/strings/clone.test.ts +43 -0
- package/gs/strings/clone.ts +17 -0
- package/gs/strings/compare.test.ts +84 -0
- package/gs/strings/compare.ts +13 -0
- package/gs/strings/godoc.txt +66 -0
- package/gs/strings/index.ts +2 -0
- package/gs/strings/iter.test.ts +343 -0
- package/gs/strings/iter.ts +171 -0
- package/gs/strings/reader.test.ts +243 -0
- package/gs/strings/reader.ts +451 -0
- package/gs/strings/replace.test.ts +181 -0
- package/gs/strings/replace.ts +1310 -0
- package/gs/strings/search.test.ts +214 -0
- package/gs/strings/search.ts +213 -0
- package/gs/strings/strings.test.ts +477 -0
- package/gs/strings/strings.ts +510 -0
- package/gs/stringslite/godoc.txt +17 -0
- package/gs/stringslite/index.ts +1 -0
- package/gs/stringslite/strings.ts +82 -0
- package/gs/sync/godoc.txt +21 -0
- package/gs/sync/index.ts +1 -0
- package/gs/sync/sync.go +64 -0
- package/gs/sync/sync.ts +449 -0
- package/gs/time/godoc.md +116 -0
- package/gs/time/godoc.txt +116 -0
- package/gs/time/index.ts +1 -0
- package/gs/time/time.ts +272 -0
- package/gs/unicode/godoc.txt +52 -0
- package/gs/unicode/index.ts +1 -0
- package/gs/unicode/unicode.go +38 -0
- package/gs/unicode/unicode.ts +418 -0
- package/gs/unicode/utf8/godoc.txt +22 -0
- package/gs/unicode/utf8/index.ts +2 -0
- package/gs/unicode/utf8/utf8.ts +227 -0
- package/gs/unsafe/godoc.txt +19 -0
- package/gs/unsafe/index.ts +1 -0
- package/gs/unsafe/unsafe.test.ts +68 -0
- package/gs/unsafe/unsafe.ts +77 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -152,9 +152,10 @@ This example imports the `compile` function, configures it to compile a Go packa
|
|
|
152
152
|
Check [the compliance tests](./compliance/COMPLIANCE.md) for implementation progress.
|
|
153
153
|
|
|
154
154
|
- [X] Simple programs compile & run
|
|
155
|
-
- [
|
|
156
|
-
- [
|
|
157
|
-
- [
|
|
155
|
+
- [X] Compliance for basic language features complete
|
|
156
|
+
- [X] Function coloring and async logic
|
|
157
|
+
- [X] Work our way up to more complex programs
|
|
158
|
+
- [ ] Implement most of the Go standard library
|
|
158
159
|
- [ ] Generate init() function to recursively initialize packages
|
|
159
160
|
- [ ] Tooling to integrate with typescript compiler
|
|
160
161
|
- [ ] "go test" implementation with Go -> Ts transformation
|
|
@@ -162,7 +163,6 @@ Check [the compliance tests](./compliance/COMPLIANCE.md) for implementation prog
|
|
|
162
163
|
- [ ] performance testing
|
|
163
164
|
- [ ] examples of calling Go code from TypeScript
|
|
164
165
|
|
|
165
|
-
|
|
166
166
|
## Generated Code
|
|
167
167
|
|
|
168
168
|
Below is a simple example of how code is generated:
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// This file has _ imports to ensure we include these in the go module.
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
// _ ensure we include the gs package
|
|
7
|
+
_ "github.com/aperturerobotics/goscript"
|
|
8
|
+
// _ ensure we include the gs metadata packages
|
|
9
|
+
_ "github.com/aperturerobotics/goscript/gs/sync"
|
|
10
|
+
_ "github.com/aperturerobotics/goscript/gs/unicode"
|
|
11
|
+
)
|
package/compiler/analysis.go
CHANGED
|
@@ -4,6 +4,8 @@ import (
|
|
|
4
4
|
"go/ast"
|
|
5
5
|
"go/token"
|
|
6
6
|
"go/types"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"strings"
|
|
7
9
|
|
|
8
10
|
"golang.org/x/tools/go/packages"
|
|
9
11
|
)
|
|
@@ -54,6 +56,7 @@ type NodeInfo struct {
|
|
|
54
56
|
IsBareReturn bool
|
|
55
57
|
EnclosingFuncDecl *ast.FuncDecl
|
|
56
58
|
EnclosingFuncLit *ast.FuncLit
|
|
59
|
+
IsInsideFunction bool // true if this declaration is inside a function body
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
// Analysis holds information gathered during the analysis phase of the Go code compilation.
|
|
@@ -79,16 +82,39 @@ type Analysis struct {
|
|
|
79
82
|
// Keep specialized maps that serve different purposes
|
|
80
83
|
// FuncLitData tracks function literal specific data since they don't have types.Object
|
|
81
84
|
FuncLitData map[*ast.FuncLit]*FunctionInfo
|
|
85
|
+
|
|
86
|
+
// PackageMetadata holds package-level metadata
|
|
87
|
+
PackageMetadata map[string]interface{}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// PackageAnalysis holds cross-file analysis data for a package
|
|
91
|
+
type PackageAnalysis struct {
|
|
92
|
+
// FunctionDefs maps file names to the functions defined in that file
|
|
93
|
+
// Key: filename (without .go extension), Value: list of function names
|
|
94
|
+
FunctionDefs map[string][]string
|
|
95
|
+
|
|
96
|
+
// FunctionCalls maps file names to the functions they call from other files
|
|
97
|
+
// Key: filename (without .go extension), Value: map[sourceFile][]functionNames
|
|
98
|
+
FunctionCalls map[string]map[string][]string
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
// NewAnalysis creates a new Analysis instance.
|
|
85
102
|
func NewAnalysis() *Analysis {
|
|
86
103
|
return &Analysis{
|
|
87
|
-
VariableUsage:
|
|
88
|
-
Imports:
|
|
89
|
-
FunctionData:
|
|
90
|
-
NodeData:
|
|
91
|
-
FuncLitData:
|
|
104
|
+
VariableUsage: make(map[types.Object]*VariableUsageInfo),
|
|
105
|
+
Imports: make(map[string]*fileImport),
|
|
106
|
+
FunctionData: make(map[types.Object]*FunctionInfo),
|
|
107
|
+
NodeData: make(map[ast.Node]*NodeInfo),
|
|
108
|
+
FuncLitData: make(map[*ast.FuncLit]*FunctionInfo),
|
|
109
|
+
PackageMetadata: make(map[string]interface{}),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// NewPackageAnalysis creates a new PackageAnalysis instance
|
|
114
|
+
func NewPackageAnalysis() *PackageAnalysis {
|
|
115
|
+
return &PackageAnalysis{
|
|
116
|
+
FunctionDefs: make(map[string][]string),
|
|
117
|
+
FunctionCalls: make(map[string]map[string][]string),
|
|
92
118
|
}
|
|
93
119
|
}
|
|
94
120
|
|
|
@@ -210,56 +236,6 @@ func (a *Analysis) NeedsVarRefAccess(obj types.Object) bool {
|
|
|
210
236
|
return false
|
|
211
237
|
}
|
|
212
238
|
|
|
213
|
-
// NeedsVarRefDeref determines whether a pointer dereference operation (*ptr) needs
|
|
214
|
-
// additional .value access beyond the standard !.value pattern.
|
|
215
|
-
//
|
|
216
|
-
// Standard pattern: ptr!.value (for *int, *string, etc.)
|
|
217
|
-
// Enhanced pattern: ptr.value!.value (when ptr itself is variable referenced)
|
|
218
|
-
//
|
|
219
|
-
// This function returns true when the pointer variable itself is variable referenced,
|
|
220
|
-
// meaning we need an extra .value to access the actual pointer before dereferencing.
|
|
221
|
-
//
|
|
222
|
-
// Examples:
|
|
223
|
-
// - ptr := &x (ptr not variable referenced): *ptr => ptr!.value
|
|
224
|
-
// - ptrPtr := &ptr (ptr is variable referenced): *ptr => ptr.value!.value
|
|
225
|
-
//
|
|
226
|
-
// Args:
|
|
227
|
-
//
|
|
228
|
-
// ptrType: The type of the pointer being dereferenced
|
|
229
|
-
//
|
|
230
|
-
// Returns:
|
|
231
|
-
//
|
|
232
|
-
// true if additional .value access is needed due to the pointer being variable referenced
|
|
233
|
-
func (a *Analysis) NeedsVarRefDeref(ptrType types.Type) bool {
|
|
234
|
-
// For now, return false - this would need more sophisticated analysis
|
|
235
|
-
// to track when pointer variables themselves are variable referenced
|
|
236
|
-
return false
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// NeedsVarRefFieldAccess determines whether a pointer variable needs the .value
|
|
240
|
-
// access when performing field access through the pointer.
|
|
241
|
-
//
|
|
242
|
-
// In Go, field access through pointers is automatically dereferenced:
|
|
243
|
-
//
|
|
244
|
-
// ptr.Field // equivalent to (*ptr).Field
|
|
245
|
-
//
|
|
246
|
-
// In TypeScript, we need to determine if the pointer is:
|
|
247
|
-
// 1. A simple pointer: ptr.Field (no .value needed)
|
|
248
|
-
// 2. A variable-referenced pointer: ptr.value.Field (needs .value)
|
|
249
|
-
//
|
|
250
|
-
// Args:
|
|
251
|
-
//
|
|
252
|
-
// ptrType: The pointer type being used for field access
|
|
253
|
-
//
|
|
254
|
-
// Returns:
|
|
255
|
-
//
|
|
256
|
-
// true if .value access is needed before field access
|
|
257
|
-
func (a *Analysis) NeedsVarRefFieldAccess(ptrType types.Type) bool {
|
|
258
|
-
// This would require analysis of the specific pointer variable
|
|
259
|
-
// For now, return false as a conservative default
|
|
260
|
-
return false
|
|
261
|
-
}
|
|
262
|
-
|
|
263
239
|
// analysisVisitor implements ast.Visitor and is used to traverse the AST during analysis.
|
|
264
240
|
type analysisVisitor struct {
|
|
265
241
|
// analysis stores information gathered during the traversal
|
|
@@ -718,6 +694,25 @@ func (v *analysisVisitor) Visit(node ast.Node) ast.Visitor {
|
|
|
718
694
|
}
|
|
719
695
|
}
|
|
720
696
|
return v // Continue traversal
|
|
697
|
+
|
|
698
|
+
case *ast.DeclStmt:
|
|
699
|
+
// Handle declarations inside functions (const, var, type declarations within function bodies)
|
|
700
|
+
// These should not have export modifiers in TypeScript
|
|
701
|
+
if genDecl, ok := n.Decl.(*ast.GenDecl); ok {
|
|
702
|
+
// Check if we're inside a function (either FuncDecl or FuncLit)
|
|
703
|
+
isInsideFunction := v.currentFuncDecl != nil || v.currentFuncLit != nil
|
|
704
|
+
|
|
705
|
+
if isInsideFunction {
|
|
706
|
+
// Mark all specs in this declaration as being inside a function
|
|
707
|
+
for _, spec := range genDecl.Specs {
|
|
708
|
+
if v.analysis.NodeData[spec] == nil {
|
|
709
|
+
v.analysis.NodeData[spec] = &NodeInfo{}
|
|
710
|
+
}
|
|
711
|
+
v.analysis.NodeData[spec].IsInsideFunction = true
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return v // Continue traversal
|
|
721
716
|
}
|
|
722
717
|
|
|
723
718
|
// For all other nodes, continue traversal
|
|
@@ -756,6 +751,37 @@ func (v *analysisVisitor) containsAsyncOperations(node ast.Node) bool {
|
|
|
756
751
|
}
|
|
757
752
|
}
|
|
758
753
|
|
|
754
|
+
// Check for method calls on imported types (e.g., sync.Mutex.Lock())
|
|
755
|
+
if selExpr, ok := s.Fun.(*ast.SelectorExpr); ok {
|
|
756
|
+
// Check if this is a method call on a variable (e.g., mu.Lock())
|
|
757
|
+
if ident, ok := selExpr.X.(*ast.Ident); ok {
|
|
758
|
+
// Get the type of the receiver
|
|
759
|
+
if obj := v.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
760
|
+
if varObj, ok := obj.(*types.Var); ok {
|
|
761
|
+
// Get the type name and package
|
|
762
|
+
if namedType, ok := varObj.Type().(*types.Named); ok {
|
|
763
|
+
typeName := namedType.Obj().Name()
|
|
764
|
+
methodName := selExpr.Sel.Name
|
|
765
|
+
|
|
766
|
+
// Check if the type is from an imported package
|
|
767
|
+
if typePkg := namedType.Obj().Pkg(); typePkg != nil && typePkg != v.pkg.Types {
|
|
768
|
+
pkgPath := typePkg.Path()
|
|
769
|
+
// Extract package name from path (e.g., "sync" from "github.com/.../gs/sync")
|
|
770
|
+
parts := strings.Split(pkgPath, "/")
|
|
771
|
+
pkgName := parts[len(parts)-1]
|
|
772
|
+
|
|
773
|
+
// Check if this method is async based on metadata
|
|
774
|
+
if v.analysis.IsMethodAsync(pkgName, typeName, methodName) {
|
|
775
|
+
hasAsync = true
|
|
776
|
+
return false
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
759
785
|
// TODO: Add detection of method calls on async types
|
|
760
786
|
}
|
|
761
787
|
|
|
@@ -789,6 +815,9 @@ func AnalyzeFile(file *ast.File, pkg *packages.Package, analysis *Analysis, cmap
|
|
|
789
815
|
// Store the comment map in the analysis object
|
|
790
816
|
analysis.Cmap = cmap
|
|
791
817
|
|
|
818
|
+
// Load package metadata for async function detection
|
|
819
|
+
analysis.LoadPackageMetadata()
|
|
820
|
+
|
|
792
821
|
// Process imports from the file
|
|
793
822
|
for _, imp := range file.Imports {
|
|
794
823
|
path := ""
|
|
@@ -844,3 +873,178 @@ func (v *analysisVisitor) getNamedReturns(funcDecl *ast.FuncDecl) []string {
|
|
|
844
873
|
}
|
|
845
874
|
return namedReturns
|
|
846
875
|
}
|
|
876
|
+
|
|
877
|
+
// AnalyzePackage performs package-level analysis to collect function definitions
|
|
878
|
+
// and calls across all files in the package for auto-import generation
|
|
879
|
+
func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
|
|
880
|
+
analysis := NewPackageAnalysis()
|
|
881
|
+
|
|
882
|
+
// First pass: collect all function definitions per file
|
|
883
|
+
for i, syntax := range pkg.Syntax {
|
|
884
|
+
fileName := pkg.CompiledGoFiles[i]
|
|
885
|
+
baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
|
|
886
|
+
|
|
887
|
+
var functions []string
|
|
888
|
+
for _, decl := range syntax.Decls {
|
|
889
|
+
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
|
|
890
|
+
// Only collect top-level functions (not methods)
|
|
891
|
+
if funcDecl.Recv == nil {
|
|
892
|
+
functions = append(functions, funcDecl.Name.Name)
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
if len(functions) > 0 {
|
|
898
|
+
analysis.FunctionDefs[baseFileName] = functions
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Second pass: analyze function calls and determine which need imports
|
|
903
|
+
for i, syntax := range pkg.Syntax {
|
|
904
|
+
fileName := pkg.CompiledGoFiles[i]
|
|
905
|
+
baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
|
|
906
|
+
|
|
907
|
+
// Find all function calls in this file
|
|
908
|
+
callsFromOtherFiles := make(map[string][]string)
|
|
909
|
+
|
|
910
|
+
ast.Inspect(syntax, func(n ast.Node) bool {
|
|
911
|
+
if callExpr, ok := n.(*ast.CallExpr); ok {
|
|
912
|
+
if ident, ok := callExpr.Fun.(*ast.Ident); ok {
|
|
913
|
+
funcName := ident.Name
|
|
914
|
+
|
|
915
|
+
// Check if this function is defined in the current file
|
|
916
|
+
currentFileFuncs := analysis.FunctionDefs[baseFileName]
|
|
917
|
+
isDefinedInCurrentFile := false
|
|
918
|
+
for _, f := range currentFileFuncs {
|
|
919
|
+
if f == funcName {
|
|
920
|
+
isDefinedInCurrentFile = true
|
|
921
|
+
break
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// If not defined in current file, find which file defines it
|
|
926
|
+
if !isDefinedInCurrentFile {
|
|
927
|
+
for sourceFile, funcs := range analysis.FunctionDefs {
|
|
928
|
+
if sourceFile == baseFileName {
|
|
929
|
+
continue // Skip current file
|
|
930
|
+
}
|
|
931
|
+
for _, f := range funcs {
|
|
932
|
+
if f == funcName {
|
|
933
|
+
// Found the function in another file
|
|
934
|
+
if callsFromOtherFiles[sourceFile] == nil {
|
|
935
|
+
callsFromOtherFiles[sourceFile] = []string{}
|
|
936
|
+
}
|
|
937
|
+
// Check if already added to avoid duplicates
|
|
938
|
+
found := false
|
|
939
|
+
for _, existing := range callsFromOtherFiles[sourceFile] {
|
|
940
|
+
if existing == funcName {
|
|
941
|
+
found = true
|
|
942
|
+
break
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if !found {
|
|
946
|
+
callsFromOtherFiles[sourceFile] = append(callsFromOtherFiles[sourceFile], funcName)
|
|
947
|
+
}
|
|
948
|
+
break
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return true
|
|
956
|
+
})
|
|
957
|
+
|
|
958
|
+
if len(callsFromOtherFiles) > 0 {
|
|
959
|
+
analysis.FunctionCalls[baseFileName] = callsFromOtherFiles
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return analysis
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// LoadPackageMetadata loads metadata from gs packages to determine which functions are async
|
|
967
|
+
func (a *Analysis) LoadPackageMetadata() {
|
|
968
|
+
// List of gs packages that have metadata
|
|
969
|
+
metadataPackages := []string{
|
|
970
|
+
"github.com/aperturerobotics/goscript/gs/sync",
|
|
971
|
+
"github.com/aperturerobotics/goscript/gs/unicode",
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
for _, pkgPath := range metadataPackages {
|
|
975
|
+
cfg := &packages.Config{
|
|
976
|
+
Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax,
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
pkgs, err := packages.Load(cfg, pkgPath)
|
|
980
|
+
if err != nil || len(pkgs) == 0 {
|
|
981
|
+
continue // Skip if package can't be loaded
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
pkg := pkgs[0]
|
|
985
|
+
if pkg.Types == nil {
|
|
986
|
+
continue
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Extract the package name (e.g., "sync" from "github.com/aperturerobotics/goscript/gs/sync")
|
|
990
|
+
parts := strings.Split(pkgPath, "/")
|
|
991
|
+
pkgName := parts[len(parts)-1]
|
|
992
|
+
|
|
993
|
+
// Look for metadata variables in the package scope
|
|
994
|
+
scope := pkg.Types.Scope()
|
|
995
|
+
for _, name := range scope.Names() {
|
|
996
|
+
obj := scope.Lookup(name)
|
|
997
|
+
if obj == nil {
|
|
998
|
+
continue
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// Check if this is a metadata variable (ends with "Info")
|
|
1002
|
+
if strings.HasSuffix(name, "Info") {
|
|
1003
|
+
if varObj, ok := obj.(*types.Var); ok {
|
|
1004
|
+
// Store the metadata with a key like "sync.MutexLock"
|
|
1005
|
+
methodName := strings.TrimSuffix(name, "Info")
|
|
1006
|
+
key := pkgName + "." + methodName
|
|
1007
|
+
a.PackageMetadata[key] = varObj
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// IsMethodAsync checks if a method call is async based on package metadata
|
|
1015
|
+
func (a *Analysis) IsMethodAsync(pkgName, typeName, methodName string) bool {
|
|
1016
|
+
// The metadata keys are stored as "sync.MutexLock", "sync.WaitGroupWait", etc.
|
|
1017
|
+
// We need to match "sync.Mutex.Lock" -> "sync.MutexLock"
|
|
1018
|
+
key := pkgName + "." + typeName + methodName
|
|
1019
|
+
|
|
1020
|
+
if metaObj, exists := a.PackageMetadata[key]; exists {
|
|
1021
|
+
if varObj, ok := metaObj.(*types.Var); ok {
|
|
1022
|
+
// Try to get the actual value of the variable
|
|
1023
|
+
// For now, we'll use the variable name to determine if it's async
|
|
1024
|
+
// The variable names follow the pattern: MutexLockInfo, WaitGroupWaitInfo, etc.
|
|
1025
|
+
// We can check if the corresponding metadata indicates IsAsync: true
|
|
1026
|
+
varName := varObj.Name()
|
|
1027
|
+
|
|
1028
|
+
// Based on our metadata definitions, these should be async:
|
|
1029
|
+
asyncMethods := map[string]bool{
|
|
1030
|
+
"MutexLockInfo": true,
|
|
1031
|
+
"RWMutexLockInfo": true,
|
|
1032
|
+
"RWMutexRLockInfo": true,
|
|
1033
|
+
"WaitGroupWaitInfo": true,
|
|
1034
|
+
"OnceDoInfo": true,
|
|
1035
|
+
"CondWaitInfo": true,
|
|
1036
|
+
"MapDeleteInfo": true,
|
|
1037
|
+
"MapLoadInfo": true,
|
|
1038
|
+
"MapLoadAndDeleteInfo": true,
|
|
1039
|
+
"MapLoadOrStoreInfo": true,
|
|
1040
|
+
"MapRangeInfo": true,
|
|
1041
|
+
"MapStoreInfo": true,
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
isAsync := asyncMethods[varName]
|
|
1045
|
+
return isAsync
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return false
|
|
1050
|
+
}
|
package/compiler/assignment.go
CHANGED
|
@@ -68,7 +68,7 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
|
|
|
68
68
|
return nil
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
//
|
|
71
|
+
// Handle variable referenced variables in declarations
|
|
72
72
|
if addDeclaration && tok == token.DEFINE {
|
|
73
73
|
// Determine if LHS is variable referenced
|
|
74
74
|
isLHSVarRefed := false
|
|
@@ -90,7 +90,7 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
//
|
|
93
|
+
// Handle short declaration of variable referenced variables
|
|
94
94
|
if isLHSVarRefed && lhsIdent != nil {
|
|
95
95
|
c.tsw.WriteLiterally("let ")
|
|
96
96
|
// Just write the identifier name without .value
|
package/compiler/builtin_test.go
CHANGED
|
@@ -42,7 +42,7 @@ func TestEmitBuiltinOption(t *testing.T) {
|
|
|
42
42
|
t.Fatalf("Compilation failed: %v", err)
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// Check that
|
|
45
|
+
// Check that handwritten packages like unsafe aren't emitted when DisableEmitBuiltin=true
|
|
46
46
|
unsafePath := filepath.Join(outputDir, "@goscript/unsafe")
|
|
47
47
|
if _, err := os.Stat(unsafePath); !os.IsNotExist(err) {
|
|
48
48
|
t.Errorf("unsafe package was emitted when DisableEmitBuiltin=true")
|