goscript 0.0.2 → 0.0.4

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 (151) hide show
  1. package/README.md +41 -0
  2. package/builtin/builtin.ts +368 -348
  3. package/cmd/goscript/main.js +37 -0
  4. package/compiler/compile_expr.go +3 -37
  5. package/compiler/index.test.ts +29 -0
  6. package/compiler/index.ts +85 -0
  7. package/dist/builtin/builtin.d.ts +168 -0
  8. package/dist/builtin/builtin.js +372 -0
  9. package/dist/builtin/builtin.js.map +1 -0
  10. package/dist/compiler/index.d.ts +26 -0
  11. package/dist/compiler/index.js +64 -0
  12. package/dist/compiler/index.js.map +1 -0
  13. package/package.json +71 -3
  14. package/.aider-prompt +0 -11
  15. package/compliance/COMPLIANCE.md +0 -133
  16. package/compliance/compliance.go +0 -313
  17. package/compliance/compliance_test.go +0 -57
  18. package/compliance/tests/array_literal/array_literal.go +0 -15
  19. package/compliance/tests/array_literal/array_literal.gs.ts +0 -19
  20. package/compliance/tests/array_literal/expected.log +0 -3
  21. package/compliance/tests/async_basic/async_basic.go +0 -26
  22. package/compliance/tests/async_basic/async_basic.gs.ts +0 -30
  23. package/compliance/tests/async_basic/expected.log +0 -1
  24. package/compliance/tests/basic_arithmetic/basic_arithmetic.go +0 -15
  25. package/compliance/tests/basic_arithmetic/basic_arithmetic.gs.ts +0 -19
  26. package/compliance/tests/basic_arithmetic/expected.log +0 -5
  27. package/compliance/tests/boolean_logic/boolean_logic.go +0 -13
  28. package/compliance/tests/boolean_logic/boolean_logic.gs.ts +0 -17
  29. package/compliance/tests/boolean_logic/expected.log +0 -3
  30. package/compliance/tests/channel_basic/channel_basic.go +0 -12
  31. package/compliance/tests/channel_basic/channel_basic.gs.ts +0 -18
  32. package/compliance/tests/channel_basic/expected.log +0 -1
  33. package/compliance/tests/composite_literal_assignment/composite_literal_assignment.go +0 -20
  34. package/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.ts +0 -27
  35. package/compliance/tests/composite_literal_assignment/expected.log +0 -2
  36. package/compliance/tests/constants/constants.go +0 -18
  37. package/compliance/tests/constants/constants.gs.ts +0 -22
  38. package/compliance/tests/constants/expected.log +0 -3
  39. package/compliance/tests/copy_independence/copy_independence.go +0 -29
  40. package/compliance/tests/copy_independence/copy_independence.gs.ts +0 -36
  41. package/compliance/tests/copy_independence/expected.log +0 -4
  42. package/compliance/tests/float64/expected.log +0 -6
  43. package/compliance/tests/float64/float64.go +0 -28
  44. package/compliance/tests/float64/float64.gs.ts +0 -32
  45. package/compliance/tests/for_loop_basic/expected.log +0 -5
  46. package/compliance/tests/for_loop_basic/for_loop_basic.go +0 -9
  47. package/compliance/tests/for_loop_basic/for_loop_basic.gs.ts +0 -13
  48. package/compliance/tests/for_loop_condition_only/expected.log +0 -5
  49. package/compliance/tests/for_loop_condition_only/main.go +0 -9
  50. package/compliance/tests/for_loop_condition_only/main.gs.ts +0 -13
  51. package/compliance/tests/for_range/expected.log +0 -9
  52. package/compliance/tests/for_range/for_range.go +0 -26
  53. package/compliance/tests/for_range/for_range.gs.ts +0 -45
  54. package/compliance/tests/for_range_index_use/expected.log +0 -6
  55. package/compliance/tests/for_range_index_use/for_range_index_use.go +0 -11
  56. package/compliance/tests/for_range_index_use/for_range_index_use.gs.ts +0 -18
  57. package/compliance/tests/func_literal/expected.log +0 -1
  58. package/compliance/tests/func_literal/func_literal.go +0 -10
  59. package/compliance/tests/func_literal/func_literal.gs.ts +0 -15
  60. package/compliance/tests/function_call_result_assignment/expected.log +0 -2
  61. package/compliance/tests/function_call_result_assignment/function_call_result_assignment.go +0 -24
  62. package/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.ts +0 -31
  63. package/compliance/tests/if_statement/expected.log +0 -1
  64. package/compliance/tests/if_statement/if_statement.go +0 -11
  65. package/compliance/tests/if_statement/if_statement.gs.ts +0 -15
  66. package/compliance/tests/interface_to_interface_type_assertion/expected.log +0 -1
  67. package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.go +0 -30
  68. package/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.ts +0 -41
  69. package/compliance/tests/interface_type_assertion/expected.log +0 -1
  70. package/compliance/tests/interface_type_assertion/interface_type_assertion.go +0 -26
  71. package/compliance/tests/interface_type_assertion/interface_type_assertion.gs.ts +0 -36
  72. package/compliance/tests/map_support/expected.log +0 -13
  73. package/compliance/tests/map_support/map_support.go +0 -89
  74. package/compliance/tests/map_support/map_support.gs.ts +0 -102
  75. package/compliance/tests/method_call_on_pointer_receiver/expected.log +0 -1
  76. package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.go +0 -19
  77. package/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.ts +0 -27
  78. package/compliance/tests/method_call_on_pointer_via_value/expected.log +0 -1
  79. package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.go +0 -29
  80. package/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.ts +0 -38
  81. package/compliance/tests/method_call_on_value_receiver/expected.log +0 -1
  82. package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.go +0 -16
  83. package/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.ts +0 -24
  84. package/compliance/tests/method_call_on_value_via_pointer/expected.log +0 -2
  85. package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.go +0 -30
  86. package/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.ts +0 -38
  87. package/compliance/tests/multiple_return_values/expected.log +0 -6
  88. package/compliance/tests/multiple_return_values/multiple_return_values.go +0 -19
  89. package/compliance/tests/multiple_return_values/multiple_return_values.gs.ts +0 -23
  90. package/compliance/tests/pointer_assignment_no_copy/expected.log +0 -2
  91. package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.go +0 -28
  92. package/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.ts +0 -35
  93. package/compliance/tests/pointer_composite_literal_assignment/expected.log +0 -3
  94. package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.go +0 -23
  95. package/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.ts +0 -30
  96. package/compliance/tests/pointer_deref_multiassign/expected.log +0 -0
  97. package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.go +0 -17
  98. package/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.ts +0 -27
  99. package/compliance/tests/pointer_initialization/expected.log +0 -1
  100. package/compliance/tests/pointer_initialization/pointer_initialization.go +0 -16
  101. package/compliance/tests/pointer_initialization/pointer_initialization.gs.ts +0 -22
  102. package/compliance/tests/select_receive_on_closed_channel_no_default/expected.log +0 -1
  103. package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.go +0 -15
  104. package/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.ts +0 -31
  105. package/compliance/tests/select_send_on_full_buffered_channel_with_default/expected.log +0 -1
  106. package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.go +0 -13
  107. package/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.ts +0 -35
  108. package/compliance/tests/select_statement/expected.log +0 -9
  109. package/compliance/tests/select_statement/select_statement.go +0 -109
  110. package/compliance/tests/select_statement/select_statement.gs.ts +0 -239
  111. package/compliance/tests/simple/expected.log +0 -1
  112. package/compliance/tests/simple/simple.go +0 -5
  113. package/compliance/tests/simple/simple.gs.ts +0 -9
  114. package/compliance/tests/simple_deref_assignment/expected.log +0 -2
  115. package/compliance/tests/simple_deref_assignment/simple_deref_assignment.go +0 -19
  116. package/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.ts +0 -26
  117. package/compliance/tests/slices/expected.log +0 -7
  118. package/compliance/tests/slices/slices.go +0 -22
  119. package/compliance/tests/slices/slices.gs.ts +0 -26
  120. package/compliance/tests/string_rune_conversion/expected.log +0 -3
  121. package/compliance/tests/string_rune_conversion/string_rune_conversion.go +0 -16
  122. package/compliance/tests/string_rune_conversion/string_rune_conversion.gs.ts +0 -22
  123. package/compliance/tests/struct_field_access/expected.log +0 -2
  124. package/compliance/tests/struct_field_access/struct_field_access.go +0 -13
  125. package/compliance/tests/struct_field_access/struct_field_access.gs.ts +0 -20
  126. package/compliance/tests/struct_value_init_clone/expected.log +0 -5
  127. package/compliance/tests/struct_value_init_clone/struct_value_init_clone.go +0 -28
  128. package/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.ts +0 -35
  129. package/compliance/tests/switch_statement/expected.log +0 -14
  130. package/compliance/tests/switch_statement/switch_statement.go +0 -59
  131. package/compliance/tests/switch_statement/switch_statement.gs.ts +0 -85
  132. package/compliance/tests/value_type_copy_behavior/expected.log +0 -3
  133. package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.go +0 -25
  134. package/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.ts +0 -34
  135. package/design/DESIGN.md +0 -599
  136. package/example/simple/build.bash +0 -10
  137. package/example/simple/go.mod +0 -23
  138. package/example/simple/go.sum +0 -39
  139. package/example/simple/main.go +0 -138
  140. package/example/simple/main.gs.ts +0 -133
  141. package/example/simple/main.ts +0 -3
  142. package/example/simple/main_test.go +0 -59
  143. package/example/simple/main_tools.go +0 -5
  144. package/example/simple/package.json +0 -7
  145. package/example/simple/run.bash +0 -6
  146. package/example/simple/tsconfig.json +0 -28
  147. package/example/simple/yarn.lock +0 -8
  148. package/output/output.go +0 -10
  149. package/tsconfig.json +0 -10
  150. package/types/tokens.go +0 -65
  151. package/types/types.go +0 -46
