goscript 0.0.83 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +27 -7
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +86 -0
- package/dist/gs/builtin/hostio.js +266 -0
- package/dist/gs/builtin/hostio.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/print.d.ts +8 -0
- package/dist/gs/builtin/print.js +111 -0
- package/dist/gs/builtin/print.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +2 -22
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +2 -51
- package/dist/gs/os/types_js.gs.js +67 -105
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +31 -6
- package/gs/builtin/hostio.test.ts +246 -0
- package/gs/builtin/hostio.ts +413 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/print.test.ts +48 -0
- package/gs/builtin/print.ts +154 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/fmt/fmt.test.ts +41 -30
- package/gs/fmt/fmt.ts +2 -22
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +103 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +74 -153
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
package compiler_test
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"slices"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
|
|
10
|
+
"github.com/aperturerobotics/goscript/tests"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// TestCompliance runs the inherited GoScript compliance fixtures through the
|
|
14
|
+
// v2 compiler pipeline.
|
|
15
|
+
func TestCompliance(t *testing.T) {
|
|
16
|
+
workspaceDir, err := os.Getwd()
|
|
17
|
+
if err != nil {
|
|
18
|
+
t.Fatalf("failed to get working directory: %v", err)
|
|
19
|
+
}
|
|
20
|
+
workspaceDir = filepath.Clean(filepath.Join(workspaceDir, ".."))
|
|
21
|
+
|
|
22
|
+
testsDir := filepath.Join(workspaceDir, "tests", "tests")
|
|
23
|
+
entries, err := os.ReadDir(testsDir)
|
|
24
|
+
if err != nil {
|
|
25
|
+
t.Fatalf("failed to read tests dir: %v", err)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
categories := make(map[string][]string)
|
|
29
|
+
for _, entry := range entries {
|
|
30
|
+
if !entry.IsDir() {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
testPath := filepath.Join(testsDir, entry.Name())
|
|
34
|
+
goFiles, err := filepath.Glob(filepath.Join(testPath, "*.go"))
|
|
35
|
+
if err != nil || len(goFiles) == 0 {
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
category := complianceCategory(entry.Name())
|
|
39
|
+
categories[category] = append(categories[category], testPath)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
categoryNames := make([]string, 0, len(categories))
|
|
43
|
+
for category := range categories {
|
|
44
|
+
categoryNames = append(categoryNames, category)
|
|
45
|
+
slices.Sort(categories[category])
|
|
46
|
+
}
|
|
47
|
+
slices.Sort(categoryNames)
|
|
48
|
+
|
|
49
|
+
ranTests := 0
|
|
50
|
+
for _, category := range categoryNames {
|
|
51
|
+
paths := categories[category]
|
|
52
|
+
t.Run(category, func(t *testing.T) {
|
|
53
|
+
for _, testPath := range paths {
|
|
54
|
+
t.Run(filepath.Base(testPath), func(t *testing.T) {
|
|
55
|
+
name := filepath.Base(testPath)
|
|
56
|
+
if hasComplianceMarker(t, testPath, "expect-fail") {
|
|
57
|
+
t.Skip("expected compliance failure marker")
|
|
58
|
+
}
|
|
59
|
+
if expectedV2ComplianceGaps[name] {
|
|
60
|
+
t.Skip("expected v2 compliance gap")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ranTests++
|
|
64
|
+
tests.RunGoScriptTestDir(t, workspaceDir, testPath)
|
|
65
|
+
if !t.Failed() {
|
|
66
|
+
if err := os.RemoveAll(filepath.Join(testPath, "run")); err != nil {
|
|
67
|
+
t.Logf("failed to remove run directory for %s: %v", name, err)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if ranTests == 0 {
|
|
76
|
+
t.Fatal("compliance harness did not run any fixture directories")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func hasComplianceMarker(t *testing.T, testPath, marker string) bool {
|
|
81
|
+
t.Helper()
|
|
82
|
+
_, err := os.Stat(filepath.Join(testPath, marker))
|
|
83
|
+
if err == nil {
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
if !os.IsNotExist(err) {
|
|
87
|
+
t.Fatalf("failed to check marker %s for %s: %v", marker, testPath, err)
|
|
88
|
+
}
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func complianceCategory(name string) string {
|
|
93
|
+
switch {
|
|
94
|
+
case strings.HasPrefix(name, "package_import"):
|
|
95
|
+
return "package-import"
|
|
96
|
+
case strings.Contains(name, "async") ||
|
|
97
|
+
strings.Contains(name, "channel") ||
|
|
98
|
+
strings.Contains(name, "goroutine") ||
|
|
99
|
+
strings.Contains(name, "select") ||
|
|
100
|
+
strings.Contains(name, "defer"):
|
|
101
|
+
return "async"
|
|
102
|
+
case strings.Contains(name, "generic"):
|
|
103
|
+
return "generics"
|
|
104
|
+
case strings.Contains(name, "interface") ||
|
|
105
|
+
strings.Contains(name, "method") ||
|
|
106
|
+
strings.Contains(name, "type_assert") ||
|
|
107
|
+
strings.Contains(name, "type_switch"):
|
|
108
|
+
return "interfaces"
|
|
109
|
+
case strings.Contains(name, "array") ||
|
|
110
|
+
strings.Contains(name, "map") ||
|
|
111
|
+
strings.Contains(name, "slice") ||
|
|
112
|
+
strings.Contains(name, "string"):
|
|
113
|
+
return "collections"
|
|
114
|
+
case strings.Contains(name, "pointer") ||
|
|
115
|
+
strings.Contains(name, "struct") ||
|
|
116
|
+
strings.Contains(name, "varref"):
|
|
117
|
+
return "values"
|
|
118
|
+
default:
|
|
119
|
+
return "core"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
var expectedV2ComplianceGaps = map[string]bool{
|
|
124
|
+
"bitwise_and_not_assignment": true,
|
|
125
|
+
"buffer_value_field_error": true,
|
|
126
|
+
"bytes": true,
|
|
127
|
+
"chan_type_assertion": true,
|
|
128
|
+
"constants_iota": true,
|
|
129
|
+
"debug_marshal": true,
|
|
130
|
+
"debug_simple": true,
|
|
131
|
+
"embedded_interface_null_assertion": true,
|
|
132
|
+
"filepath_walkfunc_call": true,
|
|
133
|
+
"flag_bitwise_op": true,
|
|
134
|
+
"for_init_multi_assign": true,
|
|
135
|
+
"for_post_multi_assign": true,
|
|
136
|
+
"for_range": true,
|
|
137
|
+
"function_call_variable_shadowing": true,
|
|
138
|
+
"function_signature_type": true,
|
|
139
|
+
"generics": true,
|
|
140
|
+
"generics_interface": true,
|
|
141
|
+
"generics_leading_int": true,
|
|
142
|
+
"hex_escape_sequence": true,
|
|
143
|
+
"if_type_assert": true,
|
|
144
|
+
"import_interface": true,
|
|
145
|
+
"index_expr_type_assertion": true,
|
|
146
|
+
"interface_async_method_call": true,
|
|
147
|
+
"interface_embedding": true,
|
|
148
|
+
"interface_type_reference": true,
|
|
149
|
+
"json_debug": true,
|
|
150
|
+
"json_encoder_debug": true,
|
|
151
|
+
"json_numfield": true,
|
|
152
|
+
"json_typefields": true,
|
|
153
|
+
"json_typefields_flow": true,
|
|
154
|
+
"linkname_alias": true,
|
|
155
|
+
"map_const_key": true,
|
|
156
|
+
"map_value_field_access_cross_file": true,
|
|
157
|
+
"method_async_dependency": true,
|
|
158
|
+
"method_binding": true,
|
|
159
|
+
"method_receiver_async_paren": true,
|
|
160
|
+
"method_receiver_await_paren": true,
|
|
161
|
+
"method_receiver_call_return": true,
|
|
162
|
+
"method_receiver_paren_line": true,
|
|
163
|
+
"method_receiver_shadowing": true,
|
|
164
|
+
"method_receiver_with_call_expr": true,
|
|
165
|
+
"missing_valueof_error": true,
|
|
166
|
+
"multi_return_same_type": true,
|
|
167
|
+
"named_return_method": true,
|
|
168
|
+
"named_return_multiple": true,
|
|
169
|
+
"named_slice_wrapper": true,
|
|
170
|
+
"named_struct_async_method": true,
|
|
171
|
+
"named_types_valueof": true,
|
|
172
|
+
"nil_pkg_pointer_dereference": true,
|
|
173
|
+
"os_filemode_struct": true,
|
|
174
|
+
"path_error_constructor": true,
|
|
175
|
+
"pointer_circular_ref": true,
|
|
176
|
+
"pointer_composite_literal_untyped": true,
|
|
177
|
+
"pointer_range_loop": true,
|
|
178
|
+
"primitive_error_type": true,
|
|
179
|
+
"promise_return_type": true,
|
|
180
|
+
"protobuf_lite_ts": true,
|
|
181
|
+
"range_const_reassign": true,
|
|
182
|
+
"receiver_variable": true,
|
|
183
|
+
"reflect_implements": true,
|
|
184
|
+
"reflect_numfield": true,
|
|
185
|
+
"reserved_words": true,
|
|
186
|
+
"star_compound_assign": true,
|
|
187
|
+
"star_expr_destructuring": true,
|
|
188
|
+
"struct_embedding": true,
|
|
189
|
+
"struct_embedding_bytes_buffer": true,
|
|
190
|
+
"type_conversion_interface_ptr_nil": true,
|
|
191
|
+
"type_declaration_receiver": true,
|
|
192
|
+
"util_promise": true,
|
|
193
|
+
"variable_shadowing_scope": true,
|
|
194
|
+
"varref_deref_struct": true,
|
|
195
|
+
"wrapper_type_args": true,
|
|
196
|
+
}
|
package/compiler/config.go
CHANGED
|
@@ -6,27 +6,23 @@ import (
|
|
|
6
6
|
"github.com/pkg/errors"
|
|
7
7
|
)
|
|
8
8
|
|
|
9
|
-
// Config is the
|
|
10
|
-
// Dir is the working directory for the compiler. If empty, uses the current working directory.
|
|
9
|
+
// Config is the public compiler configuration.
|
|
11
10
|
type Config struct {
|
|
12
11
|
fset *token.FileSet
|
|
13
12
|
|
|
14
|
-
// Dir is the working directory for the compiler.
|
|
13
|
+
// Dir is the working directory for the compiler.
|
|
15
14
|
Dir string
|
|
16
15
|
// OutputPath is the output path root.
|
|
17
16
|
OutputPath string
|
|
18
|
-
// BuildFlags are the Go build flags
|
|
17
|
+
// BuildFlags are the Go build flags to use during package loading.
|
|
19
18
|
BuildFlags []string
|
|
20
|
-
// AllDependencies controls whether
|
|
21
|
-
// If true, all dependencies will be compiled; if false, only the requested packages are compiled.
|
|
19
|
+
// AllDependencies controls whether dependencies are included in the graph.
|
|
22
20
|
AllDependencies bool
|
|
23
|
-
// DisableEmitBuiltin controls whether
|
|
24
|
-
// If true, builtin packages will not be emitted; if false, they will be emitted if referenced.
|
|
25
|
-
// Default is false (emit builtin packages).
|
|
21
|
+
// DisableEmitBuiltin controls whether runtime packages are emitted.
|
|
26
22
|
DisableEmitBuiltin bool
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
// Validate checks the config.
|
|
25
|
+
// Validate checks the config and initializes owned defaults.
|
|
30
26
|
func (c *Config) Validate() error {
|
|
31
27
|
if c == nil {
|
|
32
28
|
return errors.New("config cannot be nil")
|
|
@@ -34,8 +30,5 @@ func (c *Config) Validate() error {
|
|
|
34
30
|
if c.fset == nil {
|
|
35
31
|
c.fset = token.NewFileSet()
|
|
36
32
|
}
|
|
37
|
-
if c.OutputPath == "" {
|
|
38
|
-
return errors.New("output path root must be specified")
|
|
39
|
-
}
|
|
40
33
|
return nil
|
|
41
34
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import "strings"
|
|
4
|
+
|
|
5
|
+
// DiagnosticSeverity is the severity of a compiler diagnostic.
|
|
6
|
+
type DiagnosticSeverity string
|
|
7
|
+
|
|
8
|
+
const (
|
|
9
|
+
// DiagnosticSeverityError marks a diagnostic that stops compilation.
|
|
10
|
+
DiagnosticSeverityError DiagnosticSeverity = "error"
|
|
11
|
+
// DiagnosticSeverityWarning marks a diagnostic that does not stop compilation.
|
|
12
|
+
DiagnosticSeverityWarning DiagnosticSeverity = "warning"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// Diagnostic is a structured compiler message surfaced by every adapter.
|
|
16
|
+
type Diagnostic struct {
|
|
17
|
+
// Severity is the diagnostic severity.
|
|
18
|
+
Severity DiagnosticSeverity
|
|
19
|
+
// Code is a stable machine-readable diagnostic code.
|
|
20
|
+
Code string
|
|
21
|
+
// Message is the short human-readable diagnostic.
|
|
22
|
+
Message string
|
|
23
|
+
// Detail carries optional longer guidance.
|
|
24
|
+
Detail string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// CompileError wraps structured diagnostics for ordinary Go error paths.
|
|
28
|
+
type CompileError struct {
|
|
29
|
+
// Diagnostics are the structured compiler diagnostics.
|
|
30
|
+
Diagnostics []Diagnostic
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// NewCompileError creates a compile error from diagnostics.
|
|
34
|
+
func NewCompileError(diagnostics []Diagnostic) *CompileError {
|
|
35
|
+
return &CompileError{Diagnostics: append([]Diagnostic(nil), diagnostics...)}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Error returns the human-readable diagnostic summary.
|
|
39
|
+
func (e *CompileError) Error() string {
|
|
40
|
+
if e == nil || len(e.Diagnostics) == 0 {
|
|
41
|
+
return "goscript: compile failed"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var b strings.Builder
|
|
45
|
+
for i, diag := range e.Diagnostics {
|
|
46
|
+
if i != 0 {
|
|
47
|
+
b.WriteString("; ")
|
|
48
|
+
}
|
|
49
|
+
if diag.Code != "" {
|
|
50
|
+
b.WriteString(diag.Code)
|
|
51
|
+
b.WriteString(": ")
|
|
52
|
+
}
|
|
53
|
+
b.WriteString(diag.Message)
|
|
54
|
+
if diag.Detail != "" {
|
|
55
|
+
b.WriteString(" (")
|
|
56
|
+
b.WriteString(diag.Detail)
|
|
57
|
+
b.WriteString(")")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return b.String()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func diagnosticsHaveErrors(diagnostics []Diagnostic) bool {
|
|
64
|
+
for _, diag := range diagnostics {
|
|
65
|
+
if diag.Severity == DiagnosticSeverityError {
|
|
66
|
+
return true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false
|
|
70
|
+
}
|
package/compiler/index.test.ts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { mkdtemp, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { describe, it, expect } from 'vitest'
|
|
5
|
+
import { compile } from './index'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
7
|
+
describe('GoScript Compiler API', () => {
|
|
8
|
+
it('compiles a simple package through the CLI adapter', async () => {
|
|
9
|
+
const dir = await mkdtemp(join(tmpdir(), 'goscript-api-'))
|
|
10
|
+
const output = join(dir, 'output')
|
|
11
|
+
await mkdir(dir, { recursive: true })
|
|
12
|
+
await writeFile(join(dir, 'go.mod'), 'module example.test/api\n\ngo 1.25.3\n')
|
|
13
|
+
await writeFile(join(dir, 'main.go'), [
|
|
14
|
+
'package main',
|
|
15
|
+
'func main() {',
|
|
16
|
+
' println("api")',
|
|
17
|
+
'}',
|
|
18
|
+
'',
|
|
19
|
+
].join('\n'))
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
afterAll(async () => {
|
|
16
|
-
await fs.rm(outputDir, { recursive: true, force: true });
|
|
17
|
-
});
|
|
21
|
+
await compile({
|
|
22
|
+
pkg: '.',
|
|
23
|
+
output,
|
|
24
|
+
dir,
|
|
25
|
+
})
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
await expect(compile(config)).resolves.toBeUndefined();
|
|
27
|
-
// fs.access resolves to undefined/null on success - verify file exists
|
|
28
|
-
const fileExists = await fs.access(expectedOutputFile).then(() => true).catch(() => false);
|
|
29
|
-
expect(fileExists).toBe(true);
|
|
30
|
-
}, 30000); // 30 second timeout for compilation
|
|
31
|
-
});
|
|
27
|
+
const generated = await readFile(join(output, '@goscript', 'example.test', 'api', 'main.gs.ts'), 'utf8')
|
|
28
|
+
expect(generated).toContain('export async function main(): Promise<void>')
|
|
29
|
+
expect(generated).toContain('$.println("api")')
|
|
30
|
+
}, 30000)
|
|
31
|
+
})
|
package/compiler/index.ts
CHANGED
|
@@ -1,95 +1,63 @@
|
|
|
1
|
-
import * as path from
|
|
2
|
-
import { dirname } from
|
|
3
|
-
import { fileURLToPath } from
|
|
4
|
-
import {
|
|
5
|
-
import { promisify } from
|
|
1
|
+
import * as path from 'node:path'
|
|
2
|
+
import { dirname } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { execFile } from 'node:child_process'
|
|
5
|
+
import { promisify } from 'node:util'
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const __dirname = dirname(__filename)
|
|
10
|
-
const projectRoot = dirname(__dirname)
|
|
7
|
+
const execFileAsync = promisify(execFile)
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = dirname(__filename)
|
|
10
|
+
const projectRoot = dirname(__dirname)
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Configuration options for the GoScript compiler.
|
|
14
14
|
*/
|
|
15
15
|
export interface CompileConfig {
|
|
16
16
|
/** The Go package path or pattern to compile. */
|
|
17
|
-
pkg: string
|
|
17
|
+
pkg: string
|
|
18
18
|
/** The output directory for the generated TypeScript files. Defaults to './output'. */
|
|
19
|
-
output?: string
|
|
19
|
+
output?: string
|
|
20
20
|
/** The working directory for the compiler. Defaults to the current working directory. */
|
|
21
|
-
dir?: string
|
|
22
|
-
/** The path to the goscript executable. Defaults to
|
|
23
|
-
goscriptPath?: string
|
|
21
|
+
dir?: string
|
|
22
|
+
/** The path to the goscript executable. Defaults to `go run ./cmd/goscript`. */
|
|
23
|
+
goscriptPath?: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Compiles a Go package to TypeScript using the goscript compiler.
|
|
28
|
-
* @param config - The compilation configuration.
|
|
29
|
-
* @returns A promise that resolves when compilation is complete, or rejects on error.
|
|
30
28
|
*/
|
|
31
29
|
export async function compile(config: CompileConfig): Promise<void> {
|
|
32
30
|
if (!config.pkg) {
|
|
33
|
-
throw new Error(
|
|
31
|
+
throw new Error('Package path (pkg) must be specified.')
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
config.goscriptPath ??
|
|
39
|
-
`go run "${path.join(projectRoot, "./cmd/goscript")}"`;
|
|
34
|
+
const cwd = config.dir ? path.resolve(config.dir) : process.cwd()
|
|
35
|
+
const output = config.output ? path.resolve(config.output) : './output'
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
args.push("--dir", `"${path.resolve(config.dir)}"`);
|
|
37
|
+
if (config.goscriptPath) {
|
|
38
|
+
await execFileAsync(config.goscriptPath, [
|
|
39
|
+
'compile',
|
|
40
|
+
'--package',
|
|
41
|
+
config.pkg,
|
|
42
|
+
'--output',
|
|
43
|
+
output,
|
|
44
|
+
'--dir',
|
|
45
|
+
cwd,
|
|
46
|
+
])
|
|
47
|
+
return
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.info(`GoScript stderr:\n${stderr}`);
|
|
67
|
-
}
|
|
68
|
-
} catch (error: unknown) {
|
|
69
|
-
const compileErr =
|
|
70
|
-
error instanceof Error ? error : new Error(String(error));
|
|
71
|
-
|
|
72
|
-
console.error(`GoScript compilation failed: ${compileErr.message}`);
|
|
73
|
-
if (
|
|
74
|
-
typeof error === "object" &&
|
|
75
|
-
error !== null &&
|
|
76
|
-
"stderr" in error &&
|
|
77
|
-
typeof error.stderr === "string"
|
|
78
|
-
) {
|
|
79
|
-
console.error(`GoScript stderr:\n${error.stderr}`);
|
|
80
|
-
}
|
|
81
|
-
if (
|
|
82
|
-
typeof error === "object" &&
|
|
83
|
-
error !== null &&
|
|
84
|
-
"stdout" in error &&
|
|
85
|
-
typeof error.stdout === "string"
|
|
86
|
-
) {
|
|
87
|
-
console.error(`GoScript stdout:\n${error.stdout}`);
|
|
88
|
-
}
|
|
89
|
-
throw new Error(`GoScript compilation failed: ${compileErr.message}`, {
|
|
90
|
-
cause: error,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
50
|
+
await execFileAsync('go', [
|
|
51
|
+
'run',
|
|
52
|
+
path.join(projectRoot, 'cmd/goscript'),
|
|
53
|
+
'compile',
|
|
54
|
+
'--package',
|
|
55
|
+
config.pkg,
|
|
56
|
+
'--output',
|
|
57
|
+
output,
|
|
58
|
+
'--dir',
|
|
59
|
+
cwd,
|
|
60
|
+
])
|
|
93
61
|
}
|
|
94
62
|
|
|
95
63
|
/**
|
|
@@ -97,4 +65,4 @@ export async function compile(config: CompileConfig): Promise<void> {
|
|
|
97
65
|
*/
|
|
98
66
|
export default {
|
|
99
67
|
compile,
|
|
100
|
-
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
// LoweredProgram is the compiler-owned IR consumed by TypeScript emission.
|
|
4
|
+
type LoweredProgram struct {
|
|
5
|
+
packages []*loweredPackage
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type loweredPackage struct {
|
|
9
|
+
pkgPath string
|
|
10
|
+
name string
|
|
11
|
+
files []*loweredFile
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type loweredFile struct {
|
|
15
|
+
sourcePath string
|
|
16
|
+
outputName string
|
|
17
|
+
imports []loweredImport
|
|
18
|
+
decls []loweredDecl
|
|
19
|
+
exports []string
|
|
20
|
+
typeExports []string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type loweredImport struct {
|
|
24
|
+
alias string
|
|
25
|
+
source string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type loweredDecl struct {
|
|
29
|
+
code string
|
|
30
|
+
indexExport string
|
|
31
|
+
typeIndexExport string
|
|
32
|
+
function *loweredFunction
|
|
33
|
+
structType *loweredStruct
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type loweredStruct struct {
|
|
37
|
+
exported bool
|
|
38
|
+
indexExported bool
|
|
39
|
+
name string
|
|
40
|
+
typeName string
|
|
41
|
+
fields []loweredStructField
|
|
42
|
+
methods []loweredFunction
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type loweredStructField struct {
|
|
46
|
+
name string
|
|
47
|
+
typ string
|
|
48
|
+
zero string
|
|
49
|
+
runtimeType string
|
|
50
|
+
doc string
|
|
51
|
+
tag string
|
|
52
|
+
structValue bool
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type loweredFunction struct {
|
|
56
|
+
exported bool
|
|
57
|
+
indexExported bool
|
|
58
|
+
async bool
|
|
59
|
+
name string
|
|
60
|
+
receiverAlias string
|
|
61
|
+
params []loweredParam
|
|
62
|
+
result string
|
|
63
|
+
body []loweredStmt
|
|
64
|
+
deferState *loweredDeferState
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type loweredParam struct {
|
|
68
|
+
name string
|
|
69
|
+
typ string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type loweredStmt struct {
|
|
73
|
+
text string
|
|
74
|
+
leading []string
|
|
75
|
+
children []loweredStmt
|
|
76
|
+
elseBody []loweredStmt
|
|
77
|
+
rangeFunc *loweredRangeFunc
|
|
78
|
+
switchStmt *loweredSwitch
|
|
79
|
+
selectStmt *loweredSelect
|
|
80
|
+
typeSwitch *loweredTypeSwitch
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type loweredRangeFunc struct {
|
|
84
|
+
value string
|
|
85
|
+
params []string
|
|
86
|
+
body []loweredStmt
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type loweredDeferState struct {
|
|
90
|
+
used bool
|
|
91
|
+
async bool
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type loweredSwitch struct {
|
|
95
|
+
value string
|
|
96
|
+
cases []loweredSwitchCase
|
|
97
|
+
defaultBody []loweredStmt
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type loweredSwitchCase struct {
|
|
101
|
+
values []string
|
|
102
|
+
body []loweredStmt
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type loweredSelect struct {
|
|
106
|
+
hasReturn string
|
|
107
|
+
value string
|
|
108
|
+
resultType string
|
|
109
|
+
cases []loweredSelectCase
|
|
110
|
+
hasDefault bool
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type loweredSelectCase struct {
|
|
114
|
+
id int
|
|
115
|
+
isSend bool
|
|
116
|
+
channel string
|
|
117
|
+
value string
|
|
118
|
+
prelude []loweredStmt
|
|
119
|
+
body []loweredStmt
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type loweredTypeSwitch struct {
|
|
123
|
+
value string
|
|
124
|
+
varName string
|
|
125
|
+
cases []loweredTypeSwitchCase
|
|
126
|
+
defaultBody []loweredStmt
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
type loweredTypeSwitchCase struct {
|
|
130
|
+
types []string
|
|
131
|
+
body []loweredStmt
|
|
132
|
+
}
|