goscript 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +41 -0
  2. package/builtin/builtin.ts +368 -348
  3. package/compiler/compile_expr.go +3 -37
  4. package/compiler/index.test.ts +29 -0
  5. package/compiler/index.ts +85 -0
  6. package/dist/builtin/builtin.d.ts +168 -0
  7. package/dist/builtin/builtin.js +372 -0
  8. package/dist/builtin/builtin.js.map +1 -0
  9. package/dist/compiler/index.d.ts +26 -0
  10. package/dist/compiler/index.js +64 -0
  11. package/dist/compiler/index.js.map +1 -0
  12. package/package.json +68 -3
  13. package/.aider-prompt +0 -11
  14. package/compliance/COMPLIANCE.md +0 -133
  15. package/compliance/compliance.go +0 -313
  16. package/compliance/compliance_test.go +0 -57
  17. package/compliance/tests/array_literal/array_literal.go +0 -15
  18. package/compliance/tests/array_literal/array_literal.gs.ts +0 -19
  19. package/compliance/tests/array_literal/expected.log +0 -3
  20. package/compliance/tests/async_basic/async_basic.go +0 -26
  21. package/compliance/tests/async_basic/async_basic.gs.ts +0 -30
  22. package/compliance/tests/async_basic/expected.log +0 -1
  23. package/compliance/tests/basic_arithmetic/basic_arithmetic.go +0 -15
  24. package/compliance/tests/basic_arithmetic/basic_arithmetic.gs.ts +0 -19
  25. package/compliance/tests/basic_arithmetic/expected.log +0 -5
  26. package/compliance/tests/boolean_logic/boolean_logic.go +0 -13
  27. package/compliance/tests/boolean_logic/boolean_logic.gs.ts +0 -17
  28. package/compliance/tests/boolean_logic/expected.log +0 -3
  29. package/compliance/tests/channel_basic/channel_basic.go +0 -12
  30. package/compliance/tests/channel_basic/channel_basic.gs.ts +0 -18
  31. package/compliance/tests/channel_basic/expected.log +0 -1
  32. package/compliance/tests/composite_literal_assignment/composite_literal_assignment.go +0 -20
  33. package/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.ts +0 -27
  34. package/compliance/tests/composite_literal_assignment/expected.log +0 -2
  35. package/compliance/tests/constants/constants.go +0 -18
  36. package/compliance/tests/constants/constants.gs.ts +0 -22
  37. package/compliance/tests/constants/expected.log +0 -3
  38. package/compliance/tests/copy_independence/copy_independence.go +0 -29
  39. package/compliance/tests/copy_independence/copy_independence.gs.ts +0 -36
  40. package/compliance/tests/copy_independence/expected.log +0 -4
  41. package/compliance/tests/float64/expected.log +0 -6
  42. package/compliance/tests/float64/float64.go +0 -28
  43. package/compliance/tests/float64/float64.gs.ts +0 -32
  44. package/compliance/tests/for_loop_basic/expected.log +0 -5
  45. package/compliance/tests/for_loop_basic/for_loop_basic.go +0 -9
  46. package/compliance/tests/for_loop_basic/for_loop_basic.gs.ts +0 -13
  47. package/compliance/tests/for_loop_condition_only/expected.log +0 -5
  48. package/compliance/tests/for_loop_condition_only/main.go +0 -9
  49. package/compliance/tests/for_loop_condition_only/main.gs.ts +0 -13
  50. package/compliance/tests/for_range/expected.log +0 -9
  51. package/compliance/tests/for_range/for_range.go +0 -26
  52. package/compliance/tests/for_range/for_range.gs.ts +0 -45
  53. package/compliance/tests/for_range_index_use/expected.log +0 -6
  54. package/compliance/tests/for_range_index_use/for_range_index_use.go +0 -11
  55. package/compliance/tests/for_range_index_use/for_range_index_use.gs.ts +0 -18
  56. package/compliance/tests/func_literal/expected.log +0 -1
  57. package/compliance/tests/func_literal/func_literal.go +0 -10
  58. package/compliance/tests/func_literal/func_literal.gs.ts +0 -15
  59. package/compliance/tests/function_call_result_assignment/expected.log +0 -2
  60. package/compliance/tests/function_call_result_assignment/function_call_result_assignment.go +0 -24
  61. package/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.ts +0 -31
  62. package/compliance/tests/if_statement/expected.log +0 -1
  63. package/compliance/tests/if_statement/if_statement.go +0 -11
  64. package/compliance/tests/if_statement/if_statement.gs.ts +0 -15
  65. package/compliance/tests/interface_to_interface_type_assertion/expected.log +0 -1
  66. package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.go +0 -30
  67. package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.ts +0 -41
  68. package/compliance/tests/interface_type_assertion/expected.log +0 -1
  69. package/compliance/tests/interface_type_assertion/interface_type_assertion.go +0 -26
  70. package/compliance/tests/interface_type_assertion/interface_type_assertion.gs.ts +0 -36
  71. package/compliance/tests/map_support/expected.log +0 -13
  72. package/compliance/tests/map_support/map_support.go +0 -89
  73. package/compliance/tests/map_support/map_support.gs.ts +0 -102
  74. package/compliance/tests/method_call_on_pointer_receiver/expected.log +0 -1
  75. package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.go +0 -19
  76. package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.ts +0 -27
  77. package/compliance/tests/method_call_on_pointer_via_value/expected.log +0 -1
  78. package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.go +0 -29
  79. package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.ts +0 -38
  80. package/compliance/tests/method_call_on_value_receiver/expected.log +0 -1
  81. package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.go +0 -16
  82. package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.ts +0 -24
  83. package/compliance/tests/method_call_on_value_via_pointer/expected.log +0 -2
  84. package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.go +0 -30
  85. package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.ts +0 -38
  86. package/compliance/tests/multiple_return_values/expected.log +0 -6
  87. package/compliance/tests/multiple_return_values/multiple_return_values.go +0 -19
  88. package/compliance/tests/multiple_return_values/multiple_return_values.gs.ts +0 -23
  89. package/compliance/tests/pointer_assignment_no_copy/expected.log +0 -2
  90. package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.go +0 -28
  91. package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.ts +0 -35
  92. package/compliance/tests/pointer_composite_literal_assignment/expected.log +0 -3
  93. package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.go +0 -23
  94. package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.ts +0 -30
  95. package/compliance/tests/pointer_deref_multiassign/expected.log +0 -0
  96. package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.go +0 -17
  97. package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.ts +0 -27
  98. package/compliance/tests/pointer_initialization/expected.log +0 -1
  99. package/compliance/tests/pointer_initialization/pointer_initialization.go +0 -16
  100. package/compliance/tests/pointer_initialization/pointer_initialization.gs.ts +0 -22
  101. package/compliance/tests/select_receive_on_closed_channel_no_default/expected.log +0 -1
  102. package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.go +0 -15
  103. package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.ts +0 -31
  104. package/compliance/tests/select_send_on_full_buffered_channel_with_default/expected.log +0 -1
  105. package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.go +0 -13
  106. package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.ts +0 -35
  107. package/compliance/tests/select_statement/expected.log +0 -9
  108. package/compliance/tests/select_statement/select_statement.go +0 -109
  109. package/compliance/tests/select_statement/select_statement.gs.ts +0 -239
  110. package/compliance/tests/simple/expected.log +0 -1
  111. package/compliance/tests/simple/simple.go +0 -5
  112. package/compliance/tests/simple/simple.gs.ts +0 -9
  113. package/compliance/tests/simple_deref_assignment/expected.log +0 -2
  114. package/compliance/tests/simple_deref_assignment/simple_deref_assignment.go +0 -19
  115. package/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.ts +0 -26
  116. package/compliance/tests/slices/expected.log +0 -7
  117. package/compliance/tests/slices/slices.go +0 -22
  118. package/compliance/tests/slices/slices.gs.ts +0 -26
  119. package/compliance/tests/string_rune_conversion/expected.log +0 -3
  120. package/compliance/tests/string_rune_conversion/string_rune_conversion.go +0 -16
  121. package/compliance/tests/string_rune_conversion/string_rune_conversion.gs.ts +0 -22
  122. package/compliance/tests/struct_field_access/expected.log +0 -2
  123. package/compliance/tests/struct_field_access/struct_field_access.go +0 -13
  124. package/compliance/tests/struct_field_access/struct_field_access.gs.ts +0 -20
  125. package/compliance/tests/struct_value_init_clone/expected.log +0 -5
  126. package/compliance/tests/struct_value_init_clone/struct_value_init_clone.go +0 -28
  127. package/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.ts +0 -35
  128. package/compliance/tests/switch_statement/expected.log +0 -14
  129. package/compliance/tests/switch_statement/switch_statement.go +0 -59
  130. package/compliance/tests/switch_statement/switch_statement.gs.ts +0 -85
  131. package/compliance/tests/value_type_copy_behavior/expected.log +0 -3
  132. package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.go +0 -25
  133. package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.ts +0 -34
  134. package/design/DESIGN.md +0 -599
  135. package/example/simple/build.bash +0 -10
  136. package/example/simple/go.mod +0 -23
  137. package/example/simple/go.sum +0 -39
  138. package/example/simple/main.go +0 -138
  139. package/example/simple/main.gs.ts +0 -133
  140. package/example/simple/main.ts +0 -3
  141. package/example/simple/main_test.go +0 -59
  142. package/example/simple/main_tools.go +0 -5
  143. package/example/simple/package.json +0 -7
  144. package/example/simple/run.bash +0 -6
  145. package/example/simple/tsconfig.json +0 -28
  146. package/example/simple/yarn.lock +0 -8
  147. package/output/output.go +0 -10
  148. package/tsconfig.json +0 -10
  149. package/types/tokens.go +0 -65
  150. package/types/types.go +0 -46