@@ -1,39 +1,41 @@
1
1
  /**
2
2
  * Creates a new slice (TypeScript array) with the specified length and capacity.
3
- * @param elementType The element type of the slice (for type hinting).
4
3
  * @param len The length of the slice.
5
4
  * @param cap The capacity of the slice (optional).
6
5
  * @returns A new TypeScript array representing the slice.
7
6
  */
8
- export const makeSlice = <T>(elementType: any, len: number, cap?: number): Array<T> & { __capacity?: number } => {
9
- const slice = new Array<T>(len) as Array<T> & { __capacity?: number };
10
- slice.__capacity = cap !== undefined ? cap : len;
11
- return slice;
12
- };
7
+ export const makeSlice = <T>(
8
+ len: number,
9
+ cap?: number,
10
+ ): Array<T> & { __capacity?: number } => {
11
+ const slice = new Array<T>(len) as Array<T> & { __capacity?: number }
12
+ slice.__capacity = cap !== undefined ? cap : len
13
+ return slice
14
+ }
13
15
 
14
16
  /**
15
17
  * Creates a new map (TypeScript Map).
16
- * @param keyType The key type of the map (for type hinting).
17
- * @param valueType The value type of the map (for type hinting).
18
18
  * @returns A new TypeScript Map.
19
19
  */
