goscript 0.0.16 → 0.0.18
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/LICENSE +1 -1
- package/README.md +3 -1
- package/builtin/builtin.ts +323 -45
- package/compiler/compiler.go +537 -140
- package/compiler/writer.go +14 -0
- package/dist/builtin/builtin.d.ts +79 -6
- package/dist/builtin/builtin.js +228 -37
- package/dist/builtin/builtin.js.map +1 -1
- package/go.mod +1 -3
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2024-2025 Aperture Robotics, LLC.
|
|
4
|
-
Copyright (c) 2019-2025 Christian Stewart
|
|
4
|
+
Copyright (c) 2019-2025 Christian Stewart <christian@cjs.zip>
|
|
5
5
|
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# GoScript
|
|
2
2
|
|
|
3
|
-
[![GoDoc Widget]][GoDoc] [![Go Report Card Widget]][Go Report Card]
|
|
3
|
+
[![GoDoc Widget]][GoDoc] [![Go Report Card Widget]][Go Report Card] [![DeepWiki Widget]][DeepWiki]
|
|
4
4
|
|
|
5
5
|
[GoDoc]: https://godoc.org/github.com/aperturerobotics/goscript
|
|
6
6
|
[GoDoc Widget]: https://godoc.org/github.com/aperturerobotics/goscript?status.svg
|
|
7
7
|
[Go Report Card Widget]: https://goreportcard.com/badge/github.com/aperturerobotics/goscript
|
|
8
8
|
[Go Report Card]: https://goreportcard.com/report/github.com/aperturerobotics/goscript
|
|
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
|
+
[DeepWiki]: https://deepwiki.com/aperturerobotics/goscript
|
|
9
11
|
|
|
10
12
|
## Introduction
|
|
11
13
|
|
package/builtin/builtin.ts
CHANGED
|
@@ -731,8 +731,7 @@ export interface StructTypeInfo extends BaseTypeInfo {
|
|
|
731
731
|
kind: TypeKind.Struct
|
|
732
732
|
methods: Set<string>
|
|
733
733
|
ctor?: new (...args: any[]) => any
|
|
734
|
-
fields
|
|
735
|
-
fieldTypes?: Record<string, TypeInfo | string> // Types for struct fields
|
|
734
|
+
fields: Record<string, TypeInfo | string> // Field names and types for struct fields
|
|
736
735
|
}
|
|
737
736
|
|
|
738
737
|
/**
|
|
@@ -870,13 +869,15 @@ export const registerStructType = (
|
|
|
870
869
|
zeroValue: any,
|
|
871
870
|
methods: Set<string>,
|
|
872
871
|
ctor: new (...args: any[]) => any,
|
|
872
|
+
fields: Record<string, TypeInfo | string> = {},
|
|
873
873
|
): StructTypeInfo => {
|
|
874
874
|
const typeInfo: StructTypeInfo = {
|
|
875
875
|
name,
|
|
876
876
|
kind: TypeKind.Struct,
|
|
877
877
|
zeroValue,
|
|
878
878
|
methods,
|
|
879
|
-
ctor
|
|
879
|
+
ctor,
|
|
880
|
+
fields,
|
|
880
881
|
}
|
|
881
882
|
typeRegistry.set(name, typeInfo)
|
|
882
883
|
return typeInfo
|
|
@@ -992,24 +993,35 @@ function matchesStructType(value: any, info: TypeInfo): boolean {
|
|
|
992
993
|
return true
|
|
993
994
|
}
|
|
994
995
|
|
|
995
|
-
if (info.
|
|
996
|
-
|
|
997
|
-
|
|
996
|
+
if (info.methods && typeof value === 'object' && value !== null) {
|
|
997
|
+
const allMethodsMatch = Array.from(info.methods).every(
|
|
998
|
+
(method) => typeof value[method] === 'function',
|
|
999
|
+
)
|
|
1000
|
+
if (allMethodsMatch) {
|
|
1001
|
+
return true
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
if (typeof value === 'object' && value !== null) {
|
|
1006
|
+
const fieldNames = Object.keys(info.fields || {})
|
|
998
1007
|
const valueFields = Object.keys(value)
|
|
999
1008
|
|
|
1000
|
-
const
|
|
1001
|
-
const
|
|
1002
|
-
const
|
|
1009
|
+
const fieldsExist = fieldNames.every((field) => field in value)
|
|
1010
|
+
const sameFieldCount = valueFields.length === fieldNames.length
|
|
1011
|
+
const allFieldsInStruct = valueFields.every((field) =>
|
|
1012
|
+
fieldNames.includes(field),
|
|
1013
|
+
)
|
|
1003
1014
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1015
|
+
if (fieldsExist && sameFieldCount && allFieldsInStruct) {
|
|
1016
|
+
return Object.entries(info.fields).every(([fieldName, fieldType]) => {
|
|
1017
|
+
return matchesType(
|
|
1018
|
+
value[fieldName],
|
|
1019
|
+
normalizeTypeInfo(fieldType as TypeInfo | string),
|
|
1020
|
+
)
|
|
1021
|
+
})
|
|
1022
|
+
}
|
|
1011
1023
|
|
|
1012
|
-
return
|
|
1024
|
+
return false
|
|
1013
1025
|
}
|
|
1014
1026
|
|
|
1015
1027
|
return false
|
|
@@ -1126,9 +1138,10 @@ function matchesArrayOrSliceType(value: any, info: TypeInfo): boolean {
|
|
|
1126
1138
|
* @returns True if the value matches the pointer type, false otherwise.
|
|
1127
1139
|
*/
|
|
1128
1140
|
function matchesPointerType(value: any, info: TypeInfo): boolean {
|
|
1129
|
-
//
|
|
1141
|
+
// Allow null/undefined values to match pointer types to support nil pointer assertions
|
|
1142
|
+
// This enables Go's nil pointer type assertions like `ptr, ok := i.(*SomeType)` to work correctly
|
|
1130
1143
|
if (value === null || value === undefined) {
|
|
1131
|
-
return
|
|
1144
|
+
return true
|
|
1132
1145
|
}
|
|
1133
1146
|
|
|
1134
1147
|
// Check if the value is a Box (has a 'value' property)
|
|
@@ -1153,9 +1166,18 @@ function matchesPointerType(value: any, info: TypeInfo): boolean {
|
|
|
1153
1166
|
* @param info The function type info to match against.
|
|
1154
1167
|
* @returns True if the value matches the function type, false otherwise.
|
|
1155
1168
|
*/
|
|
1156
|
-
function matchesFunctionType(value: any, info:
|
|
1157
|
-
//
|
|
1158
|
-
|
|
1169
|
+
function matchesFunctionType(value: any, info: FunctionTypeInfo): boolean {
|
|
1170
|
+
// First check if the value is a function
|
|
1171
|
+
if (typeof value !== 'function') {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// This is important for named function types
|
|
1176
|
+
if (info.name && value.__goTypeName) {
|
|
1177
|
+
return info.name === value.__goTypeName;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
return true;
|
|
1159
1181
|
}
|
|
1160
1182
|
|
|
1161
1183
|
/**
|
|
@@ -1165,17 +1187,56 @@ function matchesFunctionType(value: any, info: TypeInfo): boolean {
|
|
|
1165
1187
|
* @param info The channel type info to match against.
|
|
1166
1188
|
* @returns True if the value matches the channel type, false otherwise.
|
|
1167
1189
|
*/
|
|
1168
|
-
function matchesChannelType(value: any, info:
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
)
|
|
1190
|
+
function matchesChannelType(value: any, info: ChannelTypeInfo): boolean {
|
|
1191
|
+
// First check if it's a channel or channel reference
|
|
1192
|
+
if (typeof value !== 'object' || value === null) {
|
|
1193
|
+
return false
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// If it's a ChannelRef, get the underlying channel
|
|
1197
|
+
let channel = value
|
|
1198
|
+
let valueDirection = 'both'
|
|
1199
|
+
|
|
1200
|
+
if ('channel' in value && 'direction' in value) {
|
|
1201
|
+
channel = value.channel
|
|
1202
|
+
valueDirection = value.direction
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Check if it has channel methods
|
|
1206
|
+
if (
|
|
1207
|
+
!('send' in channel) ||
|
|
1208
|
+
!('receive' in channel) ||
|
|
1209
|
+
!('close' in channel) ||
|
|
1210
|
+
typeof channel.send !== 'function' ||
|
|
1211
|
+
typeof channel.receive !== 'function' ||
|
|
1212
|
+
typeof channel.close !== 'function'
|
|
1213
|
+
) {
|
|
1214
|
+
return false
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
if (info.elemType) {
|
|
1218
|
+
if (
|
|
1219
|
+
info.elemType === 'string' &&
|
|
1220
|
+
'zeroValue' in channel &&
|
|
1221
|
+
channel.zeroValue !== ''
|
|
1222
|
+
) {
|
|
1223
|
+
return false
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
if (
|
|
1227
|
+
info.elemType === 'number' &&
|
|
1228
|
+
'zeroValue' in channel &&
|
|
1229
|
+
typeof channel.zeroValue !== 'number'
|
|
1230
|
+
) {
|
|
1231
|
+
return false
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
if (info.direction) {
|
|
1236
|
+
return valueDirection === info.direction
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
return true
|
|
1179
1240
|
}
|
|
1180
1241
|
|
|
1181
1242
|
/**
|
|
@@ -1211,7 +1272,7 @@ function matchesType(value: any, info: TypeInfo): boolean {
|
|
|
1211
1272
|
return matchesPointerType(value, info)
|
|
1212
1273
|
|
|
1213
1274
|
case TypeKind.Function:
|
|
1214
|
-
return matchesFunctionType(value, info)
|
|
1275
|
+
return matchesFunctionType(value, info as FunctionTypeInfo)
|
|
1215
1276
|
|
|
1216
1277
|
case TypeKind.Channel:
|
|
1217
1278
|
return matchesChannelType(value, info)
|
|
@@ -1230,23 +1291,57 @@ export function typeAssert<T>(
|
|
|
1230
1291
|
): TypeAssertResult<T> {
|
|
1231
1292
|
const normalizedType = normalizeTypeInfo(typeInfo)
|
|
1232
1293
|
|
|
1294
|
+
if (isPointerTypeInfo(normalizedType) && value === null) {
|
|
1295
|
+
return { value: null as unknown as T, ok: true }
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
if (
|
|
1299
|
+
isStructTypeInfo(normalizedType) &&
|
|
1300
|
+
normalizedType.methods &&
|
|
1301
|
+
typeof value === 'object' &&
|
|
1302
|
+
value !== null
|
|
1303
|
+
) {
|
|
1304
|
+
// Check if the value implements all methods of the struct type
|
|
1305
|
+
const allMethodsMatch = Array.from(normalizedType.methods).every(
|
|
1306
|
+
(method) => typeof value[method] === 'function',
|
|
1307
|
+
)
|
|
1308
|
+
|
|
1309
|
+
const hasAnyMethod = Array.from(normalizedType.methods).some(
|
|
1310
|
+
(method) => typeof value[method] === 'function',
|
|
1311
|
+
)
|
|
1312
|
+
|
|
1313
|
+
if (allMethodsMatch && hasAnyMethod && normalizedType.methods.size > 0) {
|
|
1314
|
+
// For interface-to-concrete type assertions, we just need to check methods
|
|
1315
|
+
return { value: value as T, ok: true }
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1233
1319
|
if (
|
|
1234
1320
|
isStructTypeInfo(normalizedType) &&
|
|
1235
1321
|
normalizedType.fields &&
|
|
1236
1322
|
typeof value === 'object' &&
|
|
1237
1323
|
value !== null
|
|
1238
1324
|
) {
|
|
1239
|
-
const
|
|
1325
|
+
const fieldNames = Object.keys(normalizedType.fields)
|
|
1240
1326
|
const valueFields = Object.keys(value)
|
|
1241
1327
|
|
|
1242
1328
|
// For struct type assertions, we need exact field matching
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
valueFields.every((field) =>
|
|
1329
|
+
const structFieldsMatch =
|
|
1330
|
+
fieldNames.length === valueFields.length &&
|
|
1331
|
+
fieldNames.every((field: string) => field in value) &&
|
|
1332
|
+
valueFields.every((field) => fieldNames.includes(field))
|
|
1333
|
+
|
|
1334
|
+
if (structFieldsMatch) {
|
|
1335
|
+
const typesMatch = Object.entries(normalizedType.fields).every(
|
|
1336
|
+
([fieldName, fieldType]) => {
|
|
1337
|
+
return matchesType(
|
|
1338
|
+
value[fieldName],
|
|
1339
|
+
normalizeTypeInfo(fieldType as TypeInfo | string),
|
|
1340
|
+
)
|
|
1341
|
+
},
|
|
1342
|
+
)
|
|
1247
1343
|
|
|
1248
|
-
|
|
1249
|
-
return { value: value as T, ok: true }
|
|
1344
|
+
return { value: value as T, ok: typesMatch }
|
|
1250
1345
|
} else {
|
|
1251
1346
|
return { value: null as unknown as T, ok: false }
|
|
1252
1347
|
}
|
|
@@ -1614,13 +1709,185 @@ class BufferedChannel<T> implements Channel<T> {
|
|
|
1614
1709
|
}
|
|
1615
1710
|
}
|
|
1616
1711
|
|
|
1712
|
+
/**
|
|
1713
|
+
* Represents a reference to a channel with a specific direction.
|
|
1714
|
+
*/
|
|
1715
|
+
export interface ChannelRef<T> {
|
|
1716
|
+
/**
|
|
1717
|
+
* The underlying channel
|
|
1718
|
+
*/
|
|
1719
|
+
channel: Channel<T>
|
|
1720
|
+
|
|
1721
|
+
/**
|
|
1722
|
+
* The direction of this channel reference
|
|
1723
|
+
*/
|
|
1724
|
+
direction: 'send' | 'receive' | 'both'
|
|
1725
|
+
|
|
1726
|
+
// Channel methods
|
|
1727
|
+
send(value: T): Promise<void>
|
|
1728
|
+
receive(): Promise<T>
|
|
1729
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>>
|
|
1730
|
+
close(): void
|
|
1731
|
+
canSendNonBlocking(): boolean
|
|
1732
|
+
canReceiveNonBlocking(): boolean
|
|
1733
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>>
|
|
1734
|
+
selectReceive(id: number): Promise<SelectResult<T>>
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
/**
|
|
1738
|
+
* A bidirectional channel reference.
|
|
1739
|
+
*/
|
|
1740
|
+
export class BidirectionalChannelRef<T> implements ChannelRef<T> {
|
|
1741
|
+
direction: 'both' = 'both'
|
|
1742
|
+
|
|
1743
|
+
constructor(public channel: Channel<T>) {}
|
|
1744
|
+
|
|
1745
|
+
// Delegate all methods to the underlying channel
|
|
1746
|
+
send(value: T): Promise<void> {
|
|
1747
|
+
return this.channel.send(value)
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
receive(): Promise<T> {
|
|
1751
|
+
return this.channel.receive()
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>> {
|
|
1755
|
+
return this.channel.receiveWithOk()
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
close(): void {
|
|
1759
|
+
this.channel.close()
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
canSendNonBlocking(): boolean {
|
|
1763
|
+
return this.channel.canSendNonBlocking()
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
canReceiveNonBlocking(): boolean {
|
|
1767
|
+
return this.channel.canReceiveNonBlocking()
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>> {
|
|
1771
|
+
return this.channel.selectSend(value, id)
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
selectReceive(id: number): Promise<SelectResult<T>> {
|
|
1775
|
+
return this.channel.selectReceive(id)
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* A send-only channel reference.
|
|
1781
|
+
*/
|
|
1782
|
+
export class SendOnlyChannelRef<T> implements ChannelRef<T> {
|
|
1783
|
+
direction: 'send' = 'send'
|
|
1784
|
+
|
|
1785
|
+
constructor(public channel: Channel<T>) {}
|
|
1786
|
+
|
|
1787
|
+
// Allow send operations
|
|
1788
|
+
send(value: T): Promise<void> {
|
|
1789
|
+
return this.channel.send(value)
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// Allow close operations
|
|
1793
|
+
close(): void {
|
|
1794
|
+
this.channel.close()
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
canSendNonBlocking(): boolean {
|
|
1798
|
+
return this.channel.canSendNonBlocking()
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>> {
|
|
1802
|
+
return this.channel.selectSend(value, id)
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// Disallow receive operations
|
|
1806
|
+
receive(): Promise<T> {
|
|
1807
|
+
throw new Error('Cannot receive from send-only channel')
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>> {
|
|
1811
|
+
throw new Error('Cannot receive from send-only channel')
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
canReceiveNonBlocking(): boolean {
|
|
1815
|
+
return false
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
selectReceive(id: number): Promise<SelectResult<T>> {
|
|
1819
|
+
throw new Error('Cannot receive from send-only channel')
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
/**
|
|
1824
|
+
* A receive-only channel reference.
|
|
1825
|
+
*/
|
|
1826
|
+
export class ReceiveOnlyChannelRef<T> implements ChannelRef<T> {
|
|
1827
|
+
direction: 'receive' = 'receive'
|
|
1828
|
+
|
|
1829
|
+
constructor(public channel: Channel<T>) {}
|
|
1830
|
+
|
|
1831
|
+
// Allow receive operations
|
|
1832
|
+
receive(): Promise<T> {
|
|
1833
|
+
return this.channel.receive()
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>> {
|
|
1837
|
+
return this.channel.receiveWithOk()
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
canReceiveNonBlocking(): boolean {
|
|
1841
|
+
return this.channel.canReceiveNonBlocking()
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
selectReceive(id: number): Promise<SelectResult<T>> {
|
|
1845
|
+
return this.channel.selectReceive(id)
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
// Disallow send operations
|
|
1849
|
+
send(value: T): Promise<void> {
|
|
1850
|
+
throw new Error('Cannot send to receive-only channel')
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
// Disallow close operations
|
|
1854
|
+
close(): void {
|
|
1855
|
+
throw new Error('Cannot close receive-only channel')
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
canSendNonBlocking(): boolean {
|
|
1859
|
+
return false
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>> {
|
|
1863
|
+
throw new Error('Cannot send to receive-only channel')
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* Creates a new channel reference with the specified direction.
|
|
1869
|
+
*/
|
|
1870
|
+
export function makeChannelRef<T>(
|
|
1871
|
+
channel: Channel<T>,
|
|
1872
|
+
direction: 'send' | 'receive' | 'both',
|
|
1873
|
+
): ChannelRef<T> {
|
|
1874
|
+
switch (direction) {
|
|
1875
|
+
case 'send':
|
|
1876
|
+
return new SendOnlyChannelRef<T>(channel)
|
|
1877
|
+
case 'receive':
|
|
1878
|
+
return new ReceiveOnlyChannelRef<T>(channel)
|
|
1879
|
+
default: // 'both'
|
|
1880
|
+
return new BidirectionalChannelRef<T>(channel)
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1617
1884
|
/**
|
|
1618
1885
|
* Represents a case in a select statement.
|
|
1619
1886
|
*/
|
|
1620
1887
|
export interface SelectCase<T> {
|
|
1621
1888
|
id: number
|
|
1622
1889
|
isSend: boolean // true for send, false for receive
|
|
1623
|
-
channel: Channel<any> | null // Allow null
|
|
1890
|
+
channel: Channel<any> | ChannelRef<any> | null // Allow null and ChannelRef
|
|
1624
1891
|
value?: any // Value to send for send cases
|
|
1625
1892
|
// Optional handlers for when this case is selected
|
|
1626
1893
|
onSelected?: (result: SelectResult<T>) => Promise<void>
|
|
@@ -1736,13 +2003,24 @@ export async function selectStatement<T>(
|
|
|
1736
2003
|
* Creates a new channel with the specified buffer size and zero value.
|
|
1737
2004
|
* @param bufferSize The size of the channel buffer. If 0, creates an unbuffered channel.
|
|
1738
2005
|
* @param zeroValue The zero value for the channel's element type.
|
|
1739
|
-
* @
|
|
2006
|
+
* @param direction Optional direction for the channel. Default is 'both' (bidirectional).
|
|
2007
|
+
* @returns A new channel instance or channel reference.
|
|
1740
2008
|
*/
|
|
1741
2009
|
export const makeChannel = <T>(
|
|
1742
2010
|
bufferSize: number,
|
|
1743
2011
|
zeroValue: T,
|
|
1744
|
-
|
|
1745
|
-
|
|
2012
|
+
direction: 'send' | 'receive' | 'both' = 'both',
|
|
2013
|
+
): Channel<T> | ChannelRef<T> => {
|
|
2014
|
+
const channel = new BufferedChannel<T>(bufferSize, zeroValue)
|
|
2015
|
+
|
|
2016
|
+
// Wrap the channel with the appropriate ChannelRef based on direction
|
|
2017
|
+
if (direction === 'send') {
|
|
2018
|
+
return new SendOnlyChannelRef<T>(channel) as ChannelRef<T>
|
|
2019
|
+
} else if (direction === 'receive') {
|
|
2020
|
+
return new ReceiveOnlyChannelRef<T>(channel) as ChannelRef<T>
|
|
2021
|
+
} else {
|
|
2022
|
+
return channel
|
|
2023
|
+
}
|
|
1746
2024
|
}
|
|
1747
2025
|
|
|
1748
2026
|
/**
|