goscript 0.0.2
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/.aider-prompt +11 -0
- package/LICENSE +21 -0
- package/README.md +427 -0
- package/builtin/builtin.ts +507 -0
- package/cmd/goscript/cmd_compile.go +59 -0
- package/cmd/goscript/main.go +23 -0
- package/compiler/compile.go +183 -0
- package/compiler/compile_comment.go +41 -0
- package/compiler/compile_decls.go +72 -0
- package/compiler/compile_expr.go +831 -0
- package/compiler/compile_field.go +89 -0
- package/compiler/compile_spec.go +256 -0
- package/compiler/compile_stmt.go +1509 -0
- package/compiler/compiler.go +81 -0
- package/compiler/config.go +32 -0
- package/compiler/context.go +9 -0
- package/compiler/file_compiler.go +80 -0
- package/compiler/output_path.go +31 -0
- package/compiler/pkg_compiler.go +73 -0
- package/compiler/writer.go +90 -0
- package/compliance/COMPLIANCE.md +133 -0
- package/compliance/compliance.go +313 -0
- package/compliance/compliance_test.go +57 -0
- package/compliance/tests/array_literal/array_literal.go +15 -0
- package/compliance/tests/array_literal/array_literal.gs.ts +19 -0
- package/compliance/tests/array_literal/expected.log +3 -0
- package/compliance/tests/async_basic/async_basic.go +26 -0
- package/compliance/tests/async_basic/async_basic.gs.ts +30 -0
- package/compliance/tests/async_basic/expected.log +1 -0
- package/compliance/tests/basic_arithmetic/basic_arithmetic.go +15 -0
- package/compliance/tests/basic_arithmetic/basic_arithmetic.gs.ts +19 -0
- package/compliance/tests/basic_arithmetic/expected.log +5 -0
- package/compliance/tests/boolean_logic/boolean_logic.go +13 -0
- package/compliance/tests/boolean_logic/boolean_logic.gs.ts +17 -0
- package/compliance/tests/boolean_logic/expected.log +3 -0
- package/compliance/tests/channel_basic/channel_basic.go +12 -0
- package/compliance/tests/channel_basic/channel_basic.gs.ts +18 -0
- package/compliance/tests/channel_basic/expected.log +1 -0
- package/compliance/tests/composite_literal_assignment/composite_literal_assignment.go +20 -0
- package/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.ts +27 -0
- package/compliance/tests/composite_literal_assignment/expected.log +2 -0
- package/compliance/tests/constants/constants.go +18 -0
- package/compliance/tests/constants/constants.gs.ts +22 -0
- package/compliance/tests/constants/expected.log +3 -0
- package/compliance/tests/copy_independence/copy_independence.go +29 -0
- package/compliance/tests/copy_independence/copy_independence.gs.ts +36 -0
- package/compliance/tests/copy_independence/expected.log +4 -0
- package/compliance/tests/float64/expected.log +6 -0
- package/compliance/tests/float64/float64.go +28 -0
- package/compliance/tests/float64/float64.gs.ts +32 -0
- package/compliance/tests/for_loop_basic/expected.log +5 -0
- package/compliance/tests/for_loop_basic/for_loop_basic.go +9 -0
- package/compliance/tests/for_loop_basic/for_loop_basic.gs.ts +13 -0
- package/compliance/tests/for_loop_condition_only/expected.log +5 -0
- package/compliance/tests/for_loop_condition_only/main.go +9 -0
- package/compliance/tests/for_loop_condition_only/main.gs.ts +13 -0
- package/compliance/tests/for_range/expected.log +9 -0
- package/compliance/tests/for_range/for_range.go +26 -0
- package/compliance/tests/for_range/for_range.gs.ts +45 -0
- package/compliance/tests/for_range_index_use/expected.log +6 -0
- package/compliance/tests/for_range_index_use/for_range_index_use.go +11 -0
- package/compliance/tests/for_range_index_use/for_range_index_use.gs.ts +18 -0
- package/compliance/tests/func_literal/expected.log +1 -0
- package/compliance/tests/func_literal/func_literal.go +10 -0
- package/compliance/tests/func_literal/func_literal.gs.ts +15 -0
- package/compliance/tests/function_call_result_assignment/expected.log +2 -0
- package/compliance/tests/function_call_result_assignment/function_call_result_assignment.go +24 -0
- package/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.ts +31 -0
- package/compliance/tests/if_statement/expected.log +1 -0
- package/compliance/tests/if_statement/if_statement.go +11 -0
- package/compliance/tests/if_statement/if_statement.gs.ts +15 -0
- package/compliance/tests/interface_to_interface_type_assertion/expected.log +1 -0
- package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.go +30 -0
- package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.ts +41 -0
- package/compliance/tests/interface_type_assertion/expected.log +1 -0
- package/compliance/tests/interface_type_assertion/interface_type_assertion.go +26 -0
- package/compliance/tests/interface_type_assertion/interface_type_assertion.gs.ts +36 -0
- package/compliance/tests/map_support/expected.log +13 -0
- package/compliance/tests/map_support/map_support.go +89 -0
- package/compliance/tests/map_support/map_support.gs.ts +102 -0
- package/compliance/tests/method_call_on_pointer_receiver/expected.log +1 -0
- package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.go +19 -0
- package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.ts +27 -0
- package/compliance/tests/method_call_on_pointer_via_value/expected.log +1 -0
- package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.go +29 -0
- package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.ts +38 -0
- package/compliance/tests/method_call_on_value_receiver/expected.log +1 -0
- package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.go +16 -0
- package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.ts +24 -0
- package/compliance/tests/method_call_on_value_via_pointer/expected.log +2 -0
- package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.go +30 -0
- package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.ts +38 -0
- package/compliance/tests/multiple_return_values/expected.log +6 -0
- package/compliance/tests/multiple_return_values/multiple_return_values.go +19 -0
- package/compliance/tests/multiple_return_values/multiple_return_values.gs.ts +23 -0
- package/compliance/tests/pointer_assignment_no_copy/expected.log +2 -0
- package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.go +28 -0
- package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.ts +35 -0
- package/compliance/tests/pointer_composite_literal_assignment/expected.log +3 -0
- package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.go +23 -0
- package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.ts +30 -0
- package/compliance/tests/pointer_deref_multiassign/expected.log +0 -0
- package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.go +17 -0
- package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.ts +27 -0
- package/compliance/tests/pointer_initialization/expected.log +1 -0
- package/compliance/tests/pointer_initialization/pointer_initialization.go +16 -0
- package/compliance/tests/pointer_initialization/pointer_initialization.gs.ts +22 -0
- package/compliance/tests/select_receive_on_closed_channel_no_default/expected.log +1 -0
- package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.go +15 -0
- package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.ts +31 -0
- package/compliance/tests/select_send_on_full_buffered_channel_with_default/expected.log +1 -0
- package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.go +13 -0
- package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.ts +35 -0
- package/compliance/tests/select_statement/expected.log +9 -0
- package/compliance/tests/select_statement/select_statement.go +109 -0
- package/compliance/tests/select_statement/select_statement.gs.ts +239 -0
- package/compliance/tests/simple/expected.log +1 -0
- package/compliance/tests/simple/simple.go +5 -0
- package/compliance/tests/simple/simple.gs.ts +9 -0
- package/compliance/tests/simple_deref_assignment/expected.log +2 -0
- package/compliance/tests/simple_deref_assignment/simple_deref_assignment.go +19 -0
- package/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.ts +26 -0
- package/compliance/tests/slices/expected.log +7 -0
- package/compliance/tests/slices/slices.go +22 -0
- package/compliance/tests/slices/slices.gs.ts +26 -0
- package/compliance/tests/string_rune_conversion/expected.log +3 -0
- package/compliance/tests/string_rune_conversion/string_rune_conversion.go +16 -0
- package/compliance/tests/string_rune_conversion/string_rune_conversion.gs.ts +22 -0
- package/compliance/tests/struct_field_access/expected.log +2 -0
- package/compliance/tests/struct_field_access/struct_field_access.go +13 -0
- package/compliance/tests/struct_field_access/struct_field_access.gs.ts +20 -0
- package/compliance/tests/struct_value_init_clone/expected.log +5 -0
- package/compliance/tests/struct_value_init_clone/struct_value_init_clone.go +28 -0
- package/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.ts +35 -0
- package/compliance/tests/switch_statement/expected.log +14 -0
- package/compliance/tests/switch_statement/switch_statement.go +59 -0
- package/compliance/tests/switch_statement/switch_statement.gs.ts +85 -0
- package/compliance/tests/value_type_copy_behavior/expected.log +3 -0
- package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.go +25 -0
- package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.ts +34 -0
- package/design/DESIGN.md +599 -0
- package/example/simple/build.bash +10 -0
- package/example/simple/go.mod +23 -0
- package/example/simple/go.sum +39 -0
- package/example/simple/main.go +138 -0
- package/example/simple/main.gs.ts +133 -0
- package/example/simple/main.ts +3 -0
- package/example/simple/main_test.go +59 -0
- package/example/simple/main_tools.go +5 -0
- package/example/simple/package.json +7 -0
- package/example/simple/run.bash +6 -0
- package/example/simple/tsconfig.json +28 -0
- package/example/simple/yarn.lock +8 -0
- package/go.mod +22 -0
- package/go.sum +39 -0
- package/output/output.go +10 -0
- package/package.json +14 -0
- package/tsconfig.json +10 -0
- package/types/tokens.go +65 -0
- package/types/types.go +46 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
|
|
7
|
+
"github.com/sirupsen/logrus"
|
|
8
|
+
"golang.org/x/tools/go/packages"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// Compiler is the root compiler for a project.
|
|
12
|
+
type Compiler struct {
|
|
13
|
+
le *logrus.Entry
|
|
14
|
+
config Config
|
|
15
|
+
opts packages.Config
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// NewCompiler builds a new Compiler
|
|
19
|
+
// opts can be nil
|
|
20
|
+
func NewCompiler(conf *Config, le *logrus.Entry, opts *packages.Config) (*Compiler, error) {
|
|
21
|
+
if err := conf.Validate(); err != nil {
|
|
22
|
+
return nil, err
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if opts == nil {
|
|
26
|
+
opts = &packages.Config{Env: os.Environ()}
|
|
27
|
+
}
|
|
28
|
+
// opts.Logf = c.le.Debugf
|
|
29
|
+
opts.Tests = false
|
|
30
|
+
opts.Env = append(opts.Env, "GOOS=js", "GOARCH=wasm")
|
|
31
|
+
opts.Dir = conf.Dir
|
|
32
|
+
|
|
33
|
+
// NeedName adds Name and PkgPath.
|
|
34
|
+
// NeedFiles adds GoFiles and OtherFiles.
|
|
35
|
+
// NeedCompiledGoFiles adds CompiledGoFiles.
|
|
36
|
+
// NeedImports adds Imports. If NeedDeps is not set, the Imports field will contain
|
|
37
|
+
// "placeholder" Packages with only the ID set.
|
|
38
|
+
// NeedDeps adds the fields requested by the LoadMode in the packages in Imports.
|
|
39
|
+
// NeedExportsFile adds ExportsFile.
|
|
40
|
+
// NeedTypes adds Types, Fset, and IllTyped.
|
|
41
|
+
// NeedSyntax adds Syntax.
|
|
42
|
+
// NeedTypesInfo adds TypesInfo.
|
|
43
|
+
// NeedTypesSizes adds TypesSizes.
|
|
44
|
+
// TODO: disable these if not needed
|
|
45
|
+
opts.Mode |= packages.NeedName |
|
|
46
|
+
packages.NeedFiles |
|
|
47
|
+
packages.NeedCompiledGoFiles |
|
|
48
|
+
packages.NeedImports |
|
|
49
|
+
packages.NeedDeps |
|
|
50
|
+
packages.NeedExportFile |
|
|
51
|
+
packages.NeedTypes |
|
|
52
|
+
packages.NeedSyntax |
|
|
53
|
+
packages.NeedTypesInfo |
|
|
54
|
+
packages.NeedTypesSizes
|
|
55
|
+
|
|
56
|
+
return &Compiler{config: *conf, le: le, opts: *opts}, nil
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// CompilePackages attempts to build packages.
|
|
60
|
+
func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) error {
|
|
61
|
+
opts := c.opts
|
|
62
|
+
opts.Context = ctx
|
|
63
|
+
|
|
64
|
+
pkgs, err := packages.Load(&opts, patterns...)
|
|
65
|
+
if err != nil {
|
|
66
|
+
return err
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for _, pkg := range pkgs {
|
|
70
|
+
pkgCompiler, err := NewPackageCompiler(c.le, &c.config, pkg)
|
|
71
|
+
if err != nil {
|
|
72
|
+
return err
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if err := pkgCompiler.Compile(ctx); err != nil {
|
|
76
|
+
return err
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return nil
|
|
81
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"go/token"
|
|
5
|
+
|
|
6
|
+
"github.com/pkg/errors"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// Config is the configuration for the compiler
|
|
10
|
+
// Dir is the working directory for the compiler. If empty, uses the current working directory.
|
|
11
|
+
type Config struct {
|
|
12
|
+
fset *token.FileSet
|
|
13
|
+
|
|
14
|
+
// Dir is the working directory for the compiler. If empty, uses the current working directory.
|
|
15
|
+
Dir string
|
|
16
|
+
// OutputPathRoot is the output path root.
|
|
17
|
+
OutputPathRoot string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Validate checks the config.
|
|
21
|
+
func (c *Config) Validate() error {
|
|
22
|
+
if c.fset == nil {
|
|
23
|
+
c.fset = token.NewFileSet()
|
|
24
|
+
}
|
|
25
|
+
if c == nil {
|
|
26
|
+
return errors.New("config cannot be nil")
|
|
27
|
+
}
|
|
28
|
+
if c.OutputPathRoot == "" {
|
|
29
|
+
return errors.New("output path root must be specified")
|
|
30
|
+
}
|
|
31
|
+
return nil
|
|
32
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
// CompilerContext is the context for the compiler.
|
|
4
|
+
type CompilerContext struct {
|
|
5
|
+
// GoPackage is the name of the go package to compile
|
|
6
|
+
GoPackage string
|
|
7
|
+
// ComputedTsPackage is the path to the typescript package for this Go package.
|
|
8
|
+
ComputedTsPackage string
|
|
9
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"fmt"
|
|
6
|
+
"go/ast"
|
|
7
|
+
"os"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
|
|
10
|
+
"golang.org/x/tools/go/packages"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// fileImport is an import in a file.
|
|
14
|
+
type fileImport struct {
|
|
15
|
+
importPath string
|
|
16
|
+
importVars map[string]struct{}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// FileCompiler is the root compiler for a file.
|
|
20
|
+
type FileCompiler struct {
|
|
21
|
+
compilerConfig *Config
|
|
22
|
+
codeWriter *TSCodeWriter
|
|
23
|
+
pkg *packages.Package
|
|
24
|
+
ast *ast.File
|
|
25
|
+
fullPath string
|
|
26
|
+
|
|
27
|
+
imports map[string]fileImport
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// NewFileCompiler builds a new FileCompiler
|
|
31
|
+
func NewFileCompiler(
|
|
32
|
+
compilerConf *Config,
|
|
33
|
+
pkg *packages.Package,
|
|
34
|
+
astFile *ast.File,
|
|
35
|
+
fullPath string,
|
|
36
|
+
) (*FileCompiler, error) {
|
|
37
|
+
return &FileCompiler{
|
|
38
|
+
compilerConfig: compilerConf,
|
|
39
|
+
pkg: pkg,
|
|
40
|
+
ast: astFile,
|
|
41
|
+
fullPath: fullPath,
|
|
42
|
+
|
|
43
|
+
imports: make(map[string]fileImport),
|
|
44
|
+
}, nil
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Compile compiles a file.
|
|
48
|
+
func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
49
|
+
f := c.ast
|
|
50
|
+
|
|
51
|
+
pkgPath := c.pkg.PkgPath
|
|
52
|
+
outputFilePath := TranslateGoFilePathToTypescriptFilePath(pkgPath, filepath.Base(c.fullPath))
|
|
53
|
+
outputFilePathAbs := filepath.Join(c.compilerConfig.OutputPathRoot, outputFilePath)
|
|
54
|
+
|
|
55
|
+
if err := os.MkdirAll(filepath.Dir(outputFilePathAbs), 0o755); err != nil {
|
|
56
|
+
return err
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
of, err := os.OpenFile(outputFilePathAbs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return err
|
|
62
|
+
}
|
|
63
|
+
defer of.Close() //nolint:errcheck
|
|
64
|
+
|
|
65
|
+
c.codeWriter = NewTSCodeWriter(of)
|
|
66
|
+
// Create comment map
|
|
67
|
+
cmap := ast.NewCommentMap(c.pkg.Fset, f, f.Comments)
|
|
68
|
+
// Pass comment map to compiler
|
|
69
|
+
goWriter := NewGoToTSCompiler(c.codeWriter, c.pkg, cmap)
|
|
70
|
+
|
|
71
|
+
// Add import for the goscript runtime using namespace import and alias
|
|
72
|
+
c.codeWriter.WriteLine("import * as goscript from \"@go/builtin\";")
|
|
73
|
+
c.codeWriter.WriteLine("") // Add a newline after the import
|
|
74
|
+
|
|
75
|
+
if err := goWriter.WriteDecls(f.Decls); err != nil {
|
|
76
|
+
return fmt.Errorf("failed to write declarations: %w", err)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return nil
|
|
80
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
var typeScriptGoStubPrefix = "@ts/"
|
|
10
|
+
|
|
11
|
+
// translateGoPathToTypescriptPath translates a go package import path to a typescript import path.
|
|
12
|
+
func translateGoPathToTypescriptPath(goImportPath string) string {
|
|
13
|
+
if strings.HasPrefix(goImportPath, typeScriptGoStubPrefix) {
|
|
14
|
+
return goImportPath[len(typeScriptGoStubPrefix):]
|
|
15
|
+
}
|
|
16
|
+
return fmt.Sprintf("@go/%s", goImportPath)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// packageNameFromGoPath attempts to determine the package name from the last segment of the go path.
|
|
20
|
+
func packageNameFromGoPath(goPkgPath string) string {
|
|
21
|
+
pts := strings.Split(goPkgPath, "/")
|
|
22
|
+
return pts[len(pts)-1]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// TranslateGoFilePathToTypescriptFilePath converts the go package path and typescript filename to output path within the typescript output dir
|
|
26
|
+
func TranslateGoFilePathToTypescriptFilePath(goPkgPath, goCodeFilename string) string {
|
|
27
|
+
op := translateGoPathToTypescriptPath(goPkgPath)
|
|
28
|
+
baseFilename := goCodeFilename[:len(goCodeFilename)-3]
|
|
29
|
+
baseFilename = fmt.Sprintf("%s.gs.ts", baseFilename)
|
|
30
|
+
return filepath.Join(op, baseFilename)
|
|
31
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
|
|
9
|
+
"github.com/paralin/goscript/output"
|
|
10
|
+
"github.com/sirupsen/logrus"
|
|
11
|
+
"golang.org/x/tools/go/packages"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// PackageCompiler compiles an entire package.
|
|
15
|
+
type PackageCompiler struct {
|
|
16
|
+
le *logrus.Entry
|
|
17
|
+
compilerConf *Config
|
|
18
|
+
outputPath string
|
|
19
|
+
pkg *packages.Package
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// NewPackageCompiler builds a new PackageCompiler.
|
|
23
|
+
func NewPackageCompiler(
|
|
24
|
+
le *logrus.Entry,
|
|
25
|
+
compilerConf *Config,
|
|
26
|
+
pkg *packages.Package,
|
|
27
|
+
) (*PackageCompiler, error) {
|
|
28
|
+
res := &PackageCompiler{
|
|
29
|
+
le: le,
|
|
30
|
+
pkg: pkg,
|
|
31
|
+
compilerConf: compilerConf,
|
|
32
|
+
outputPath: output.ComputeModulePath(compilerConf.OutputPathRoot, pkg.PkgPath),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return res, nil
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Compile compiles the package.
|
|
39
|
+
func (c *PackageCompiler) Compile(ctx context.Context) error {
|
|
40
|
+
wd := c.compilerConf.Dir
|
|
41
|
+
if wd == "" {
|
|
42
|
+
var err error
|
|
43
|
+
wd, err = os.Getwd()
|
|
44
|
+
if err != nil {
|
|
45
|
+
return err
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Compile the files in the package one at a time
|
|
50
|
+
for i, f := range c.pkg.Syntax {
|
|
51
|
+
fileName := c.pkg.CompiledGoFiles[i]
|
|
52
|
+
relWdFileName, err := filepath.Rel(wd, fileName)
|
|
53
|
+
if err != nil {
|
|
54
|
+
return err
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
c.le.WithField("file", relWdFileName).Debug("compiling file")
|
|
58
|
+
if err := c.CompileFile(ctx, fileName, f); err != nil {
|
|
59
|
+
return err
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return nil
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// CompileFile compiles a file.
|
|
67
|
+
func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *ast.File) error {
|
|
68
|
+
fileCompiler, err := NewFileCompiler(p.compilerConf, p.pkg, syntax, name)
|
|
69
|
+
if err != nil {
|
|
70
|
+
return err
|
|
71
|
+
}
|
|
72
|
+
return fileCompiler.Compile(ctx)
|
|
73
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
"strings"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// TSCodeWriter writes TypeScript code.
|
|
10
|
+
type TSCodeWriter struct {
|
|
11
|
+
w io.Writer
|
|
12
|
+
indentLevel int
|
|
13
|
+
sectionWrittenFlag bool
|
|
14
|
+
lineWritten bool
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// NewTSCodeWriter builds a new TypeScript code writer.
|
|
18
|
+
func NewTSCodeWriter(w io.Writer) *TSCodeWriter {
|
|
19
|
+
return &TSCodeWriter{w: w}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// WriteLinePreamble writes the indentation.
|
|
23
|
+
func (w *TSCodeWriter) WriteLinePreamble() {
|
|
24
|
+
w.sectionWrittenFlag = true
|
|
25
|
+
w.lineWritten = false
|
|
26
|
+
for range w.indentLevel {
|
|
27
|
+
w.w.Write([]byte{byte('\t')}) //nolint:errcheck
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// WriteLine writes a line of code to the output.
|
|
32
|
+
func (w *TSCodeWriter) WriteLine(line string) {
|
|
33
|
+
if w.lineWritten {
|
|
34
|
+
w.WriteLinePreamble()
|
|
35
|
+
}
|
|
36
|
+
w.w.Write([]byte(line)) //nolint:errcheck
|
|
37
|
+
w.w.Write([]byte{byte('\n')}) //nolint:errcheck
|
|
38
|
+
w.lineWritten = true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// WriteLinef writes a formatted line of code to the output.
|
|
42
|
+
func (w *TSCodeWriter) WriteLinef(line string, args ...any) {
|
|
43
|
+
l := fmt.Sprintf(line, args...)
|
|
44
|
+
w.WriteLine(l)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Indent changes the indentation level by a delta.
|
|
48
|
+
func (w *TSCodeWriter) Indent(count int) {
|
|
49
|
+
w.indentLevel += count
|
|
50
|
+
if w.indentLevel < 0 {
|
|
51
|
+
w.indentLevel = 0
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// WriteImport writes a TypeScript import.
|
|
56
|
+
func (w *TSCodeWriter) WriteImport(symbolName, importPath string) {
|
|
57
|
+
w.WriteLinef("import * as %s from %q;", symbolName, importPath)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// WriteCommentLine writes a comment as a // line.
|
|
61
|
+
func (w *TSCodeWriter) WriteCommentLine(commentText string) {
|
|
62
|
+
lines := strings.Split(commentText, "\n")
|
|
63
|
+
for _, line := range lines {
|
|
64
|
+
w.WriteLinef("// %s", line)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// WriteCommentInline write a comment within /* */.
|
|
69
|
+
func (w *TSCodeWriter) WriteCommentInline(commentText string) {
|
|
70
|
+
w.w.Write([]byte("/* ")) //nolint:errcheck
|
|
71
|
+
w.w.Write([]byte(commentText)) //nolint:errcheck
|
|
72
|
+
w.w.Write([]byte(" */")) //nolint:errcheck
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// WriteLiterally writes something to the output without processing
|
|
76
|
+
func (w *TSCodeWriter) WriteLiterally(literal string) {
|
|
77
|
+
w.sectionWrittenFlag = true
|
|
78
|
+
if w.lineWritten {
|
|
79
|
+
w.WriteLinePreamble()
|
|
80
|
+
}
|
|
81
|
+
w.w.Write([]byte(literal))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// WriteSectionTail writes the end of a section.
|
|
85
|
+
func (w *TSCodeWriter) WriteSectionTail() {
|
|
86
|
+
if w.sectionWrittenFlag {
|
|
87
|
+
w.WriteLine("")
|
|
88
|
+
w.sectionWrittenFlag = false
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# GoScript Compliance Tests
|
|
2
|
+
|
|
3
|
+
This document outlines the compliance tests for the GoScript compiler, verifying its ability to correctly translate various Go language features into TypeScript.
|
|
4
|
+
|
|
5
|
+
## Existing Compliance Tests
|
|
6
|
+
|
|
7
|
+
The following tests are currently implemented in the `/compliance/tests` directory:
|
|
8
|
+
|
|
9
|
+
* **`basic_arithmetic/`**: Verifies basic arithmetic operations (`+`, `-`, `*`, `/`, `%`).
|
|
10
|
+
* **`boolean_logic/`**: Tests boolean logic operators (`&&`, `||`, `!`) and comparisons (`==`, `!=`, `<`, `>`, `<=`, `>=`).
|
|
11
|
+
* **`composite_literal_assignment/`**: Checks the assignment of struct values created using composite literals, ensuring correct value copying.
|
|
12
|
+
* **`copy_independence/`**: Verifies that copies of struct values are independent and modifications to one do not affect others.
|
|
13
|
+
* **`function_call_result_assignment/`**: Tests assigning the result of a function returning a struct, ensuring proper value semantics (copying).
|
|
14
|
+
* **`if_statement/`**: Covers basic `if`/`else` conditional statements, including correct `} else {` formatting.
|
|
15
|
+
* **`switch_statement/`**: Verifies basic `switch` statements with integer and string tags and default cases.
|
|
16
|
+
* **`for_loop_basic/`**: Verifies basic counter-based `for` loops (`for init; cond; post {}`).
|
|
17
|
+
* **`map_support/`**: Covers map creation (`make`, literal), access, assignment, deletion, length, and iteration (`range`).
|
|
18
|
+
* **`method_call_on_pointer_receiver/`**: Verifies calling methods with pointer receivers (`*T`) on pointer variables.
|
|
19
|
+
* **`method_call_on_value_receiver/`**: Verifies calling methods with value receivers (`T`) on value variables. (Note: Go often implicitly takes the address for pointer receivers, this tests the explicit value receiver case).
|
|
20
|
+
* **`pointer_deref_multiassign/`**: Tests dereferencing a pointer during a multi-variable assignment (`:=` or `=`), including the use of the blank identifier (`_`).
|
|
21
|
+
* **`pointer_initialization/`**: Checks the initialization of pointer variables using the address-of operator (`&`) or `new()`.
|
|
22
|
+
* **`simple/`**: A basic test covering simple struct definition, field access, method calls, and `println`. (Likely overlaps with others, could be a general integration test).
|
|
23
|
+
* **`simple_deref_assignment/`**: Tests simple assignment involving pointer dereferencing (`*ptr`), ensuring value copying.
|
|
24
|
+
* **`struct_field_access/`**: Verifies accessing fields of struct values and struct pointers.
|
|
25
|
+
* **`struct_value_init_clone/`**: Checks struct initialization via composite literal (`T{...}`) (omitting `.clone()` for direct assignment) and subsequent assignment from variables (ensuring `.clone()` is used for value semantics).
|
|
26
|
+
* **`value_type_copy_behavior/`**: Focuses specifically on demonstrating that assigning struct values creates independent copies (value semantics).
|
|
27
|
+
|
|
28
|
+
Each test should have only three files:
|
|
29
|
+
|
|
30
|
+
1. test_name.go - the Go code to convert to TypeScript
|
|
31
|
+
2. test_name.gs.ts - the generated TypeScript code, created automatically on test run
|
|
32
|
+
3. expected.log - the expected output from running the .gs.ts
|
|
33
|
+
|
|
34
|
+
## Covered Go Language Constructs
|
|
35
|
+
|
|
36
|
+
Based on the existing tests, GoScript aims to support the following Go features:
|
|
37
|
+
|
|
38
|
+
* **Basic Types:** `int`, `string`, `bool`, `float64` (implicitly tested).
|
|
39
|
+
* **Type Conversions:** `string(rune)`
|
|
40
|
+
* **Operators:**
|
|
41
|
+
* Arithmetic: `+`, `-`, `*`, `/`, `%`
|
|
42
|
+
* Comparison: `==`, `!=`, `<`, `>`, `<=`, `>=`
|
|
43
|
+
* Logical: `&&`, `||`, `!`
|
|
44
|
+
* **Control Flow:**
|
|
45
|
+
* `if`/`else` statements.
|
|
46
|
+
* `switch` statements.
|
|
47
|
+
* `select` statement.
|
|
48
|
+
* `for` loops (condition-only, basic counter-based, `range` over arrays/slices/strings).
|
|
49
|
+
* **Data Structures:**
|
|
50
|
+
* Arrays (`[N]T`) - Including array literals and indexing.
|
|
51
|
+
* Slices (`[]T`) - Creation using `make([]T, len)` and `make([]T, len, cap)`.
|
|
52
|
+
* Maps (`map[K]V`) - Creation using `make`, literals, access, assignment, `delete`, `len`, `range`.
|
|
53
|
+
* `struct` definitions (including exported/unexported fields).
|
|
54
|
+
* Composite Literals for structs (`MyStruct{...}`).
|
|
55
|
+
* **Functions & Methods:**
|
|
56
|
+
* Function definition (`func`).
|
|
57
|
+
* Function Literals (`func() { ... }`)
|
|
58
|
+
* Method definition with value receivers (`func (v T) Method()`).
|
|
59
|
+
* Method definition with pointer receivers (`func (p *T) Method()`).
|
|
60
|
+
* Function calls.
|
|
61
|
+
* Method calls (on values and pointers).
|
|
62
|
+
* `println` built-in (mapped to `console.log`).
|
|
63
|
+
* Multiple return values (including assignment and usage with blank identifier).
|
|
64
|
+
* Asynchronous Functions (`async`/`await` based on channel operations)
|
|
65
|
+
* **Variables & Assignment:**
|
|
66
|
+
* Variable declaration (`var`, implicitly via `:=`).
|
|
67
|
+
* Short variable declaration (`:=`).
|
|
68
|
+
* Assignment (`=`).
|
|
69
|
+
* Multi-variable assignment.
|
|
70
|
+
* Blank identifier (`_`) in assignment.
|
|
71
|
+
* **Pointers:**
|
|
72
|
+
* Pointer types (`*T`).
|
|
73
|
+
* Address-of operator (`&`).
|
|
74
|
+
* Dereference operator (`*`).
|
|
75
|
+
* **Value Semantics:** Emulation of Go's struct copy-on-assignment behavior.
|
|
76
|
+
* **Concurrency:**
|
|
77
|
+
* Goroutines (`go func()`)
|
|
78
|
+
* Channels (`chan T`, `make`, send `<-`, receive `<-`, buffered/unbuffered, closing)
|
|
79
|
+
|
|
80
|
+
## Uncovered Go Language Constructs (Based on Go By Example)
|
|
81
|
+
|
|
82
|
+
The following Go constructs, present in the "Go By Example" guide, do not appear to have dedicated compliance tests yet. This list is not exhaustive but provides a starting point for future test development.
|
|
83
|
+
|
|
84
|
+
* Interfaces (`interface{}`) - Definition tested, and type assertions (`v.(T)`) are now compliant, including interface-to-interface type assertions.
|
|
85
|
+
* **Control Flow:**
|
|
86
|
+
* `for` loops (condition-only, infinite still uncovered)
|
|
87
|
+
* `switch` statements (with/without expression, type switches)
|
|
88
|
+
* `select` statement (for channel operations)
|
|
89
|
+
* `defer` statement
|
|
90
|
+
* `panic` / `recover`
|
|
91
|
+
* **Data Structures:**
|
|
92
|
+
* Struct Embedding
|
|
93
|
+
* **Functions:**
|
|
94
|
+
* Variadic functions (`...T`)
|
|
95
|
+
* Closures
|
|
96
|
+
* Recursion
|
|
97
|
+
* **Basic Types & Values:**
|
|
98
|
+
* `iota` consts
|
|
99
|
+
* **Concurrency:**
|
|
100
|
+
* Mutexes (`sync.Mutex`)
|
|
101
|
+
* **Error Handling:**
|
|
102
|
+
* `error` interface usage
|
|
103
|
+
* **Packages & Imports:**
|
|
104
|
+
* Import aliasing (`import alias "path"`)
|
|
105
|
+
|
|
106
|
+
This list helps identify areas where GoScript's feature coverage can be expanded and verified through new compliance tests.
|
|
107
|
+
|
|
108
|
+
## Ignored or Not-planned Go Language Constructs
|
|
109
|
+
|
|
110
|
+
These are the not-planned features that we should NOT waste time adding yet:
|
|
111
|
+
|
|
112
|
+
* complex number support (complex64, etc.)
|
|
113
|
+
* **Reflection:** (`reflect` package) - Likely out of scope for direct translation.
|
|
114
|
+
* **Testing:** (`testing` package) - Test files themselves are usually not translated.
|
|
115
|
+
* Constants (`const`) - handling of large integer constants (exceeding standard JavaScript number limits) is currently not fully compliant.
|
|
116
|
+
* Generics (Type parameters, constraints)
|
|
117
|
+
* `goto` (less common, but part of the language)
|
|
118
|
+
* **Directives:**
|
|
119
|
+
* `//go:embed`
|
|
120
|
+
* Dot imports (`import . "path"`) - Generally discouraged.
|
|
121
|
+
* Handling standard library packages (e.g., `fmt`, `math`, `time`, `os`, `net/http`, `encoding/json`, `regexp`, etc.) - Requires runtime shims or direct translation.
|
|
122
|
+
* **Input/Output & System:**
|
|
123
|
+
* File I/O (`os.ReadFile`, `os.WriteFile`, etc.)
|
|
124
|
+
* Command-line arguments/flags (`os.Args`, `flag` package)
|
|
125
|
+
* Environment variables (`os.Getenv`)
|
|
126
|
+
* Executing processes (`os/exec`)
|
|
127
|
+
* Signals (`os/signal`)
|
|
128
|
+
* Context (`context`)
|
|
129
|
+
* WaitGroups (`sync.WaitGroup`)
|
|
130
|
+
* Atomic Counters (`sync/atomic`)
|
|
131
|
+
* Rate Limiting concepts
|
|
132
|
+
* Worker Pools
|
|
133
|
+
* Stateful Goroutines
|