20
- export const makeMap = <K, V>(keyType: any, valueType: any): Map<K, V> => {
21
- return new Map<K, V>();
22
- };
20
+ export const makeMap = <K, V>(): Map<K, V> => {
21
+ return new Map<K, V>()
22
+ }
23
23
 
24
24
  /**
25
25
  * Returns the length of a collection (string, array, or map).
26
26
  * @param collection The collection to get the length of.
27
27
  * @returns The length of the collection.
28
28
  */
29
- export const len = <T>(collection: string | Array<T> | Map<any, any>): number => {
30
- if (typeof collection === 'string' || Array.isArray(collection)) {
31
- return collection.length;
32
- } else if (collection instanceof Map) {
33
- return collection.size;
34
- }
35
- return 0; // Default fallback
36
- };
29
+ export const len = <T>(
30
+ collection: string | Array<T> | Map<unknown, unknown>,
31
+ ): number => {
32
+ if (typeof collection === 'string' || Array.isArray(collection)) {
33
+ return collection.length
34
+ } else if (collection instanceof Map) {
35
+ return collection.size
36
+ }
37
+ return 0 // Default fallback
38
+ }
37
39
 
38
40
  /**
39
41
  * Returns the capacity of a slice (TypeScript array).
@@ -41,8 +43,8 @@ export const len = <T>(collection: string | Array<T> | Map<any, any>): number =>
41
43
  * @returns The capacity of the slice.
42
44
  */
43
45
  export const cap = <T>(slice: Array<T> & { __capacity?: number }): number => {
44
- return slice.__capacity !== undefined ? slice.__capacity : slice.length;
45
- };
46
+ return slice.__capacity !== undefined ? slice.__capacity : slice.length
47
+ }
46
48
 
47
49
  /**
48
50
  * Converts a string to an array of Unicode code points (runes).
@@ -50,8 +52,8 @@ export const cap = <T>(slice: Array<T> & { __capacity?: number }): number => {
50
52
  * @returns An array of numbers representing the Unicode code points.
51
53
  */
52
54
  export const stringToRunes = (str: string): number[] => {
53
- return Array.from(str).map(c => c.codePointAt(0) || 0);
54
- };
55
+ return Array.from(str).map((c) => c.codePointAt(0) || 0)
56
+ }
55
57
 
56
58
  /**
57
59
  * Gets a value from a map, with a default value if the key doesn't exist.
@@ -60,9 +62,13 @@ export const stringToRunes = (str: string): number[] => {
60
62
  * @param defaultValue The default value to return if the key doesn't exist (defaults to 0).
61
63
  * @returns The value for the key, or the default value if the key doesn't exist.
62
64
  */
63
- export const mapGet = <K, V>(map: Map<K, V>, key: K, defaultValue: V | null = null): V | null => {
64
- return map.has(key) ? map.get(key)! : defaultValue;
65
- };
65
+ export const mapGet = <K, V>(
66
+ map: Map<K, V>,
67
+ key: K,
68
+ defaultValue: V | null = null,
69
+ ): V | null => {
70
+ return map.has(key) ? map.get(key)! : defaultValue
71
+ }
66
72
 
67
73
  /**
68
74
  * Sets a value in a map.
@@ -71,8 +77,8 @@ export const mapGet = <K, V>(map: Map<K, V>, key: K, defaultValue: V | null = nu
71
77
  * @param value The value to set.
72
78
  */
73
79
  export const mapSet = <K, V>(map: Map<K, V>, key: K, value: V): void => {
74
- map.set(key, value);
75
- };
80
+ map.set(key, value)
81
+ }
76
82
 
77
83
  /**
78
84
  * Deletes a key from a map.
@@ -80,8 +86,8 @@ export const mapSet = <K, V>(map: Map<K, V>, key: K, value: V): void => {
80
86
  * @param key The key to delete.
81
87
  */
82
88
  export const deleteMapEntry = <K, V>(map: Map<K, V>, key: K): void => {
83
- map.delete(key);
84
- };
89
+ map.delete(key)
90
+ }
85
91
 
86
92
  /**
87
93
  * Checks if a key exists in a map.
@@ -90,8 +96,8 @@ export const deleteMapEntry = <K, V>(map: Map<K, V>, key: K): void => {
90
96
  * @returns True if the key exists, false otherwise.
91
97
  */
92
98
  export const mapHas = <K, V>(map: Map<K, V>, key: K): boolean => {
93
- return map.has(key);
94
- };
99
+ return map.has(key)
100
+ }
95
101
  /**
96
102
  * Appends elements to a slice (TypeScript array).
97
103
  * Note: In Go, append can return a new slice if the underlying array is reallocated.
@@ -101,25 +107,25 @@ export const mapHas = <K, V>(map: Map<K, V>, key: K): boolean => {
101
107
  * @returns The modified slice (TypeScript array).
102
108
  */
103
109
  export const append = <T>(slice: Array<T>, ...elements: T[]): Array<T> => {
104
- slice.push(...elements);
105
- return slice;
106
- };
110
+ slice.push(...elements)
111
+ return slice
112
+ }
107
113
 
108
114
  /**
109
115
  * Represents the result of a channel receive operation with 'ok' value
110
116
  */