package/design/DESIGN.md DELETED
@@ -1,599 +0,0 @@
1
- # Package Structure
2
-
3
- This is the typical package structure of the output TypeScript import path:
4
-
5
- ```
6
- @go/ # Typical Go workspace, all packages live here. Includes the '@go/builtin' alias for the runtime.
7
- # Compiled Go packages go here (e.g., @go/my/package)
8
- ```
9
-
10
- # Go to TypeScript Compiler Design
11
-
12
- ## Naming Conventions
13
-
14
- - **Exported Identifiers:** Go identifiers (functions, types, variables, struct fields, interface methods) that are exported (start with an uppercase letter) retain their original PascalCase naming in the generated TypeScript code. For example, `MyFunction` in Go becomes `export function MyFunction(...)` in TypeScript, and `MyStruct.MyField` becomes `MyStruct.MyField`.
15
- - **Unexported Identifiers:** Go identifiers that are unexported (start with a lowercase letter) retain their original camelCase naming but are typically not directly accessible in the generated TypeScript unless they are part of an exported struct's definition (where they might become private fields).
16
- - **Keywords:** Go keywords are generally not an issue, but care must be taken if a Go identifier clashes with a TypeScript keyword.
17
-
18
- ## Type Mapping
19
- - **Built-in Types:** Go built-in types are mapped to corresponding TypeScript types (e.g., `string` -> `string`, `int` -> `number`, `bool` -> `boolean`).
20
- - **String and Rune Conversions:** Go's `rune` type (an alias for `int32` representing a Unicode code point) and its interaction with `string` are handled as follows:
21
- - **`rune` Type:** Translated to TypeScript `number`.
22
- - **`string(rune)` Conversion:** The Go conversion from a `rune` to a `string` containing that single character is translated using `String.fromCharCode()`:
23
- ```go
24
- var r rune = 'A' // Unicode point 65
25
- s := string(r)
26
- ```
27
- becomes:
28
- ```typescript
29
- let r: number = 65
30
- let s = String.fromCharCode(r) // s becomes "A"
31
- ```
32
- - **`[]rune(string)` Conversion:** Converting a `string` to a slice of `rune`s requires a runtime helper to correctly handle multi-byte Unicode characters:
33
- ```go
34
- runes := []rune("Go€")
35
- ```
36
- becomes (conceptual translation using a runtime helper):
37
- ```typescript
38
- import * as goscript from "@go/builtin"
39
- let runes = goscript.stringToRunes("Go€") // runes becomes [71, 111, 8364]
40
- ```
41
- *(This helper was also seen in the `for range` over strings translation).*
42
- - **`string([]rune)` Conversion:** Converting a slice of `rune`s back to a `string` also requires a runtime helper:
43
- ```go
44
- s := string([]rune{71, 111, 8364})
45
- ```
46
- becomes (conceptual translation using a runtime helper):
47
- ```typescript
48
- import * as goscript from "@go/builtin"
49
- let s = goscript.runesToString([71, 111, 8364]) // s becomes "Go€"
50
- ```
51
- *Note: Direct conversion between `string` and `[]byte` would involve different runtime helpers focusing on byte representations.*
52
-
53
- - **Structs:** Converted to TypeScript `class`es. Exported fields become `public` members, unexported fields become `private` members. A `clone()` method is added to support Go's value semantics on assignment.
54
- - **Field Access:** Accessing exported struct fields uses standard TypeScript dot notation (`instance.FieldName`). Go's automatic dereferencing for pointer field access (`ptr.Field`) translates to using optional chaining (`ptr?.FieldName`) in TypeScript due to the `T | null` pointer mapping. Unexported fields become `private` class members and are generally not accessible from outside the class.
55
- - **Struct Composite Literals:**
56
- - **Value Initialization (`T{...}`):** Initializing a struct value translates directly to creating a new instance of the corresponding TypeScript class using its constructor.
57
- ```go
58
- type Point struct{ X, Y int }
59
- v := Point{X: 1, Y: 2} // v is Point
60
- ```
61
- becomes:
62
- ```typescript
63
- class Point { /* ... constructor, fields, clone ... */ }
64
- let v = new Point({ X: 1, Y: 2 }) // v is Point
65
- ```
66
- *Note: Assigning from a composite literal value (`T{...}`) directly to a variable (`v := T{...}` or `var v = T{...}`) translates to `new Type(...)` without an immediate `.clone()`. For assignments from *other* struct values, `.clone()` is invoked to ensure the assigned variable holds an independent copy, as per the "Value Semantics" section.*
67
- - **Pointer Initialization (`&T{...}`):** Initializing a pointer to a struct using a composite literal with the address-of operator (`&`) also translates directly to creating a new class instance. The resulting TypeScript object represents the non-null pointer value.
68
- ```go
69
- p := &Point{X: 1, Y: 2} // p is *Point
70
- ```
71
- becomes:
72
- ```typescript
73
- let p = new Point({ X: 1, Y: 2 }) // p is Point (representing the non-null pointer case)
74
- ```
75
- *Note: The distinction between pointer and value initialization in Go is primarily relevant for assignment semantics (cloning for values) and method receiver types, rather than the initial object creation in TypeScript.*
76
- - **Pointers (`*T`):** Mapped to TypeScript union types (`T | null`).
77
- - **Interfaces:** Mapped to TypeScript `interface` types. Methods retain their original Go casing.
78
- - **Type Assertions:** Go's type assertion allows checking the underlying concrete type of an interface variable and extracting it. This requires runtime type information.
79
- - **Comma-Ok Assertion (`v, ok := i.(T)`):** This form checks if interface `i` holds a value of concrete type `T`. If it does, `ok` is `true` and `v` gets the value of type `T`. Otherwise, `ok` is `false` and `v` gets the zero value for type `T`. This requires a runtime check, likely via a helper function.
80
- ```go
81
- var i MyInterface = MyStruct{Value: 10}
82
- s, ok := i.(MyStruct)
83
- if ok {
84
- // use s (type MyStruct)
85
- }
86
- ```
87
- becomes (conceptual translation using a runtime helper):
88
- ```typescript
89
- import * as goscript from "@go/builtin"
90
-
91
- let i: MyInterface = new MyStruct({ Value: 10 }).clone()
92
- // goscript.typeAssert returns [value, ok] tuple
93
- let [s, ok] = goscript.typeAssert<MyStruct>(i, MyStruct) // Runtime helper needed
94
- if (ok) {
95
- // use s (type MyStruct | null, non-null if ok is true)
96
- }
97
- ```
98
- *Note: A runtime helper (e.g., `goscript.typeAssert`) is necessary because TypeScript interfaces are structural and erased at runtime. Simple casting (`as T`) or operators like `instanceof` (only for classes) or `satisfies` (compile-time only) are insufficient to fully replicate Go's runtime behavior.*
99
-
100
- - **Panic Assertion (`v := i.(T)`):** This form asserts that `i` holds type `T`. If the assertion fails, it panics. This would also translate using a runtime helper that throws an error or mimics Go's panic on failure.
101
- - **Slices:** Go slices (`[]T`) are mapped to standard TypeScript arrays (`T[]`). However, Go's slice semantics, particularly regarding length, capacity, and creation with `make`, require runtime support.
102
- - **Creation (`make`):** `make([]T, len)` and `make([]T, len, cap)` are translated using a runtime helper `makeSlice`:
103
- ```go
104
- s1 := make([]int, 5)
105
- s2 := make([]int, 5, 10)
106
- ```
107
- becomes:
108
- ```typescript
109
- import * as goscript from "@go/builtin"
110
- let s1 = goscript.makeSlice("int", 5) // Creates array of length 5, capacity 5
111
- let s2 = goscript.makeSlice("int", 5, 10) // Creates array of length 5, capacity 10 (runtime handles capacity)
112
- ```
113
- *Note: The runtime (`@go/builtin`) likely manages the capacity concept internally, as standard TypeScript arrays don't have explicit capacity.*
114
- - **Literals:** Slice literals are translated directly to TypeScript array literals:
115
- ```go
116
- s := []int{1, 2, 3}
117
- ```
118
- becomes:
119
- ```typescript
120
- let s = [1, 2, 3]
121
- ```
122
- - **Length (`len(s)`):** Uses a runtime helper `len`:
123
- ```go
124
- l := len(s)
125
- ```
126
- becomes:
127
- ```typescript
128
- let l = goscript.len(s) // Not s.length directly, to potentially handle nil slices correctly
129
- ```
130
- - **Capacity (`cap(s)`):** Uses a runtime helper `cap`:
131
- ```go
132
- c := cap(s)
133
- ```
134
- becomes:
135
- ```typescript
136
- let c = goscript.cap(s) // Runtime provides capacity info
137
- ```
138
- - **Access/Assignment (`s[i]`):** Translated directly using standard TypeScript array indexing.
139
- - **Append (`append(s, ...)`):** Requires a runtime helper `append` to handle potential resizing and capacity changes according to Go rules. (This is assumed based on Go semantics, though not explicitly in this specific test).
140
- - **Slicing (`s[low:high]`):** Requires runtime support to correctly handle Go's slicing behavior, which creates a new slice header sharing the underlying array. (Assumed, not in this test).
141
- - **Arrays:** Go arrays (e.g., `[5]int`) have a fixed size known at compile time. They are also mapped to TypeScript arrays (`T[]`), but their fixed-size nature is enforced during compilation (e.g., preventing `append`).
142
-
143
- *Note: The distinction between slices and arrays in Go is important. While both map to TypeScript arrays, runtime helpers are essential for emulating slice-specific behaviors like `make`, `len`, `cap`, `append`, and sub-slicing.*
144
- - **Maps:** Go maps (`map[K]V`) are translated to TypeScript's standard `Map<K, V>` objects. Various Go map operations are mapped as follows:
145
- - **Creation (`make`):** `make(map[K]V)` is translated using a runtime helper:
146
- ```go
147
- m := make(map[string]int)
148
- ```
149
- becomes:
150
- ```typescript
151
- import * as goscript from "@go/builtin"
152
- let m = goscript.makeMap("string", "int") // Type info passed as strings
153
- ```
154
- - **Literals:** Map literals are translated to `new Map(...)`:
155
- ```go
156
- m := map[string]int{"one": 1, "two": 2}
157
- ```
158
- becomes:
159
- ```typescript
160
- let m = new Map([["one", 1], ["two", 2]])
161
- ```
162
- - **Assignment (`m[k] = v`):** Uses a runtime helper `mapSet`:
163
- ```go
164
- m["three"] = 3
165
- ```
166
- becomes:
167
- ```typescript
168
- goscript.mapSet(m, "three", 3)
169
- ```
170
- - **Access (`m[k]`):** Uses the standard `Map.get()` method. Accessing a non-existent key in Go yields the zero value for the value type. In TypeScript, `Map.get()` returns `undefined` for non-existent keys, so the translation must ensure the correct zero value is returned (this might involve runtime checks or type information).
171
- ```go
172
- val := m["one"] // Assuming m["one"] exists
173
- zero := m["nonexistent"] // Assuming m["nonexistent"] doesn't exist
174
- ```
175
- becomes (simplified conceptual translation):
176
- ```typescript
177
- let val = m.get("one")
178
- let zero = m.get("nonexistent") ?? 0 // Provide zero value (0 for int) if undefined
179
- ```
180
- - **Comma-Ok Idiom (`v, ok := m[k]`):** Translated using `Map.has()` and `Map.get()` with zero-value handling:
181
- ```go
182
- v, ok := m["three"]
183
- ```
184
- becomes:
185
- ```typescript
186
- let v: number
187
- let ok: boolean
188
- ok = m.has("three")
189
- v = m.get("three") ?? 0 // Provide zero value if key doesn't exist
190
- ```
191
- - **Length (`len(m)`):** Uses a runtime helper `len`:
192
- ```go
193
- size := len(m)
194
- ```
195
- becomes:
196
- ```typescript
197
- let size = goscript.len(m) // Uses runtime helper, not Map.size directly
198
- ```
199
- - **Deletion (`delete(m, k)`):** Uses a runtime helper `deleteMapEntry`:
200
- ```go
201
- delete(m, "two")
202
- ```
203
- becomes:
204
- ```typescript
205
- goscript.deleteMapEntry(m, "two")
206
- ```
207
- - **Iteration (`for k, v := range m`):** Uses standard `Map.entries()` and `for...of`:
208
- ```go
209
- for key, value := range m {
210
- // ...
211
- }
212
- ```
213
- becomes:
214
- ```typescript
215
- for (const [key, value] of m.entries()) {
216
- // ...
217
- }
218
- ```
219
- *Note: The reliance on runtime helpers (`@go/builtin`) is crucial for correctly emulating Go's map semantics, especially regarding zero values and potentially type information for `makeMap`.*
220
- - **Functions:** Converted to TypeScript `function`s. Exported functions are prefixed with `export`.
221
- - **Function Literals:** Go function literals (anonymous functions) are translated into TypeScript arrow functions (`=>`).
222
- ```go
223
- greet := func(name string) string {
224
- return "Hello, " + name
225
- }
226
- message := greet("world")
227
- ```
228
- becomes:
229
- ```typescript
230
- let greet = (name: string): string => { // Arrow function
231
- return "Hello, " + name
232
- }
233
- let message = greet("world")
234
- ```
235
- - **Methods:** Go functions with receivers are generated as methods within the corresponding TypeScript `class`. They retain their original Go casing.
236
- - **Receiver Type (Value vs. Pointer):** Both value receivers (`func (m MyStruct) Method()`) and pointer receivers (`func (m *MyStruct) Method()`) are translated into regular methods on the TypeScript class.
237
- ```go
238
- type Counter struct{ count int }
239
- func (c Counter) Value() int { return c.count } // Value receiver
240
- func (c *Counter) Inc() { c.count++ } // Pointer receiver
241
- ```
242
- becomes:
243
- ```typescript
244
- class Counter {
245
- private count: number = 0;
246
- public Value(): number { const c = this; return c.count; }
247
- public Inc(): void { const c = this; c.count++; }
248
- // ... constructor, clone ...
249
- }
250
- ```
251
- - **Method Calls:** Go allows calling pointer-receiver methods on values (`value.PtrMethod()`) and value-receiver methods on pointers (`ptr.ValueMethod()`) via automatic referencing/dereferencing. In TypeScript, method calls are made directly on the class instance (which represents either the Go value or the non-null Go pointer).
252
- ```go
253
- var c Counter
254
- var p *Counter = &c
255
- _ = c.Value() // OK
256
- _ = p.Value() // OK (Go implicitly dereferences p)
257
- c.Inc() // OK (Go implicitly takes address of c)
258
- p.Inc() // OK
259
- ```
260
- becomes:
261
- ```typescript
262
- let c = new Counter().clone()
263
- let p: Counter | null = c // p references the same object as c initially
264
- c.Value() // OK
265
- p?.Value() // OK (requires null check for pointer types)
266
- c.Inc() // OK
267
- p?.Inc() // OK (requires null check for pointer types)
268
- ```
269
- *Note: The optional chaining (`?.`) is generally required when calling methods on variables representing Go pointers (mapped to `T | null`). However, if the compiler can determine that a pointer variable is definitely not `null` at the point of call (e.g., immediately after initialization via `p := &T{...}`), the `?.` may be omitted for optimization.*
270
- - **Receiver Binding:** As per Code Generation Conventions, the Go receiver identifier (e.g., `c`) is bound to `this` within the method body (`const c = this`).
271
- - **Semantic Note on Value Receivers:** In Go, a method with a value receiver operates on a *copy* of the struct. The current TypeScript translation defines the method directly on the class. If a value-receiver method modifies the receiver's fields, the TypeScript version will modify the *original* object referenced by `this`, differing from Go's copy semantics. This is an area for potential future refinement if strict copy-on-call semantics for value receivers are required. (The `clone()` method handles copy-on-assignment, not copy-on-method-call).
272
-
273
- ## Value Semantics
274
-
275
- Go's value semantics (where assigning a struct copies it) are emulated in TypeScript by:
276
- 1. Adding a `clone()` method to generated classes.
277
- 2. Automatically calling `.clone()` during assignment statements (`=`, `:=`) whenever the right-hand side evaluates to a struct *value* (e.g., assigning from a variable, a composite literal `T{...}`, or a dereferenced pointer `*p`). This requires type information during compilation.
278
-
279
- ## Control Flow: `for range` Loops
280
-
281
- Go's `for range` construct is translated differently depending on the type being iterated over:
282
-
283
- - **Slices and Arrays:** `for range` over slices (`[]T`) or arrays (`[N]T`) is translated into a standard TypeScript C-style `for` loop:
284
- ```go
285
- items := []string{"a", "b", "c"}
286
- for i, item := range items {
287
- // ... use i and item
288
- }
289
- for _, item := range items {
290
- // ... use item only
291
- }
292
- ```
293
- becomes:
294
- ```typescript
295
- let items = ["a", "b", "c"]
296
- for (let i = 0; i < items.length; i++) {
297
- const item = items[i]
298
- { // New scope for loop body variables
299
- // ... use i and item
300
- }
301
- }
302
- for (let i = 0; i < items.length; i++) { // Index 'i' still generated
303
- const item = items[i]
304
- { // New scope for loop body variables
305
- // ... use item only
306
- }
307
- }
308
- ```
309
- *Note: A new block scope `{}` is introduced for the loop body to correctly emulate Go's per-iteration variable scoping for `item` (and `i` if captured).*
310
-
311
- - **Maps:** `for range` over maps (`map[K]V`) uses the `Map.entries()` iterator (as shown previously in the Maps section):
312
- ```go
313
- m := map[string]int{"one": 1}
314
- for k, v := range m {
315
- // ...
316
- }
317
- ```
318
- becomes:
319
- ```typescript
320
- let m = new Map([["one", 1]])
321
- for (const [k, v] of m.entries()) {
322
- // ...
323
- }
324
- ```
325
-
326
- - **Strings:** `for range` over strings iterates over Unicode code points (runes). This is translated using a runtime helper `stringToRunes` and a C-style `for` loop:
327
- ```go
328
- str := "go"
329
- for i, r := range str {
330
- // i is byte index, r is rune (int32)
331
- }
332
- ```
333
- becomes:
334
- ```typescript
335
- import * as goscript from "@go/builtin"
336
- let str = "go"
337
- const _runes = goscript.stringToRunes(str) // Convert to array of runes (numbers)
338
- for (let i = 0; i < _runes.length; i++) { // i is rune index here
339
- const r = _runes[i] // r is rune (number)
340
- {
341
- // ... use i and r
342
- }
343
- }
344
- ```
345
- *Note: The index `i` in the generated TypeScript loop corresponds to the *rune index*, not the byte index as in Go's `for range` over strings.*
346
- ## Control Flow: `switch` Statements
347
-
348
- Go's `switch` statement is translated into a standard TypeScript `switch` statement.
349
-
350
- - **Basic Switch:**
351
- ```go
352
- switch value {
353
- case 1:
354
- // do something
355
- case 2, 3: // Multiple values per case
356
- // do something else
357
- default:
358
- // default action
359
- }
360
- ```
361
- becomes:
362
- ```typescript
363
- switch (value) {
364
- case 1:
365
- // do something
366
- break // Automatically added
367
- case 2: // Multiple Go cases become separate TS cases
368
- case 3:
369
- // do something else
370
- break // Automatically added
371
- default:
372
- // default action
373
- break // Automatically added
374
- }
375
- ```
376
- *Note: `break` statements are automatically inserted at the end of each translated `case` block to replicate Go's default behavior of not falling through.*
377
-
378
- - **Switch without Expression:** A Go `switch` without an expression (`switch { ... }`) is equivalent to `switch true { ... }` and is useful for cleaner if/else-if chains. This translates similarly, comparing `true` against the case conditions.
379
- ```go
380
- switch {
381
- case x < 0:
382
- // negative
383
- case x == 0:
384
- // zero
385
- default: // x > 0
386
- // positive
387
- }
388
- ```
389
- becomes:
390
- ```typescript
391
- switch (true) {
392
- case x < 0:
393
- // negative
394
- break
395
- case x == 0:
396
- // zero
397
- break
398
- default:
399
- // positive
400
- break
401
- }
402
- ```
403
- - **Fallthrough:** Go's explicit `fallthrough` keyword is *not* currently supported and would require specific handling if implemented.
404
- ## Control Flow: `if` Statements
405
-
406
- Go's `if` statements are translated into standard TypeScript `if` statements.
407
-
408
- - **Basic `if`/`else if`/`else`:**
409
- ```go
410
- if condition1 {
411
- // block 1
412
- } else if condition2 {
413
- // block 2
414
- } else {
415
- // block 3
416
- }
417
- ```
418
- becomes:
419
- ```typescript
420
- if (condition1) {
421
- // block 1
422
- } else if (condition2) {
423
- // block 2
424
- } else {
425
- // block 3
426
- }
427
- ```
428
-
429
- - **`if` with Short Statement:** Go allows an optional short statement (typically variable initialization) before the condition. The scope of variables declared in the short statement is limited to the `if` (and any `else if`/`else`) blocks. This is translated by declaring the variable before the `if` statement in TypeScript, often within an immediately-invoked function expression (IIFE) or a simple block to mimic the limited scope if necessary, although simpler translations might place the variable in the outer scope if no name conflicts arise.
430
- ```go
431
- if v := computeValue(); v > 10 {
432
- // use v
433
- } else {
434
- // use v
435
- }
436
- // v is not accessible here
437
- ```
438
- becomes (conceptual translation, potentially simplified):
439
- ```typescript
440
- { // Optional block to limit scope
441
- const v = computeValue()
442
- if (v > 10) {
443
- // use v
444
- } else {
445
- // use v
446
- }
447
- }
448
- // v is not accessible here (if block scope is used)
449
- ```
450
- *Note: Precise scoping might require careful handling, especially if the initialized variable shadows an outer variable.*
451
- ## Zero Values
452
-
453
- Go's zero values are mapped as follows:
454
- - `number`: `0`
455
- - `string`: `""`
456
- - `boolean`: `false`
457
- - `struct`: `new TypeName()`
458
- - `pointer`, `interface`, `slice`, `map`, `channel`, `function`: `null`
459
-
460
- ## Packages and Imports
461
-
462
- - Go packages are mapped to TypeScript modules under the `@go/` scope (e.g., `import { MyType } from '@go/my/package';`).
463
- - The GoScript runtime is imported using the `@go/builtin` alias, which maps to the `builtin/builtin.ts` file.
464
- - Standard Go library packages might require specific runtime implementations or shims.
465
-
466
- ## Code Generation Conventions
467
-
468
- - **No Trailing Semicolons:** Generated TypeScript code omits semicolons at end of statements. Statements are line-separated without `;`.
469
-
470
- ## Asynchronous Operations (Async/Await)
471
-
472
- GoScript handles Go's concurrency primitives (like channels and potentially goroutines in the future) by mapping them to TypeScript's `async`/`await` mechanism where appropriate.
473
-
474
- ### Function Coloring
475
-
476
- To determine which functions need to be marked `async` in TypeScript, the compiler performs a "function coloring" analysis during compilation:
477
-
478
- 1. **Base Cases (Async Roots):**
479
- * A function is inherently **Asynchronous** if its body contains:
480
- * A channel receive operation (`&lt;-ch`).
481
- * A `select` statement.
482
- * (Potentially in the future: `go` statement).
483
- 2. **Propagation:**
484
- * A function is marked **Asynchronous** if it directly calls another function that is already marked **Asynchronous**.
485
- 3. **Default:**
486
- * If a function does not meet any of the asynchronous criteria above, it is considered **Synchronous**.
487
-
488
- ### TypeScript Generation
489
-
490
- ## Functions
491
-
492
- - **Async Functions:** Go functions colored as **Asynchronous** are generated as TypeScript `async function`s. Their return type `T` is wrapped in a `Promise<T>`. If the function has no return value, the TypeScript return type is `Promise<void>`.
493
- - **Sync Functions:** Go functions colored as **Synchronous** are generated as regular TypeScript `function`s with their corresponding return types.
494
- - **Function Calls:** When a Go function call targets an **Asynchronous** function, the generated TypeScript call expression is prefixed with the `await` keyword. Calls to **Synchronous** functions are generated directly without `await`.
495
-
496
- This coloring approach ensures that asynchronous operations propagate correctly through the call stack in the generated TypeScript code.
497
-
498
- ### Async Example
499
-
500
- Consider the following Go code using a channel:
501
-
502
- ```go
503
- package main
504
-
505
- // This function receives from a channel, making it async.
506
- func receiveFromChan(ch chan int) int {
507
- val := <-ch // This operation makes the function async
508
- return val
509
- }
510
-
511
- // This function calls an async function, making it async too.
512
- func caller(ch chan int) int {
513
- // We expect this call to be awaited in TypeScript
514
- result := receiveFromChan(ch)
515
- return result + 1
516
- }
517
-
518
- func main() {
519
- myChan := make(chan int, 1)
520
- myChan <- 10
521
- finalResult := caller(myChan)
522
- println(finalResult) // Expected output: 11
523
- close(myChan)
524
- }
525
-
526
- ```
527
-
528
- This translates to the following TypeScript:
529
-
530
- ```typescript
531
- import * as goscript from "@go/builtin";
532
-
533
- // Marked async because it contains 'await ch.receive()'
534
- async function receiveFromChan(ch: goscript.Channel<number>): Promise<number> {
535
- let val = await ch.receive()
536
- return val
537
- }
538
-
539
- // Marked async because it calls the async 'receiveFromChan'
540
- async function caller(ch: goscript.Channel<number>): Promise<number> {
541
- let result = await receiveFromChan(ch) // Call is awaited
542
- return result + 1
543
- }
544
-
545
- // Marked async because it calls the async 'caller' and uses 'await myChan.send()'
546
- export async function main(): Promise<void> {
547
- let myChan = goscript.makeChannel<number>(1)
548
- await myChan.send(10) // Send is awaited
549
- let finalResult = await caller(myChan) // Call is awaited
550
- console.log(finalResult)
551
- myChan.close()
552
- }
553
- ```
554
-
555
- *Note on Microtasks:* While Go's concurrency model involves goroutines and a scheduler, the TypeScript translation primarily uses `async`/`await` and Promises for channel operations. Starting a new Goroutine with the `go` keyword is translated to a call to `queueMicrotask` with the target function, effectively scheduling it to run asynchronously similar to how Promises resolve.
556
-
557
- ## Constants
558
-
559
- Go `const` declarations are translated into TypeScript `let` declarations at the module scope.
560
-
561
- ```go
562
- const Pi = 3.14
563
- const Greeting = "Hello"
564
- ```
565
-
566
- becomes:
567
-
568
- ```typescript
569
- let Pi = 3.14
570
- let Greeting = "Hello"
571
- ```
572
-
573
- *Note: Handling of untyped constants and potential precision issues with large numbers or complex constant expressions is an area for future refinement.*
574
-
575
- ## Multiple Return Values
576
-
577
- Go functions that return multiple values are translated into TypeScript functions that return a tuple (an array with fixed element types).
578
-
579
- ```go
580
- func swap(x, y string) (string, string) {
581
- return y, x
582
- }
583
-
584
- a, b := swap("hello", "world")
585
- first, _ := swap("one", "two") // Ignore second value
586
- ```
587
-
588
- becomes:
589
-
590
- ```typescript
591
- function swap(x: string, y: string): [string, string] {
592
- return [y, x]
593
- }
594
-
595
- let [a, b] = swap("hello", "world")
596
- let [first, ] = swap("one", "two") // Ignore second value via destructuring hole
597
- ```
598
-
599
- Assignment from function calls returning multiple values uses TypeScript's array destructuring syntax. The blank identifier `_` in Go corresponds to omitting the variable name in the TypeScript destructuring pattern.
@@ -1,10 +0,0 @@
1
- #!/bin/bash
2
- set -eo pipefail
3
- set -x
4
-
5
- pkgs=( "." )
6
- for pkg in ${pkgs[@]}; do
7
- go run -v github.com/paralin/goscript/cmd/goscript \
8
- compile \
9
- --package $pkg
10
- done
@@ -1,23 +0,0 @@
1
- module example
2
-
3
- go 1.24
4
-
5
- replace github.com/paralin/goscript => ../../
6
-
7
- require (
8
- github.com/paralin/goscript v0.0.0-20250421235527-0180cae519d3
9
- github.com/sirupsen/logrus v1.9.3
10
- )
11
-
12
- require (
13
- github.com/aperturerobotics/cli v1.0.0 // indirect
14
- github.com/aperturerobotics/common v0.21.2 // indirect
15
- github.com/pkg/errors v0.9.1 // indirect
16
- github.com/sanity-io/litter v1.5.8 // indirect
17
- github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
18
- golang.org/x/mod v0.24.0 // indirect
19
- golang.org/x/sync v0.13.0 // indirect
20
- golang.org/x/sys v0.32.0 // indirect
21
- golang.org/x/tools v0.32.0 // indirect
22
- gopkg.in/yaml.v3 v3.0.1 // indirect
23
- )
@@ -1,39 +0,0 @@
1
- github.com/aperturerobotics/cli v1.0.0 h1:s3xT2h7eBih4/4yZKTn/HQ6P+qpk6ygWZl2416xAI1M=
2
- github.com/aperturerobotics/cli v1.0.0/go.mod h1:wtlINjMcKuwyV1x4ftReuA6hHZcPB8kPMXHyQqGFCSc=
3
- github.com/aperturerobotics/common v0.21.2 h1:fqnPL5Oovpd8nDaNBYGiD1UpZhcH/JfpsS8gt5iBDyA=
4
- github.com/aperturerobotics/common v0.21.2/go.mod h1:FrecdNcsYvVS8RcWCR8FUkKFh+XmouFOYKHpBdMqqBA=
5
- github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6
- github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7
- github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8
- github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9
- github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10
- github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
11
- github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
12
- github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
13
- github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14
- github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15
- github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16
- github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
17
- github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
18
- github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
19
- github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
20
- github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21
- github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
22
- github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
23
- github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
24
- github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
25
- github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
26
- github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
27
- golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
28
- golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
29
- golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
30
- golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
31
- golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
32
- golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
33
- golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
34
- golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
35
- golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
36
- gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
37
- gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
38
- gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
39
- gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=