goscript 0.0.45 โ 0.0.48
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 +198 -504
- package/compiler/compiler.go +20 -70
- package/compiler/decl.go +52 -38
- package/compiler/expr-call-async.go +101 -0
- package/compiler/expr-call-builtins.go +133 -0
- package/compiler/expr-call-helpers.go +138 -0
- package/compiler/expr-call-make.go +568 -0
- package/compiler/expr-call-type-conversion.go +424 -0
- package/compiler/expr-call.go +59 -1305
- package/compiler/expr.go +126 -4
- package/compiler/spec-struct.go +22 -9
- package/compiler/spec.go +53 -118
- package/compiler/type.go +51 -0
- package/dist/gs/builtin/builtin.d.ts +3 -1
- package/dist/gs/builtin/builtin.js +6 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +12 -1
- package/dist/gs/io/fs/fs.js +106 -30
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -3
- package/dist/gs/os/types_js.gs.js +2 -1
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js +2 -2
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/gs/builtin/builtin.ts +7 -2
- package/gs/io/fs/fs.ts +100 -31
- package/gs/io/fs/godoc.txt +370 -17
- package/gs/os/types_js.gs.ts +2 -2
- package/gs/os/types_unix.gs.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,594 +9,288 @@
|
|
|
9
9
|
[DeepWiki Widget]: https://img.shields.io/badge/DeepWiki-aperturerobotics%2Fgoscript-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==
|
|
10
10
|
[DeepWiki]: https://deepwiki.com/aperturerobotics/goscript
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## What is GoScript?
|
|
13
13
|
|
|
14
|
-
GoScript is a Go to TypeScript compiler
|
|
15
|
-
|
|
16
|
-
It works on translating Go to TypeScript on the AST level.
|
|
17
|
-
|
|
18
|
-
For detailed information on the compiler's design, refer to the [design document](./design/DESIGN.md).
|
|
14
|
+
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.
|
|
19
15
|
|
|
20
16
|
> 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.
|
|
21
17
|
>
|
|
22
18
|
> — [nevkontakte](https://gophers.slack.com/archives/C039C0R2T/p1745870396945719), developer of [GopherJS](https://github.com/gopherjs/gopherjs)
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
non-spec-compliant way. It is intended only for bringing over high-level logic
|
|
26
|
-
from Go to TypeScript, so not all programs will work correctly:
|
|
20
|
+
### ๐ฏ Why GoScript?
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
- Pointer arithmetic (uintptr) and unsafe are not supported
|
|
30
|
-
- Reflection is not supported
|
|
31
|
-
- Complex numbers are not supported
|
|
22
|
+
**Write once, run everywhere.** Share your Go algorithms, business logic, and data structures seamlessly between your backend and frontend without maintaining two codebases.
|
|
32
23
|
|
|
33
|
-
|
|
24
|
+
โ
**Perfect for:**
|
|
25
|
+
- Sharing business logic between Go services and web apps
|
|
26
|
+
- Porting Go algorithms to run in browsers
|
|
27
|
+
- Building TypeScript libraries from existing Go code
|
|
28
|
+
- Full-stack teams that love Go's simplicity
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
โ ๏ธ **What's supported:**
|
|
31
|
+
GoScript compiles a powerful subset of Go:
|
|
32
|
+
- Structs, interfaces, methods, and functions
|
|
33
|
+
- Channels and goroutines (translated to async/await)
|
|
34
|
+
- Slices, maps, and most built-in types
|
|
35
|
+
- Basic reflection support
|
|
36
|
+
- Standard control flow (if, for, switch, etc.)
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
**Current limitations:**
|
|
39
|
+
- Uses JavaScript `number` type (64-bit float, not Go's int types)
|
|
40
|
+
- No pointer arithmetic (`uintptr`) or `unsafe` package
|
|
41
|
+
- No complex numbers
|
|
42
|
+
- Limited standard library (growing rapidly)
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
If you're building algorithms, business logic, or data processing code, GoScript has you covered! ๐
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
๐ **Learn more:** [Design document](./design/DESIGN.md) | [Compliance tests](./compliance/COMPLIANCE.md)
|
|
42
47
|
|
|
48
|
+
## ๐ Get Started in 2 Minutes
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
**Option 1: Go Install**
|
|
43
53
|
```bash
|
|
44
|
-
|
|
45
|
-
--package "my/package" \
|
|
46
|
-
--output ./output
|
|
54
|
+
go install github.com/aperturerobotics/goscript/cmd/goscript@latest
|
|
47
55
|
```
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
**Option 2: NPM**
|
|
51
58
|
```bash
|
|
52
|
-
|
|
59
|
+
npm install -g goscript
|
|
53
60
|
```
|
|
54
|
-
|
|
61
|
+
|
|
62
|
+
### Your First Compilation
|
|
55
63
|
|
|
56
64
|
```bash
|
|
57
|
-
|
|
58
|
-
goscript compile --package . --output ./
|
|
65
|
+
# Compile your Go package to TypeScript
|
|
66
|
+
goscript compile --package . --output ./dist
|
|
59
67
|
```
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
## ๐ก See It In Action
|
|
62
70
|
|
|
63
|
-
|
|
71
|
+
### Example: User Management
|
|
64
72
|
|
|
73
|
+
**Go Code** (`user.go`):
|
|
65
74
|
```go
|
|
66
75
|
package main
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"github.com/sirupsen/logrus"
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
func main() {
|
|
77
|
-
// Initialize logger (optional)
|
|
78
|
-
logger := logrus.New()
|
|
79
|
-
logger.SetLevel(logrus.DebugLevel) // Adjust log level as needed
|
|
80
|
-
le := logrus.NewEntry(logger)
|
|
77
|
+
type User struct {
|
|
78
|
+
ID int `json:"id"`
|
|
79
|
+
Name string `json:"name"`
|
|
80
|
+
Email string `json:"email"`
|
|
81
|
+
}
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
if err := conf.Validate(); err != nil {
|
|
87
|
-
log.Fatalf("invalid compiler config: %v", err)
|
|
88
|
-
}
|
|
83
|
+
func (u *User) IsValid() bool {
|
|
84
|
+
return u.Name != "" && u.Email != ""
|
|
85
|
+
}
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
log.Fatalf("failed to create compiler: %v", err)
|
|
94
|
-
}
|
|
87
|
+
func NewUser(id int, name, email string) *User {
|
|
88
|
+
return &User{ID: id, Name: name, Email: email}
|
|
89
|
+
}
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
func FindUserByEmail(users []*User, email string) *User {
|
|
92
|
+
for _, user := range users {
|
|
93
|
+
if user.Email == email {
|
|
94
|
+
return user
|
|
95
|
+
}
|
|
100
96
|
}
|
|
101
|
-
|
|
102
|
-
log.Println("Compilation successful!")
|
|
97
|
+
return nil
|
|
103
98
|
}
|
|
104
|
-
|
|
105
99
|
```
|
|
106
100
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
### TypeScript API
|
|
110
|
-
|
|
111
|
-
You can also use GoScript programmatically within your Node.js projects.
|
|
112
|
-
|
|
113
|
-
**Installation:**
|
|
114
|
-
|
|
101
|
+
**Compile it:**
|
|
115
102
|
```bash
|
|
116
|
-
|
|
117
|
-
# or
|
|
118
|
-
yarn add goscript
|
|
103
|
+
goscript compile --package . --output ./dist
|
|
119
104
|
```
|
|
120
105
|
|
|
121
|
-
**
|
|
122
|
-
|
|
106
|
+
**Generated TypeScript** (`user.ts`):
|
|
123
107
|
```typescript
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
await compile({
|
|
133
|
-
pkg: '.', // Compile the package in the exampleDir
|
|
134
|
-
dir: exampleDir,
|
|
135
|
-
output: outputDir,
|
|
136
|
-
// Optional: specify path to goscript CLI if not in PATH or using go run
|
|
137
|
-
// goscriptPath: '/path/to/goscript/executable'
|
|
138
|
-
});
|
|
139
|
-
console.log(`Compilation successful! Output in ${outputDir}`);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
console.error('Compilation failed:', error);
|
|
108
|
+
export class User {
|
|
109
|
+
public ID: number = 0
|
|
110
|
+
public Name: string = ""
|
|
111
|
+
public Email: string = ""
|
|
112
|
+
|
|
113
|
+
public IsValid(): boolean {
|
|
114
|
+
const u = this
|
|
115
|
+
return u.Name !== "" && u.Email !== ""
|
|
142
116
|
}
|
|
143
|
-
}
|
|
144
117
|
|
|
145
|
-
|
|
146
|
-
|
|
118
|
+
constructor(init?: Partial<User>) {
|
|
119
|
+
if (init) Object.assign(this, init)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
147
122
|
|
|
148
|
-
|
|
123
|
+
export function NewUser(id: number, name: string, email: string): User {
|
|
124
|
+
return new User({ ID: id, Name: name, Email: email })
|
|
125
|
+
}
|
|
149
126
|
|
|
150
|
-
|
|
127
|
+
export function FindUserByEmail(users: User[], email: string): User | null {
|
|
128
|
+
for (let user of users) {
|
|
129
|
+
if (user.Email === email) {
|
|
130
|
+
return user
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
```
|
|
151
136
|
|
|
152
|
-
|
|
137
|
+
**Use in your frontend:**
|
|
138
|
+
```typescript
|
|
139
|
+
import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
|
|
153
140
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
- [ ] Generate init() function to recursively initialize packages
|
|
160
|
-
- [ ] Tooling to integrate with typescript compiler
|
|
161
|
-
- [ ] "go test" implementation with Go -> Ts transformation
|
|
162
|
-
- vitest
|
|
163
|
-
- [ ] performance testing
|
|
164
|
-
- [ ] examples of calling Go code from TypeScript
|
|
141
|
+
// Same logic, now in TypeScript!
|
|
142
|
+
const users = [
|
|
143
|
+
NewUser(1, "Alice", "alice@example.com"),
|
|
144
|
+
NewUser(2, "Bob", "bob@example.com")
|
|
145
|
+
]
|
|
165
146
|
|
|
166
|
-
|
|
147
|
+
const alice = FindUserByEmail(users, "alice@example.com")
|
|
148
|
+
console.log(alice?.IsValid()) // true
|
|
149
|
+
```
|
|
167
150
|
|
|
168
|
-
|
|
151
|
+
### Example: Async Processing with Channels
|
|
169
152
|
|
|
153
|
+
**Go Code:**
|
|
170
154
|
```go
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// GetMyString returns the MyString field.
|
|
185
|
-
func (m *MyStruct) GetMyString() string {
|
|
186
|
-
return m.MyString
|
|
155
|
+
func ProcessMessages(messages []string) chan string {
|
|
156
|
+
results := make(chan string, len(messages))
|
|
157
|
+
|
|
158
|
+
for _, msg := range messages {
|
|
159
|
+
go func(m string) {
|
|
160
|
+
// Simulate processing
|
|
161
|
+
processed := "โ " + m
|
|
162
|
+
results <- processed
|
|
163
|
+
}(msg)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return results
|
|
187
167
|
}
|
|
168
|
+
```
|
|
188
169
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
170
|
+
**Generated TypeScript:**
|
|
171
|
+
```typescript
|
|
172
|
+
export function ProcessMessages(messages: string[]): $.Channel<string> {
|
|
173
|
+
let results = $.makeChannel<string>(messages.length, "")
|
|
174
|
+
|
|
175
|
+
for (let msg of messages) {
|
|
176
|
+
queueMicrotask(async (m: string) => {
|
|
177
|
+
let processed = "โ " + m
|
|
178
|
+
await results.send(processed)
|
|
179
|
+
})(msg)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return results
|
|
192
183
|
}
|
|
184
|
+
```
|
|
193
185
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
186
|
+
**Use with async/await:**
|
|
187
|
+
```typescript
|
|
188
|
+
import { ProcessMessages } from '@goscript/myapp/processor'
|
|
198
189
|
|
|
199
|
-
|
|
200
|
-
|
|
190
|
+
async function handleMessages() {
|
|
191
|
+
const channel = ProcessMessages(["hello", "world", "goscript"])
|
|
192
|
+
|
|
193
|
+
// Receive processed messages
|
|
194
|
+
for (let i = 0; i < 3; i++) {
|
|
195
|
+
const result = await channel.receive()
|
|
196
|
+
console.log(result) // "โ hello", "โ world", "โ goscript"
|
|
197
|
+
}
|
|
201
198
|
}
|
|
199
|
+
```
|
|
202
200
|
|
|
203
|
-
|
|
204
|
-
println("Hello from GoScript example!")
|
|
205
|
-
|
|
206
|
-
// Basic arithmetic
|
|
207
|
-
a, b := 10, 3
|
|
208
|
-
println("Addition:", a+b, "Subtraction:", a-b, "Multiplication:", a*b, "Division:", a/b, "Modulo:", a%b)
|
|
209
|
-
|
|
210
|
-
// Boolean logic and comparisons
|
|
211
|
-
println("Logic &&:", true && false, "||:", true || false, "!:!", !true)
|
|
212
|
-
println("Comparisons:", a == b, a != b, a < b, a > b, a <= b, a >= b)
|
|
213
|
-
|
|
214
|
-
// string(rune) conversion
|
|
215
|
-
var r rune = 'X'
|
|
216
|
-
s := string(r)
|
|
217
|
-
println("string('X'):", s)
|
|
201
|
+
## ๐ ๏ธ Integration & Usage
|
|
218
202
|
|
|
219
|
-
|
|
220
|
-
s2 := string(r2)
|
|
221
|
-
println("string(121):", s2)
|
|
203
|
+
### Command Line
|
|
222
204
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
205
|
+
```bash
|
|
206
|
+
goscript compile --package ./my-go-code --output ./dist
|
|
207
|
+
```
|
|
226
208
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
209
|
+
**Options:**
|
|
210
|
+
- `--package <path>` - Go package to compile (default: ".")
|
|
211
|
+
- `--output <dir>` - Output directory for TypeScript files
|
|
230
212
|
|
|
231
|
-
|
|
232
|
-
slice := []int{4, 5, 6}
|
|
233
|
-
println("Slice elements:", slice[0], slice[1], slice[2])
|
|
234
|
-
println("Slice length:", len(slice), "capacity:", cap(slice))
|
|
235
|
-
|
|
236
|
-
sliceWithCap := make([]int, 3, 5)
|
|
237
|
-
println("\nSlice created with make([]int, 3, 5):")
|
|
238
|
-
println("Length:", len(sliceWithCap), "Capacity:", cap(sliceWithCap))
|
|
239
|
-
|
|
240
|
-
println("\nAppend and capacity growth:")
|
|
241
|
-
growingSlice := make([]int, 0, 2)
|
|
242
|
-
println("Initial - Length:", len(growingSlice), "Capacity:", cap(growingSlice))
|
|
243
|
-
|
|
244
|
-
for i := 1; i <= 4; i++ {
|
|
245
|
-
growingSlice = append(growingSlice, i)
|
|
246
|
-
println("After append", i, "- Length:", len(growingSlice), "Capacity:", cap(growingSlice))
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
println("\nSlicing operations and shared backing arrays:")
|
|
250
|
-
original := []int{10, 20, 30, 40, 50}
|
|
251
|
-
println("Original slice - Length:", len(original), "Capacity:", cap(original))
|
|
252
|
-
|
|
253
|
-
slice1 := original[1:3]
|
|
254
|
-
println("slice1 := original[1:3] - Values:", slice1[0], slice1[1])
|
|
255
|
-
println("slice1 - Length:", len(slice1), "Capacity:", cap(slice1))
|
|
256
|
-
|
|
257
|
-
slice2 := original[1:3:4]
|
|
258
|
-
println("slice2 := original[1:3:4] - Values:", slice2[0], slice2[1])
|
|
259
|
-
println("slice2 - Length:", len(slice2), "Capacity:", cap(slice2))
|
|
260
|
-
|
|
261
|
-
println("\nShared backing arrays:")
|
|
262
|
-
slice1[0] = 999
|
|
263
|
-
println("After slice1[0] = 999:")
|
|
264
|
-
println("original[1]:", original[1], "slice1[0]:", slice1[0], "slice2[0]:", slice2[0])
|
|
265
|
-
|
|
266
|
-
sum := 0
|
|
267
|
-
for idx, val := range slice {
|
|
268
|
-
sum += val
|
|
269
|
-
println("Range idx:", idx, "val:", val)
|
|
270
|
-
}
|
|
271
|
-
println("Range sum:", sum)
|
|
213
|
+
### Programmatic API
|
|
272
214
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
prod *= i
|
|
277
|
-
}
|
|
278
|
-
println("Product via for:", prod)
|
|
279
|
-
|
|
280
|
-
// Struct, pointers, copy independence
|
|
281
|
-
instance := NewMyStruct("go-script")
|
|
282
|
-
println("instance.MyString:", instance.GetMyString())
|
|
283
|
-
instance.MyInt = 42
|
|
284
|
-
copyInst := instance
|
|
285
|
-
copyInst.MyInt = 7
|
|
286
|
-
println("instance.MyInt:", instance.MyInt, "copyInst.MyInt:", copyInst.MyInt)
|
|
287
|
-
|
|
288
|
-
// Pointer initialization and dereference assignment
|
|
289
|
-
ptr := new(MyStruct)
|
|
290
|
-
ptr.MyInt = 9
|
|
291
|
-
println("ptr.MyInt:", ptr.MyInt)
|
|
292
|
-
deref := *ptr
|
|
293
|
-
deref.MyInt = 8
|
|
294
|
-
println("After deref assign, ptr.MyInt:", ptr.MyInt, "deref.MyInt:", deref.MyInt)
|
|
295
|
-
|
|
296
|
-
// Method calls on pointer receiver
|
|
297
|
-
ptr.myBool = true
|
|
298
|
-
println("ptr.GetMyBool():", ptr.GetMyBool())
|
|
299
|
-
|
|
300
|
-
// Composite literal assignment
|
|
301
|
-
comp := MyStruct{MyInt: 100, MyString: "composite", myBool: false}
|
|
302
|
-
println("comp fields:", comp.MyInt, comp.GetMyString(), comp.GetMyBool())
|
|
303
|
-
|
|
304
|
-
// Multiple return values and blank identifier
|
|
305
|
-
x, _ := vals()
|
|
306
|
-
_, y := vals()
|
|
307
|
-
println("vals x:", x, "y:", y)
|
|
308
|
-
|
|
309
|
-
// If/else
|
|
310
|
-
if a > b {
|
|
311
|
-
println("If branch: a>b")
|
|
312
|
-
} else {
|
|
313
|
-
println("Else branch: a<=b")
|
|
314
|
-
}
|
|
215
|
+
**Go:**
|
|
216
|
+
```go
|
|
217
|
+
import "github.com/aperturerobotics/goscript/compiler"
|
|
315
218
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
default:
|
|
321
|
-
println("Switch default")
|
|
322
|
-
}
|
|
219
|
+
conf := &compiler.Config{OutputPath: "./dist"}
|
|
220
|
+
comp, err := compiler.NewCompiler(conf, logger, nil)
|
|
221
|
+
_, err = comp.CompilePackages(ctx, "your/package/path")
|
|
222
|
+
```
|
|
323
223
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
go func() {
|
|
328
|
-
println("Goroutine: Sending message")
|
|
329
|
-
ch <- "Hello from goroutine!"
|
|
330
|
-
}()
|
|
331
|
-
|
|
332
|
-
msg := <-ch
|
|
333
|
-
println("Main goroutine: Received message:", msg)
|
|
334
|
-
|
|
335
|
-
// Select statement
|
|
336
|
-
println("\nSelect statement:")
|
|
337
|
-
selectCh := make(chan string)
|
|
338
|
-
go func() {
|
|
339
|
-
selectCh <- "Message from select goroutine!"
|
|
340
|
-
}()
|
|
341
|
-
anotherCh := make(chan string)
|
|
342
|
-
select {
|
|
343
|
-
case selectMsg := <-selectCh:
|
|
344
|
-
println("Select received:", selectMsg)
|
|
345
|
-
case anotherMsg := <-anotherCh: // Add another case
|
|
346
|
-
println("Select received from another channel:", anotherMsg)
|
|
347
|
-
}
|
|
224
|
+
**Node.js:**
|
|
225
|
+
```typescript
|
|
226
|
+
import { compile } from 'goscript'
|
|
348
227
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
sum = add(5, 7)
|
|
355
|
-
println("Function literal result:", sum)
|
|
356
|
-
}
|
|
228
|
+
await compile({
|
|
229
|
+
pkg: './my-go-package',
|
|
230
|
+
output: './dist'
|
|
231
|
+
})
|
|
357
232
|
```
|
|
358
233
|
|
|
359
|
-
|
|
234
|
+
### Frontend Frameworks
|
|
360
235
|
|
|
236
|
+
**React + GoScript:**
|
|
361
237
|
```typescript
|
|
362
|
-
import
|
|
363
|
-
|
|
364
|
-
class MyStruct {
|
|
365
|
-
// MyInt is a public integer field, initialized to zero.
|
|
366
|
-
public MyInt: number = 0
|
|
367
|
-
// MyString is a public string field, initialized to empty string.
|
|
368
|
-
public MyString: string = ""
|
|
369
|
-
// myBool is a private boolean field, initialized to false.
|
|
370
|
-
private myBool: boolean = false
|
|
371
|
-
|
|
372
|
-
// GetMyString returns the MyString field.
|
|
373
|
-
public GetMyString(): string {
|
|
374
|
-
const m = this
|
|
375
|
-
return m.MyString
|
|
376
|
-
}
|
|
238
|
+
import { NewCalculator } from '@goscript/myapp/calculator'
|
|
377
239
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
240
|
+
function CalculatorApp() {
|
|
241
|
+
const [calc] = useState(() => NewCalculator())
|
|
242
|
+
|
|
243
|
+
const handleAdd = () => {
|
|
244
|
+
const result = calc.Add(5, 3)
|
|
245
|
+
setResult(result)
|
|
382
246
|
}
|
|
383
247
|
|
|
384
|
-
|
|
385
|
-
public clone(): MyStruct { return Object.assign(Object.create(MyStruct.prototype) as MyStruct, this) }
|
|
248
|
+
return <button onClick={handleAdd}>Add 5 + 3</button>
|
|
386
249
|
}
|
|
250
|
+
```
|
|
387
251
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
252
|
+
**Vue + GoScript:**
|
|
253
|
+
```vue
|
|
254
|
+
<script setup lang="ts">
|
|
255
|
+
import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
|
|
256
|
+
|
|
257
|
+
const users = ref([
|
|
258
|
+
NewUser(1, "Alice", "alice@example.com")
|
|
259
|
+
])
|
|
392
260
|
|
|
393
|
-
|
|
394
|
-
return
|
|
261
|
+
const searchUser = (email: string) => {
|
|
262
|
+
return FindUserByEmail(users.value, email)
|
|
395
263
|
}
|
|
264
|
+
</script>
|
|
265
|
+
```
|
|
396
266
|
|
|
397
|
-
|
|
398
|
-
console.log("Hello from GoScript example!")
|
|
399
|
-
|
|
400
|
-
// Basic arithmetic
|
|
401
|
-
let a = 10
|
|
402
|
-
let b = 3
|
|
403
|
-
console.log("Addition:", a + b, "Subtraction:", a - b, "Multiplication:", a * b, "Division:", a / b, "Modulo:", a % b)
|
|
404
|
-
|
|
405
|
-
// Boolean logic and comparisons
|
|
406
|
-
console.log("Logic &&:", true && false, "||:", true || false, "!:!", !true)
|
|
407
|
-
console.log("Comparisons:", a == b, a != b, a < b, a > b, a <= b, a >= b)
|
|
408
|
-
|
|
409
|
-
// string(rune) conversion
|
|
410
|
-
let r: number = 'X'
|
|
411
|
-
let s = String.fromCharCode(r)
|
|
412
|
-
console.log("string('X'):", s)
|
|
413
|
-
|
|
414
|
-
// 'y'
|
|
415
|
-
let r2: number = 121
|
|
416
|
-
let s2 = String.fromCharCode(r2)
|
|
417
|
-
console.log("string(121):", s2)
|
|
418
|
-
|
|
419
|
-
// 'โ'
|
|
420
|
-
let r3: number = 0x221A
|
|
421
|
-
let s3 = String.fromCharCode(r3)
|
|
422
|
-
console.log("string(0x221A):", s3)
|
|
423
|
-
|
|
424
|
-
// Arrays
|
|
425
|
-
let arr = $.arrayToSlice([1, 2, 3])
|
|
426
|
-
console.log("Array elements:", arr![0], arr![1], arr![2])
|
|
427
|
-
|
|
428
|
-
// Slices - Basic initialization and access
|
|
429
|
-
let slice = $.arrayToSlice([4, 5, 6])
|
|
430
|
-
console.log("Slice elements:", slice![0], slice![1], slice![2])
|
|
431
|
-
console.log("Slice length:", $.len(slice), "capacity:", $.cap(slice))
|
|
432
|
-
|
|
433
|
-
let sliceWithCap = $.makeSlice<number>(3, 5)
|
|
434
|
-
console.log("\nSlice created with make([]int, 3, 5):")
|
|
435
|
-
console.log("Length:", $.len(sliceWithCap), "Capacity:", $.cap(sliceWithCap))
|
|
436
|
-
|
|
437
|
-
console.log("\nAppend and capacity growth:")
|
|
438
|
-
let growingSlice = $.makeSlice<number>(0, 2)
|
|
439
|
-
console.log("Initial - Length:", $.len(growingSlice), "Capacity:", $.cap(growingSlice))
|
|
440
|
-
|
|
441
|
-
for (let i = 1; i <= 4; i++) {
|
|
442
|
-
growingSlice = $.append(growingSlice, i)
|
|
443
|
-
console.log("After append", i, "- Length:", $.len(growingSlice), "Capacity:", $.cap(growingSlice))
|
|
444
|
-
}
|
|
267
|
+
## ๐ What's Next?
|
|
445
268
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
console.log("slice1 := original[1:3] - Values:", slice1![0], slice1![1])
|
|
452
|
-
console.log("slice1 - Length:", $.len(slice1), "Capacity:", $.cap(slice1))
|
|
453
|
-
|
|
454
|
-
let slice2 = $.goSlice(original, 1, 3, 4)
|
|
455
|
-
console.log("slice2 := original[1:3:4] - Values:", slice2![0], slice2![1])
|
|
456
|
-
console.log("slice2 - Length:", $.len(slice2), "Capacity:", $.cap(slice2))
|
|
457
|
-
|
|
458
|
-
console.log("\nShared backing arrays:")
|
|
459
|
-
slice1![0] = 999
|
|
460
|
-
console.log("After slice1[0] = 999:")
|
|
461
|
-
console.log("original[1]:", original![1], "slice1[0]:", slice1![0], "slice2[0]:", slice2![0])
|
|
462
|
-
|
|
463
|
-
let sum = 0
|
|
464
|
-
for (let idx = 0; idx < slice.length; idx++) {
|
|
465
|
-
const val = slice[idx]
|
|
466
|
-
{
|
|
467
|
-
sum += val
|
|
468
|
-
console.log("Range idx:", idx, "val:", val)
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
console.log("Range sum:", sum)
|
|
269
|
+
**Current Status:**
|
|
270
|
+
- โ
Core language features (structs, methods, interfaces)
|
|
271
|
+
- โ
Async/await for goroutines and channels
|
|
272
|
+
- โ
Basic reflection support
|
|
273
|
+
- โ
Most control flow and data types
|
|
472
274
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
console.log("Product via for:", prod)
|
|
479
|
-
|
|
480
|
-
// Struct, pointers, copy independence
|
|
481
|
-
let instance = NewMyStruct("go-script").clone()
|
|
482
|
-
console.log("instance.MyString:", instance.GetMyString())
|
|
483
|
-
instance.MyInt = 42
|
|
484
|
-
let copyInst = instance.clone()
|
|
485
|
-
copyInst.MyInt = 7
|
|
486
|
-
console.log("instance.MyInt:", instance.MyInt, "copyInst.MyInt:", copyInst.MyInt)
|
|
487
|
-
|
|
488
|
-
// Pointer initialization and dereference assignment
|
|
489
|
-
let ptr = new MyStruct()
|
|
490
|
-
ptr.MyInt = 9
|
|
491
|
-
console.log("ptr.MyInt:", ptr.MyInt)
|
|
492
|
-
let deref = ptr.clone()
|
|
493
|
-
deref.MyInt = 8
|
|
494
|
-
console.log("After deref assign, ptr.MyInt:", ptr.MyInt, "deref.MyInt:", deref.MyInt)
|
|
495
|
-
|
|
496
|
-
// Method calls on pointer receiver
|
|
497
|
-
ptr.myBool = true
|
|
498
|
-
console.log("ptr.GetMyBool():", ptr.GetMyBool())
|
|
499
|
-
|
|
500
|
-
// Composite literal assignment
|
|
501
|
-
let comp = new MyStruct({ MyInt: 100, MyString: "composite", myBool: false }).clone()
|
|
502
|
-
console.log("comp fields:", comp.MyInt, comp.GetMyString(), comp.GetMyBool())
|
|
503
|
-
|
|
504
|
-
// Multiple return values and blank identifier
|
|
505
|
-
let [x, ] = vals()
|
|
506
|
-
let [, y] = vals()
|
|
507
|
-
console.log("vals x:", x, "y:", y)
|
|
508
|
-
|
|
509
|
-
// If/else
|
|
510
|
-
if (a > b) {
|
|
511
|
-
console.log("If branch: a>b")
|
|
512
|
-
} else {
|
|
513
|
-
console.log("Else branch: a<=b")
|
|
514
|
-
}
|
|
275
|
+
**Coming Soon:**
|
|
276
|
+
- ๐ฆ Expanded standard library
|
|
277
|
+
- ๐งช Go test โ TypeScript test conversion
|
|
278
|
+
- โก Performance optimizations
|
|
279
|
+
- ๐ง Better tooling integration
|
|
515
280
|
|
|
516
|
-
|
|
517
|
-
switch (a) {
|
|
518
|
-
case 10:
|
|
519
|
-
console.log("Switch case 10")
|
|
520
|
-
break
|
|
521
|
-
default:
|
|
522
|
-
console.log("Switch default")
|
|
523
|
-
break
|
|
524
|
-
}
|
|
281
|
+
Check our [compliance tests](./compliance/COMPLIANCE.md) for detailed progress.
|
|
525
282
|
|
|
526
|
-
|
|
527
|
-
console.log("\nGoroutines and Channels:")
|
|
528
|
-
let ch = $.makeChannel<string>(0, "")
|
|
529
|
-
queueMicrotask(async () => {
|
|
530
|
-
{
|
|
531
|
-
console.log("Goroutine: Sending message")
|
|
532
|
-
await ch.send("Hello from goroutine!")
|
|
533
|
-
}
|
|
534
|
-
})
|
|
283
|
+
## ๐ค Real-World Use Cases
|
|
535
284
|
|
|
536
|
-
|
|
537
|
-
console.log("Main goroutine: Received message:", msg)
|
|
285
|
+
**Fintech:** Share complex financial calculations between Go services and trading dashboards
|
|
538
286
|
|
|
539
|
-
|
|
540
|
-
console.log("\nSelect statement:")
|
|
541
|
-
let selectCh = $.makeChannel<string>(0, "")
|
|
542
|
-
queueMicrotask(async () => {
|
|
543
|
-
{
|
|
544
|
-
await selectCh.send("Message from select goroutine!")
|
|
545
|
-
}
|
|
546
|
-
})
|
|
547
|
-
let anotherCh = $.makeChannel<string>(0, "")
|
|
548
|
-
|
|
549
|
-
// Add another case
|
|
550
|
-
await $.selectStatement([
|
|
551
|
-
{
|
|
552
|
-
id: 0,
|
|
553
|
-
isSend: false,
|
|
554
|
-
channel: selectCh,
|
|
555
|
-
onSelected: async (result) => {
|
|
556
|
-
const selectMsg = result.value
|
|
557
|
-
console.log("Select received:", selectMsg)
|
|
558
|
-
}
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
id: 1,
|
|
562
|
-
isSend: false,
|
|
563
|
-
channel: anotherCh,
|
|
564
|
-
onSelected: async (result) => {
|
|
565
|
-
const anotherMsg = result.value
|
|
566
|
-
console.log("Select received from another channel:", anotherMsg)
|
|
567
|
-
}
|
|
568
|
-
},
|
|
569
|
-
], false)
|
|
570
|
-
|
|
571
|
-
// Function Literals
|
|
572
|
-
console.log("\nFunction Literals:")
|
|
573
|
-
let add = (x: number, y: number): number => {
|
|
574
|
-
return x + y
|
|
575
|
-
}
|
|
576
|
-
sum = add(5, 7)
|
|
577
|
-
console.log("Function literal result:", sum)
|
|
578
|
-
}
|
|
579
|
-
```
|
|
287
|
+
**Gaming:** Run the same game logic on servers and in browser clients
|
|
580
288
|
|
|
581
|
-
|
|
289
|
+
**Data Processing:** Use identical algorithms for backend ETL and frontend analytics
|
|
582
290
|
|
|
583
|
-
|
|
291
|
+
**Validation:** Keep business rules consistent across your entire stack
|
|
584
292
|
|
|
585
|
-
|
|
586
|
-
import { MyAsyncFunction, MyStruct } from '@goscript/github.com/myorg/mypackage';
|
|
587
|
-
|
|
588
|
-
// Example of importing and using a compiled Go async function
|
|
589
|
-
async function runGoCode() {
|
|
590
|
-
// Call an async function compiled from Go
|
|
591
|
-
const result = await MyAsyncFunction("input data");
|
|
592
|
-
console.log("Result from Go async function:", result);
|
|
593
|
-
|
|
594
|
-
// You can still use synchronous types and functions
|
|
595
|
-
let myThing = new MyStruct();
|
|
596
|
-
myThing.GetMyString();
|
|
597
|
-
runGoCode();
|
|
598
|
-
}
|
|
599
|
-
```
|
|
293
|
+
Ready to eliminate code duplication? [Get started now](#-get-started-in-2-minutes) ๐
|
|
600
294
|
|
|
601
295
|
## License
|
|
602
296
|
|