111
117
  export interface ChannelReceiveResult<T> {
112
- value: T; // Should be T | ZeroValue<T>
113
- ok: boolean;
118
+ value: T // Should be T | ZeroValue<T>
119
+ ok: boolean
114
120
  }
115
121
 
116
122
  /**
117
123
  * Represents a result from a select operation
118
124
  */
119
125
  export interface SelectResult<T> {
120
- value: T; // Should be T | ZeroValue<T>
121
- ok: boolean;
122
- id: number;
126
+ value: T // Should be T | ZeroValue<T>
127
+ ok: boolean
128
+ id: number
123
129
  }
124
130
 
125
131
  /**
@@ -127,291 +133,290 @@ export interface SelectResult<T> {
127
133
  * Supports asynchronous sending and receiving of values.
128
134
  */
129
135
  export interface Channel<T> {
130
- /**
131
- * Sends a value to the channel.
132
- * Returns a promise that resolves when the value is accepted by the channel.
133
- * @param value The value to send.
134
- */
135
- send(value: T): Promise<void>;
136
-
137
- /**
138
- * Receives a value from the channel.
139
- * Returns a promise that resolves with the received value.
140
- * If the channel is closed, it throws an error.
141
- */
142
- receive(): Promise<T>;
143
-
144
- /**
145
- * Receives a value from the channel along with a boolean indicating
146
- * whether the channel is still open.
147
- * Returns a promise that resolves with {value, ok}.
148
- * - If channel is open and has data: {value: <data>, ok: true}
149
- * - If channel is closed and empty: {value: <zero value>, ok: false}
150
- * - If channel is closed but has remaining buffered data: {value: <data>, ok: true}
151
- */
152
- receiveWithOk(): Promise<ChannelReceiveResult<T>>;
153
-
154
- /**
155
- * Closes the channel.
156
- * No more values can be sent to a closed channel.
157
- * Receive operations on a closed channel return the zero value and ok=false.
158
- */
159
- close(): void;
160
-
161
- /**
162
- * Used in select statements to create a receive operation promise.
163
- * @param id An identifier for this case in the select statement
164
- * @returns Promise that resolves when this case is selected
165
- */
166
- selectReceive(id: number): Promise<SelectResult<T>>;
167
-
168
- /**
169
- * Used in select statements to create a send operation promise.
170
- * @param value The value to send
171
- * @param id An identifier for this case in the select statement
172
- * @returns Promise that resolves when this case is selected
173
- */
174
- selectSend(value: T, id: number): Promise<SelectResult<boolean>>;
175
-
176
- /**
177
- * Checks if the channel has data ready to be received without blocking.
178
- * Used for non-blocking select operations.
179
- */
180
- canReceiveNonBlocking(): boolean;
181
-
182
- /**
183
- * Checks if the channel can accept a send operation without blocking.
184
- * Used for non-blocking select operations.
185
- */
186
- canSendNonBlocking(): boolean;
136
+ /**
137
+ * Sends a value to the channel.
138
+ * Returns a promise that resolves when the value is accepted by the channel.
139
+ * @param value The value to send.
140
+ */
141
+ send(value: T): Promise<void>
142
+
143
+ /**
144
+ * Receives a value from the channel.
145
+ * Returns a promise that resolves with the received value.
146
+ * If the channel is closed, it throws an error.
147
+ */
148
+ receive(): Promise<T>
149
+
150
+ /**
151
+ * Receives a value from the channel along with a boolean indicating
152
+ * whether the channel is still open.
153
+ * Returns a promise that resolves with {value, ok}.
154
+ * - If channel is open and has data: {value: <data>, ok: true}
155
+ * - If channel is closed and empty: {value: <zero value>, ok: false}
156
+ * - If channel is closed but has remaining buffered data: {value: <data>, ok: true}
157
+ */
158
+ receiveWithOk(): Promise<ChannelReceiveResult<T>>
159
+
160
+ /**
161
+ * Closes the channel.
162
+ * No more values can be sent to a closed channel.
163
+ * Receive operations on a closed channel return the zero value and ok=false.
164
+ */
165
+ close(): void
166
+
167
+ /**
168
+ * Used in select statements to create a receive operation promise.
169
+ * @param id An identifier for this case in the select statement
170
+ * @returns Promise that resolves when this case is selected
171
+ */
172
+ selectReceive(id: number): Promise<SelectResult<T>>
173
+
174
+ /**
175
+ * Used in select statements to create a send operation promise.
176
+ * @param value The value to send
177
+ * @param id An identifier for this case in the select statement
178
+ * @returns Promise that resolves when this case is selected
179
+ */
180
+ selectSend(value: T, id: number): Promise<SelectResult<boolean>>
181
+
182
+ /**
183
+ * Checks if the channel has data ready to be received without blocking.
184
+ * Used for non-blocking select operations.
185
+ */
186
+ canReceiveNonBlocking(): boolean
187
+
188
+ /**
189
+ * Checks if the channel can accept a send operation without blocking.
190
+ * Used for non-blocking select operations.
191
+ */
192
+ canSendNonBlocking(): boolean
187
193
  }
188
194
 
189
195
  // A simple implementation of buffered channels
190
196
  class BufferedChannel<T> implements Channel<T> {
191
- private buffer: T[] = [];
192
- private closed: boolean = false;
193
- private capacity: number;
194
- private senders: Array<(value: boolean) => void> = []; // Resolvers for blocked senders
195
- private receivers: Array<(value: T) => void> = []; // Resolvers for blocked receivers
196
- private receiversWithOk: Array<(result: ChannelReceiveResult<T>) => void> = []; // For receive with ok
197
- private zeroValue: T; // Store the zero value for the element type
198
-
199
- constructor(capacity: number, zeroValue: T) {
200
- this.capacity = capacity;
201
- this.zeroValue = zeroValue;
197
+ private buffer: T[] = []
198
+ private closed: boolean = false
199
+ private capacity: number
200
+ private senders: Array<(value: boolean) => void> = [] // Resolvers for blocked senders
201
+ private receivers: Array<(value: T) => void> = [] // Resolvers for blocked receivers
202
+ private receiversWithOk: Array<(result: ChannelReceiveResult<T>) => void> = [] // For receive with ok
203
+ private zeroValue: T // Store the zero value for the element type
204
+
205
+ constructor(capacity: number, zeroValue: T) {
206
+ this.capacity = capacity
207
+ this.zeroValue = zeroValue
208
+ }
209
+
210
+ async send(value: T): Promise<void> {
211
+ if (this.closed) {
212
+ throw new Error('send on closed channel')
202
213
  }
203
214
 
204
- async send(value: T): Promise<void> {
205
- if (this.closed) {
206
- throw new Error("send on closed channel");
207
- }
208
-
209
- // If there are waiting receivers, directly pass the value
210
- if (this.receivers.length > 0) {
211
- const receiver = this.receivers.shift()!;
212
- receiver(value);
213
- return;
214
- }
215
-
216
- // If there are waiting receivers with ok, directly pass the value and ok=true
217
- if (this.receiversWithOk.length > 0) {
218
- const receiver = this.receiversWithOk.shift()!;
219
- receiver({ value, ok: true });
220
- return;
221
- }
222
-
223
- // If buffer is not full, add to buffer
224
- if (this.buffer.length < this.capacity) {
225
- this.buffer.push(value);
226
- return;
227
- }
228
-
229
- // Buffer is full, block the sender
230
- return new Promise<void>((resolve, reject) => {
231
- this.senders.push((success: boolean) => {
232
- if (success) {
233
- this.buffer.push(value);
234
- resolve();
235
- } else {
236
- reject(new Error("send on closed channel"));
237
- }
238
- });
239
- });
215
+ // If there are waiting receivers, directly pass the value
216
+ if (this.receivers.length > 0) {
217
+ const receiver = this.receivers.shift()!
218
+ receiver(value)
219
+ return
240
220
  }
241
221
 
242
- async receive(): Promise<T> {
243
- // If buffer has values, return from buffer
244
- if (this.buffer.length > 0) {
245
- const value = this.buffer.shift()!;
246
-
247
- // If there are waiting senders, unblock one
248
- if (this.senders.length > 0) {
249
- const sender = this.senders.shift()!;
250
- sender(true); // Unblock with success
251
- }
222
+ // If there are waiting receivers with ok, directly pass the value and ok=true
223
+ if (this.receiversWithOk.length > 0) {
224
+ const receiver = this.receiversWithOk.shift()!
225
+ receiver({ value, ok: true })
226
+ return
227
+ }
252
228
 
253
- return value;
254
- }
229
+ // If buffer is not full, add to buffer
230
+ if (this.buffer.length < this.capacity) {
231
+ this.buffer.push(value)
232
+ return
233
+ }
255
234
 
256
- // If channel is closed and buffer is empty, throw error (receive without ok)
257
- if (this.closed) {
258
- throw new Error("receive on closed channel");
235
+ // Buffer is full, block the sender
236
+ return new Promise<void>((resolve, reject) => {
237
+ this.senders.push((success: boolean) => {
238
+ if (success) {
239
+ this.buffer.push(value)
240
+ resolve()
241
+ } else {
242
+ reject(new Error('send on closed channel'))
259
243
  }
260
-
261
- // Buffer is empty, block the receiver
262
- return new Promise<T>((resolve) => {
263
- this.receivers.push(resolve);
264
- });
244
+ })
245
+ })
246
+ }
247
+
248
+ async receive(): Promise<T> {
249
+ // If buffer has values, return from buffer
250
+ if (this.buffer.length > 0) {
251
+ const value = this.buffer.shift()!
252
+
253
+ // If there are waiting senders, unblock one
254
+ if (this.senders.length > 0) {
255
+ const sender = this.senders.shift()!
256
+ sender(true) // Unblock with success
257
+ }
258
+
259
+ return value
265
260
  }
266
261
 
267
- async receiveWithOk(): Promise<ChannelReceiveResult<T>> {
268
- // If buffer has values, return from buffer with ok=true
269
- if (this.buffer.length > 0) {
270
- const value = this.buffer.shift()!;
262
+ // If channel is closed and buffer is empty, throw error (receive without ok)
263
+ if (this.closed) {
264
+ throw new Error('receive on closed channel')
265
+ }
271
266
 
272
- // If there are waiting senders, unblock one
273
- if (this.senders.length > 0) {
274
- const sender = this.senders.shift()!;
275
- sender(true); // Unblock with success
276
- }
267
+ // Buffer is empty, block the receiver
268
+ return new Promise<T>((resolve) => {
269
+ this.receivers.push(resolve)
270
+ })
271
+ }
277
272
 
278
- return { value, ok: true };
279
- }
273
+ async receiveWithOk(): Promise<ChannelReceiveResult<T>> {
274
+ // If buffer has values, return from buffer with ok=true
275
+ if (this.buffer.length > 0) {
276
+ const value = this.buffer.shift()!
280
277
 
281
- // If channel is closed and buffer is empty, return zero value with ok=false
282
- if (this.closed) {
283
- return { value: this.zeroValue, ok: false }; // Return zeroValue
284
- }
278
+ // If there are waiting senders, unblock one
279
+ if (this.senders.length > 0) {
280
+ const sender = this.senders.shift()!
281
+ sender(true) // Unblock with success
282
+ }
285
283
 
286
- // Buffer is empty, block the receiver with ok
287
- return new Promise<ChannelReceiveResult<T>>((resolve) => {
288
- this.receiversWithOk.push(resolve);
289
- });
284
+ return { value, ok: true }
290
285
  }
291
286
 
292
- async selectReceive(id: number): Promise<SelectResult<T>> {
293
- // If buffer has values, return from buffer with ok=true
294
- if (this.buffer.length > 0) {
295
- const value = this.buffer.shift()!;
287
+ // If channel is closed and buffer is empty, return zero value with ok=false
288
+ if (this.closed) {
289
+ return { value: this.zeroValue, ok: false } // Return zeroValue
290
+ }
296
291
 
297
- // If there are waiting senders, unblock one
298
- if (this.senders.length > 0) {
299
- const sender = this.senders.shift()!;
300
- sender(true); // Unblock with success
301
- }
292
+ // Buffer is empty, block the receiver with ok
293
+ return new Promise<ChannelReceiveResult<T>>((resolve) => {
294
+ this.receiversWithOk.push(resolve)
295
+ })
296
+ }
302
297
 
303
- return { value, ok: true, id };
304
- }
298
+ async selectReceive(id: number): Promise<SelectResult<T>> {
299
+ // If buffer has values, return from buffer with ok=true
300
+ if (this.buffer.length > 0) {
301
+ const value = this.buffer.shift()!
305
302
 
306
- // If channel is closed and buffer is empty, return zero value with ok=false
307
- if (this.closed) {
308
- return { value: this.zeroValue, ok: false, id }; // Return zeroValue
309
- }
303
+ // If there are waiting senders, unblock one
304
+ if (this.senders.length > 0) {
305
+ const sender = this.senders.shift()!
306
+ sender(true) // Unblock with success
307
+ }
310
308
 
311
- // Buffer is empty, return a promise that will be resolved when a value is available
312
- return new Promise<SelectResult<T>>((resolve) => {
313
- this.receiversWithOk.push((result) => {
314
- resolve({ ...result, id });
315
- });
316
- });
309
+ return { value, ok: true, id }
317
310
  }
318
311
 
319
- async selectSend(value: T, id: number): Promise<SelectResult<boolean>> {
320
- if (this.closed) {
321
- return { value: false, ok: false, id };
322
- }
312
+ // If channel is closed and buffer is empty, return zero value with ok=false
313
+ if (this.closed) {
314
+ return { value: this.zeroValue, ok: false, id } // Return zeroValue
315
+ }
323
316
 
324
- // If there are waiting receivers, directly pass the value
325
- if (this.receivers.length > 0) {
326
- const receiver = this.receivers.shift()!;
327
- receiver(value);
328
- return { value: true, ok: true, id };
329
- }
317
+ // Buffer is empty, return a promise that will be resolved when a value is available
318
+ return new Promise<SelectResult<T>>((resolve) => {
319
+ this.receiversWithOk.push((result) => {
320
+ resolve({ ...result, id })
321
+ })
322
+ })
323
+ }
324
+
325
+ async selectSend(value: T, id: number): Promise<SelectResult<boolean>> {
326
+ if (this.closed) {
327
+ return { value: false, ok: false, id }
328
+ }
330
329
 
331
- // If there are waiting receivers with ok, directly pass the value and ok=true
332
- if (this.receiversWithOk.length > 0) {
333
- const receiver = this.receiversWithOk.shift()!;
334
- receiver({ value, ok: true });
335
- return { value: true, ok: true, id };
336
- }
330
+ // If there are waiting receivers, directly pass the value
331
+ if (this.receivers.length > 0) {
332
+ const receiver = this.receivers.shift()!
333
+ receiver(value)
334
+ return { value: true, ok: true, id }
335
+ }
337
336
 
338
- // If buffer is not full, add to buffer
339
- if (this.buffer.length < this.capacity) {
340
- this.buffer.push(value);
341
- return { value: true, ok: true, id };
342
- }
337
+ // If there are waiting receivers with ok, directly pass the value and ok=true
338
+ if (this.receiversWithOk.length > 0) {
339
+ const receiver = this.receiversWithOk.shift()!
340
+ receiver({ value, ok: true })
341
+ return { value: true, ok: true, id }
342
+ }
343
343
 
344
- // Buffer is full, return a promise that will be resolved when buffer space is available
345
- return new Promise<SelectResult<boolean>>((resolve, reject) => {
346
- this.senders.push((success: boolean) => {
347
- if (success) {
348
- this.buffer.push(value);
349
- resolve({ value: true, ok: true, id });
350
- } else {
351
- resolve({ value: false, ok: false, id });
352
- }
353
- });
354
- });
344
+ // If buffer is not full, add to buffer
345
+ if (this.buffer.length < this.capacity) {
346
+ this.buffer.push(value)
347
+ return { value: true, ok: true, id }
355
348
  }
356
349
 
357
- close(): void {
358
- if (this.closed) {
359
- throw new Error("close of closed channel");
350
+ // Buffer is full, return a promise that will be resolved when buffer space is available
351
+ return new Promise<SelectResult<boolean>>((resolve) => {
352
+ this.senders.push((success: boolean) => {
353
+ if (success) {
354
+ this.buffer.push(value)
355
+ resolve({ value: true, ok: true, id })
356
+ } else {
357
+ resolve({ value: false, ok: false, id })
360
358
  }
359
+ })
360
+ })
361
+ }
361
362
 
362
- this.closed = true;
363
-
364
- // Unblock all waiting senders with failure
365
- for (const sender of this.senders) {
366
- sender(false);
367
- }
368
- this.senders = [];
363
+ close(): void {
364
+ if (this.closed) {
365
+ throw new Error('close of closed channel')
366
+ }
369
367
 
370
- // Unblock all waiting receivers with the zero value
371
- for (const receiver of this.receivers) {
372
- // Note: receive() without ok throws on closed channel, this unblocking should not happen in correct Go logic
373
- // but for safety, we'll resolve with zero value if it somehow does.
374
- receiver(this.zeroValue);
375
- }
376
- this.receivers = [];
368
+ this.closed = true
377
369
 
378
- // Unblock all waiting receivers with ok=false and zero value
379
- for (const receiver of this.receiversWithOk) {
380
- receiver({ value: this.zeroValue, ok: false });
381
- }
382
- this.receiversWithOk = [];
370
+ // Unblock all waiting senders with failure
371
+ for (const sender of this.senders) {
372
+ sender(false)
383
373
  }
374
+ this.senders = []
384
375
 
385
- /**
386
- * Checks if the channel has data ready to be received without blocking.
387
- * Used for non-blocking select operations.
388
- */
389
- canReceiveNonBlocking(): boolean {
390
- return this.buffer.length > 0 || this.closed;
376
+ // Unblock all waiting receivers with the zero value
377
+ for (const receiver of this.receivers) {
378
+ // Note: receive() without ok throws on closed channel, this unblocking should not happen in correct Go logic
379
+ // but for safety, we'll resolve with zero value if it somehow does.
380
+ receiver(this.zeroValue)
391
381
  }
382
+ this.receivers = []
392
383
 
393
- /**
394
- * Checks if the channel can accept a send operation without blocking.
395
- * Used for non-blocking select operations.
396
- */
397
- canSendNonBlocking(): boolean {
398
- return !this.closed && this.buffer.length < this.capacity;
384
+ // Unblock all waiting receivers with ok=false and zero value
385
+ for (const receiver of this.receiversWithOk) {
386
+ receiver({ value: this.zeroValue, ok: false })
399
387
  }
388
+ this.receiversWithOk = []
389
+ }
390
+
391
+ /**
392
+ * Checks if the channel has data ready to be received without blocking.
393
+ * Used for non-blocking select operations.
394
+ */
395
+ canReceiveNonBlocking(): boolean {
396
+ return this.buffer.length > 0 || this.closed
397
+ }
398
+
399
+ /**
400
+ * Checks if the channel can accept a send operation without blocking.
401
+ * Used for non-blocking select operations.
402
+ */
403
+ canSendNonBlocking(): boolean {
404
+ return !this.closed && this.buffer.length < this.capacity
405
+ }
400
406
  }
401
407
 
402
408
  /**
403
409
  * Represents a case in a select statement.
404
410
  */
405
411
  export interface SelectCase<T> {
406
- id: number;
407
- isSend: boolean; // true for send, false for receive
408
- channel: Channel<any>;
409
- value?: any; // Value to send for send cases
410
- // Optional handlers for when this case is selected
411
- onSelected?: (result: SelectResult<T>) => Promise<void>;
412
+ id: number
413
+ isSend: boolean // true for send, false for receive
414
+ channel: Channel<any>
415
+ value?: any // Value to send for send cases
416
+ // Optional handlers for when this case is selected
417
+ onSelected?: (result: SelectResult<T>) => Promise<void>
412
418
  }
413
419
 
414
-
415
420
  /**
416
421
  * Helper for 'select' statements. Takes an array of select cases
417
422
  * and resolves when one of them completes, following Go's select rules.
@@ -421,79 +426,91 @@ export interface SelectCase<T> {
421
426
  * @returns A promise that resolves with the result of the selected case
422
427
  */
423
428
  export async function selectStatement<T>(
424
- cases: SelectCase<T>[],
425
- hasDefault: boolean = false
429
+ cases: SelectCase<T>[],
430
+ hasDefault: boolean = false,
426
431
  ): Promise<void> {
427
- if (cases.length === 0 && !hasDefault) {
428
- // Go spec: If there are no cases, the select statement blocks forever.
429
- // Emulate blocking forever with a promise that never resolves.
430
- return new Promise<void>(() => {}); // Promise never resolves
432
+ if (cases.length === 0 && !hasDefault) {
433
+ // Go spec: If there are no cases, the select statement blocks forever.
434
+ // Emulate blocking forever with a promise that never resolves.
435
+ return new Promise<void>(() => {}) // Promise never resolves
436
+ }
437
+
438
+ // 1. Check for ready (non-blocking) operations
439
+ const readyCases: SelectCase<T>[] = []
440
+ for (const caseObj of cases) {
441
+ if (caseObj.id === -1) {
442
+ // Skip default case in this check
443
+ continue
431
444
  }
432
-
433
- // 1. Check for ready (non-blocking) operations
434
- const readyCases: SelectCase<T>[] = [];
435
- for (const caseObj of cases) {
436
- if (caseObj.id === -1) { // Skip default case in this check
437
- continue
438
- }
439
- if (caseObj.isSend) {
440
- if (caseObj.channel.canSendNonBlocking()) {
441
- readyCases.push(caseObj);
442
- }
443
- } else {
444
- if (caseObj.channel.canReceiveNonBlocking()) {
445
- readyCases.push(caseObj);
446
- }
447
- }
445
+ if (caseObj.isSend) {
446
+ if (caseObj.channel.canSendNonBlocking()) {
447
+ readyCases.push(caseObj)
448
+ }
449
+ } else {
450
+ if (caseObj.channel.canReceiveNonBlocking()) {
451
+ readyCases.push(caseObj)
452
+ }
448
453
  }
449
-
450
- if (readyCases.length > 0) {
451
- // If one or more cases are ready, choose one pseudo-randomly
452
- const selectedCase = readyCases[Math.floor(Math.random() * readyCases.length)];
453
-
454
- // Execute the selected operation and its onSelected handler
455
- if (selectedCase.isSend) {
456
- const result = await selectedCase.channel.selectSend(selectedCase.value, selectedCase.id);
457
- if (selectedCase.onSelected) {
458
- await selectedCase.onSelected(result as SelectResult<T>); // Await the handler
459
- }
460
- } else {
461
- const result = await selectedCase.channel.selectReceive(selectedCase.id);
462
- if (selectedCase.onSelected) {
463
- await selectedCase.onSelected(result); // Await the handler
464
- }
465
- }
466
- return; // Return after executing a ready case
454
+ }
455
+
456
+ if (readyCases.length > 0) {
457
+ // If one or more cases are ready, choose one pseudo-randomly
458
+ const selectedCase =
459
+ readyCases[Math.floor(Math.random() * readyCases.length)]
460
+
461
+ // Execute the selected operation and its onSelected handler
462
+ if (selectedCase.isSend) {
463
+ const result = await selectedCase.channel.selectSend(
464
+ selectedCase.value,
465
+ selectedCase.id,
466
+ )
467
+ if (selectedCase.onSelected) {
468
+ await selectedCase.onSelected(result as SelectResult<T>) // Await the handler
469
+ }
470
+ } else {
471
+ const result = await selectedCase.channel.selectReceive(selectedCase.id)
472
+ if (selectedCase.onSelected) {
473
+ await selectedCase.onSelected(result) // Await the handler
474
+ }
467
475
  }
468
-
469
- // 2. If no operations are ready and there's a default case, select default
470
- if (hasDefault) {
471
- // Find the default case (it will have id -1)
472
- const defaultCase = cases.find(c => c.id === -1);
473
- if (defaultCase && defaultCase.onSelected) {
474
- // Execute the onSelected handler for the default case
475
- await defaultCase.onSelected({ value: undefined, ok: false, id: -1 } as SelectResult<T>); // Await the handler
476
- }
477
- return; // Return after executing the default case
476
+ return // Return after executing a ready case
477
+ }
478
+
479
+ // 2. If no operations are ready and there's a default case, select default
480
+ if (hasDefault) {
481
+ // Find the default case (it will have id -1)
482
+ const defaultCase = cases.find((c) => c.id === -1)
483
+ if (defaultCase && defaultCase.onSelected) {
484
+ // Execute the onSelected handler for the default case
485
+ await defaultCase.onSelected({
486
+ value: undefined,
487
+ ok: false,
488
+ id: -1,
489
+ } as SelectResult<T>) // Await the handler
478
490
  }
479
-
480
- // 3. If no operations are ready and no default case, block until one is ready
481
- // Use Promise.race on the blocking promises
482
- const blockingPromises = cases.filter(c => c.id !== -1).map(caseObj => { // Exclude default case
483
- if (caseObj.isSend) {
484
- return caseObj.channel.selectSend(caseObj.value, caseObj.id);
485
- } else {
486
- return caseObj.channel.selectReceive(caseObj.id);
487
- }
488
- });
489
-
490
- const result = await Promise.race(blockingPromises);
491
- // Execute onSelected handler for the selected case
492
- const selectedCase = cases.find(c => c.id === result.id);
493
- if (selectedCase && selectedCase.onSelected) {
494
- await selectedCase.onSelected(result); // Await the handler
495
- }
496
- // No explicit return needed here, as the function will implicitly return after the await
491
+ return // Return after executing the default case
492
+ }
493
+
494
+ // 3. If no operations are ready and no default case, block until one is ready
495
+ // Use Promise.race on the blocking promises
496
+ const blockingPromises = cases
497
+ .filter((c) => c.id !== -1)
498
+ .map((caseObj) => {
499
+ // Exclude default case
500
+ if (caseObj.isSend) {
501
+ return caseObj.channel.selectSend(caseObj.value, caseObj.id)
502
+ } else {
503
+ return caseObj.channel.selectReceive(caseObj.id)
504
+ }
505
+ })
506
+
507
+ const result = await Promise.race(blockingPromises)
508
+ // Execute onSelected handler for the selected case
509
+ const selectedCase = cases.find((c) => c.id === result.id)
510
+ if (selectedCase && selectedCase.onSelected) {
511
+ await selectedCase.onSelected(result) // Await the handler
512
+ }
513
+ // No explicit return needed here, as the function will implicitly return after the await
497
514
  }
498
515
 
499
516
  /**
@@ -502,6 +519,9 @@ export async function selectStatement<T>(
502
519
  * @param zeroValue The zero value for the channel's element type.
503
520
  * @returns A new channel instance.
504
521
  */
505
- export const makeChannel = <T>(bufferSize: number, zeroValue: T): Channel<T> => {
506
- return new BufferedChannel<T>(bufferSize, zeroValue);
507
- };
522
+ export const makeChannel = <T>(
523
+ bufferSize: number,
524
+ zeroValue: T,
525
+ ): Channel<T> => {
526
+ return new BufferedChannel<T>(bufferSize, zeroValue)
527
+ }