goscript 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/compiler/analysis.go +974 -369
- package/compiler/assignment.go +72 -0
- package/compiler/compiler.go +74 -15
- package/compiler/composite-lit.go +29 -8
- package/compiler/decl.go +67 -98
- package/compiler/expr-call-async.go +26 -1
- package/compiler/expr-call-builtins.go +60 -4
- package/compiler/expr-call-helpers.go +182 -0
- package/compiler/expr-call-type-conversion.go +37 -5
- package/compiler/expr-call.go +25 -33
- package/compiler/expr-selector.go +71 -1
- package/compiler/expr-type.go +49 -3
- package/compiler/expr.go +37 -28
- package/compiler/index.test.ts +3 -1
- package/compiler/lit.go +13 -4
- package/compiler/spec-struct.go +42 -9
- package/compiler/spec-value.go +2 -2
- package/compiler/spec.go +42 -5
- package/compiler/stmt-assign.go +71 -0
- package/compiler/stmt-range.go +2 -2
- package/compiler/stmt.go +130 -10
- package/compiler/type-utils.go +40 -16
- package/compiler/type.go +50 -12
- package/dist/gs/builtin/builtin.d.ts +8 -1
- package/dist/gs/builtin/builtin.js +26 -1
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/errors.d.ts +1 -0
- package/dist/gs/builtin/errors.js +8 -0
- package/dist/gs/builtin/errors.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +5 -4
- package/dist/gs/builtin/slice.js +51 -21
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +28 -2
- package/dist/gs/builtin/type.js +132 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/reader.gs.d.ts +1 -1
- package/dist/gs/bytes/reader.gs.js +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +6 -0
- package/dist/gs/internal/byteorder/index.js +34 -0
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +3 -3
- package/dist/gs/reflect/index.js +2 -2
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.d.ts +3 -2
- package/dist/gs/reflect/map.js +37 -3
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +55 -8
- package/dist/gs/reflect/type.js +889 -23
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +11 -12
- package/dist/gs/reflect/types.js +26 -15
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +4 -4
- package/dist/gs/reflect/value.js +8 -2
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +32 -0
- package/dist/gs/slices/slices.js +81 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +2 -2
- package/dist/gs/sync/atomic/type.gs.js +12 -2
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/unicode/utf8/utf8.d.ts +2 -2
- package/dist/gs/unicode/utf8/utf8.js +10 -6
- package/dist/gs/unicode/utf8/utf8.js.map +1 -1
- package/go.mod +4 -4
- package/go.sum +8 -16
- package/gs/builtin/builtin.ts +27 -2
- package/gs/builtin/errors.ts +12 -0
- package/gs/builtin/slice.ts +77 -14
- package/gs/builtin/type.ts +167 -2
- package/gs/bytes/reader.gs.ts +2 -2
- package/gs/internal/byteorder/index.ts +40 -0
- package/gs/math/hypot.gs.test.ts +3 -1
- package/gs/math/pow10.gs.test.ts +5 -4
- package/gs/reflect/index.ts +6 -3
- package/gs/reflect/map.test.ts +7 -6
- package/gs/reflect/map.ts +49 -7
- package/gs/reflect/type.ts +1139 -43
- package/gs/reflect/types.ts +34 -21
- package/gs/reflect/value.ts +12 -6
- package/gs/slices/slices.ts +92 -0
- package/gs/sync/atomic/type.gs.ts +14 -5
- package/gs/sync/meta.json +1 -1
- package/gs/unicode/utf8/utf8.ts +12 -8
- package/package.json +13 -13
package/gs/builtin/type.ts
CHANGED
|
@@ -39,6 +39,14 @@ export interface MethodSignature {
|
|
|
39
39
|
returns: MethodArg[]
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Information about a struct field including type and optional tag
|
|
44
|
+
*/
|
|
45
|
+
export interface StructFieldInfo {
|
|
46
|
+
type: TypeInfo | string // The field's type
|
|
47
|
+
tag?: string // The struct field tag (e.g., `json:"name,omitempty"`)
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
/**
|
|
43
51
|
* Type information for struct types
|
|
44
52
|
*/
|
|
@@ -46,7 +54,7 @@ export interface StructTypeInfo extends BaseTypeInfo {
|
|
|
46
54
|
kind: TypeKind.Struct
|
|
47
55
|
methods: MethodSignature[] // Array of method signatures
|
|
48
56
|
ctor?: new (...args: any[]) => any
|
|
49
|
-
fields: Record<string, TypeInfo | string> // Field names and types for struct fields
|
|
57
|
+
fields: Record<string, TypeInfo | string | StructFieldInfo> // Field names and types for struct fields
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
/**
|
|
@@ -170,6 +178,21 @@ export function isChannelTypeInfo(info: TypeInfo): info is ChannelTypeInfo {
|
|
|
170
178
|
return info.kind === TypeKind.Channel
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Type guard to check if a field value is a StructFieldInfo (has 'type' property)
|
|
183
|
+
* vs a direct TypeInfo or string
|
|
184
|
+
*/
|
|
185
|
+
export function isStructFieldInfo(
|
|
186
|
+
fieldValue: TypeInfo | string | StructFieldInfo,
|
|
187
|
+
): fieldValue is StructFieldInfo {
|
|
188
|
+
return (
|
|
189
|
+
typeof fieldValue === 'object' &&
|
|
190
|
+
fieldValue !== null &&
|
|
191
|
+
'type' in fieldValue &&
|
|
192
|
+
!('kind' in fieldValue)
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
173
196
|
/**
|
|
174
197
|
* Comparable interface for Go's comparable constraint.
|
|
175
198
|
* Types that implement this can be compared with == and !=.
|
|
@@ -196,7 +219,7 @@ export const registerStructType = (
|
|
|
196
219
|
zeroValue: any,
|
|
197
220
|
methods: MethodSignature[],
|
|
198
221
|
ctor: new (...args: any[]) => any,
|
|
199
|
-
fields: Record<string, TypeInfo | string> = {},
|
|
222
|
+
fields: Record<string, TypeInfo | string | StructFieldInfo> = {},
|
|
200
223
|
): StructTypeInfo => {
|
|
201
224
|
const typeInfo: StructTypeInfo = {
|
|
202
225
|
name,
|
|
@@ -233,6 +256,14 @@ export const registerInterfaceType = (
|
|
|
233
256
|
return typeInfo
|
|
234
257
|
}
|
|
235
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Gets a registered type by name from the type registry.
|
|
261
|
+
* Returns undefined if the type is not registered.
|
|
262
|
+
*/
|
|
263
|
+
export const getTypeByName = (name: string): TypeInfo | undefined => {
|
|
264
|
+
return typeRegistry.get(name)
|
|
265
|
+
}
|
|
266
|
+
|
|
236
267
|
/**
|
|
237
268
|
* Represents the result of a type assertion.
|
|
238
269
|
*/
|
|
@@ -860,6 +891,110 @@ function matchesType(value: any, info: TypeInfo): boolean {
|
|
|
860
891
|
}
|
|
861
892
|
}
|
|
862
893
|
|
|
894
|
+
/**
|
|
895
|
+
* Compares a Go type string (from typedNil) with a TypeInfo object.
|
|
896
|
+
* Used to check if a typed nil pointer matches a type assertion target.
|
|
897
|
+
*
|
|
898
|
+
* @param typeStr The Go type string (e.g., "*struct{Name string}")
|
|
899
|
+
* @param typeInfo The normalized TypeInfo to compare against
|
|
900
|
+
* @returns True if the types match, false otherwise
|
|
901
|
+
*/
|
|
902
|
+
function compareTypeStringWithTypeInfo(
|
|
903
|
+
typeStr: string,
|
|
904
|
+
typeInfo: TypeInfo,
|
|
905
|
+
): boolean {
|
|
906
|
+
// For pointer types, strip the leading * and compare element types
|
|
907
|
+
if (isPointerTypeInfo(typeInfo)) {
|
|
908
|
+
if (!typeStr.startsWith('*')) {
|
|
909
|
+
return false
|
|
910
|
+
}
|
|
911
|
+
const elemStr = typeStr.slice(1)
|
|
912
|
+
const elemType = typeInfo.elemType
|
|
913
|
+
if (!elemType) {
|
|
914
|
+
return false
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// Handle struct types
|
|
918
|
+
if (elemStr.startsWith('struct{')) {
|
|
919
|
+
const elemTypeInfo = normalizeTypeInfo(elemType)
|
|
920
|
+
if (!isStructTypeInfo(elemTypeInfo)) {
|
|
921
|
+
return false
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// For anonymous structs, compare the type string representation
|
|
925
|
+
// Extract field definitions from the string
|
|
926
|
+
const fieldsMatch = elemStr.match(/^struct{(.+)}$/)
|
|
927
|
+
if (!fieldsMatch) {
|
|
928
|
+
return false
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const fieldStr = fieldsMatch[1]
|
|
932
|
+
// Parse fields like "Name string" or "X int; Y string"
|
|
933
|
+
const fieldParts = fieldStr.split(';').map(s => s.trim())
|
|
934
|
+
const parsedFields: Record<string, string> = {}
|
|
935
|
+
|
|
936
|
+
for (const part of fieldParts) {
|
|
937
|
+
// Handle "Name string" format
|
|
938
|
+
const match = part.match(/^(\w+)\s+(.+)$/)
|
|
939
|
+
if (match) {
|
|
940
|
+
const [, fieldName, fieldType] = match
|
|
941
|
+
parsedFields[fieldName] = fieldType.trim()
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Compare fields
|
|
946
|
+
const typeInfoFields = elemTypeInfo.fields || {}
|
|
947
|
+
const typeInfoFieldNames = Object.keys(typeInfoFields)
|
|
948
|
+
const parsedFieldNames = Object.keys(parsedFields)
|
|
949
|
+
|
|
950
|
+
if (typeInfoFieldNames.length !== parsedFieldNames.length) {
|
|
951
|
+
return false
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// Check if all field names match and types are compatible
|
|
955
|
+
for (const fieldName of typeInfoFieldNames) {
|
|
956
|
+
if (!(fieldName in parsedFields)) {
|
|
957
|
+
return false
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
const fieldValue = typeInfoFields[fieldName]
|
|
961
|
+
// Handle StructFieldInfo (which has 'type' and optional 'tag' properties)
|
|
962
|
+
const fieldTypeInfo: TypeInfo | string = isStructFieldInfo(fieldValue)
|
|
963
|
+
? fieldValue.type
|
|
964
|
+
: fieldValue
|
|
965
|
+
const typeInfoFieldType = normalizeTypeInfo(fieldTypeInfo)
|
|
966
|
+
const parsedFieldType = parsedFields[fieldName]
|
|
967
|
+
|
|
968
|
+
// Compare basic types
|
|
969
|
+
if (isBasicTypeInfo(typeInfoFieldType)) {
|
|
970
|
+
const expectedTypeName = typeInfoFieldType.name || ''
|
|
971
|
+
// Map Go types to TypeScript/runtime types
|
|
972
|
+
if (expectedTypeName === 'string' && parsedFieldType === 'string') {
|
|
973
|
+
continue
|
|
974
|
+
}
|
|
975
|
+
if ((expectedTypeName === 'int' || expectedTypeName === 'number') &&
|
|
976
|
+
(parsedFieldType === 'int' || parsedFieldType === 'number')) {
|
|
977
|
+
continue
|
|
978
|
+
}
|
|
979
|
+
return false
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
return true
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Handle named types
|
|
987
|
+
if (typeof elemType === 'string') {
|
|
988
|
+
return elemStr === elemType
|
|
989
|
+
}
|
|
990
|
+
if (elemType.name) {
|
|
991
|
+
return elemStr === elemType.name
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
return false
|
|
996
|
+
}
|
|
997
|
+
|
|
863
998
|
/**
|
|
864
999
|
* Performs a type assertion on a value against a specified type.
|
|
865
1000
|
* Returns an object containing the value (cast to type T) and a boolean indicating success.
|
|
@@ -874,6 +1009,21 @@ export function typeAssert<T>(
|
|
|
874
1009
|
typeInfo: string | TypeInfo,
|
|
875
1010
|
): TypeAssertResult<T> {
|
|
876
1011
|
const normalizedType = normalizeTypeInfo(typeInfo)
|
|
1012
|
+
|
|
1013
|
+
// Handle typed nil pointers (created by typedNil() for conversions like (*T)(nil))
|
|
1014
|
+
if (typeof value === 'object' && value !== null && value.__isTypedNil) {
|
|
1015
|
+
// For typed nils, we need to compare the stored type with the expected type
|
|
1016
|
+
if (isPointerTypeInfo(normalizedType)) {
|
|
1017
|
+
// Parse the stored type string and compare with expected type
|
|
1018
|
+
const storedTypeStr = value.__goType as string
|
|
1019
|
+
if (compareTypeStringWithTypeInfo(storedTypeStr, normalizedType)) {
|
|
1020
|
+
return { value: null as unknown as T, ok: true }
|
|
1021
|
+
}
|
|
1022
|
+
return { value: null as unknown as T, ok: false }
|
|
1023
|
+
}
|
|
1024
|
+
return { value: null as unknown as T, ok: false }
|
|
1025
|
+
}
|
|
1026
|
+
|
|
877
1027
|
if (isPointerTypeInfo(normalizedType) && value === null) {
|
|
878
1028
|
return { value: null as unknown as T, ok: true }
|
|
879
1029
|
}
|
|
@@ -1053,3 +1203,18 @@ export function typeSwitch(
|
|
|
1053
1203
|
defaultCase()
|
|
1054
1204
|
}
|
|
1055
1205
|
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Creates a typed nil pointer with type metadata for reflection.
|
|
1209
|
+
* This is used for type conversions like (*Interface)(nil) where we need
|
|
1210
|
+
* to preserve the pointer type information even though the value is null.
|
|
1211
|
+
*
|
|
1212
|
+
* @param typeName The full Go type name (e.g., "*main.Stringer")
|
|
1213
|
+
* @returns An object that represents a typed nil with reflection metadata
|
|
1214
|
+
*/
|
|
1215
|
+
export function typedNil(typeName: string): any {
|
|
1216
|
+
return Object.assign(Object.create(null), {
|
|
1217
|
+
__goType: typeName,
|
|
1218
|
+
__isTypedNil: true,
|
|
1219
|
+
})
|
|
1220
|
+
}
|
package/gs/bytes/reader.gs.ts
CHANGED
|
@@ -224,7 +224,7 @@ export class Reader {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// NewReader returns a new [Reader] reading from b.
|
|
227
|
-
export function NewReader(b: $.Bytes): Reader
|
|
228
|
-
return new Reader({})
|
|
227
|
+
export function NewReader(b: $.Bytes): Reader {
|
|
228
|
+
return new Reader({s: $.normalizeBytes(b), i: 0, prevRune: -1})
|
|
229
229
|
}
|
|
230
230
|
|
|
@@ -38,3 +38,43 @@ export function LEUint64(b: $.Bytes): number {
|
|
|
38
38
|
let high = LEUint32($.goSlice(b, 4, undefined))
|
|
39
39
|
return low + high * 0x100000000
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
// Big Endian Put functions
|
|
43
|
+
export function BEPutUint16(b: $.Bytes, v: number): void {
|
|
44
|
+
b![0] = (v >> 8) & 0xff
|
|
45
|
+
b![1] = v & 0xff
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function BEPutUint32(b: $.Bytes, v: number): void {
|
|
49
|
+
b![0] = (v >> 24) & 0xff
|
|
50
|
+
b![1] = (v >> 16) & 0xff
|
|
51
|
+
b![2] = (v >> 8) & 0xff
|
|
52
|
+
b![3] = v & 0xff
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function BEPutUint64(b: $.Bytes, v: number): void {
|
|
56
|
+
const high = Math.floor(v / 0x100000000)
|
|
57
|
+
const low = v >>> 0
|
|
58
|
+
BEPutUint32(b, high)
|
|
59
|
+
BEPutUint32($.goSlice(b, 4, undefined), low)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Little Endian Put functions
|
|
63
|
+
export function LEPutUint16(b: $.Bytes, v: number): void {
|
|
64
|
+
b![0] = v & 0xff
|
|
65
|
+
b![1] = (v >> 8) & 0xff
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function LEPutUint32(b: $.Bytes, v: number): void {
|
|
69
|
+
b![0] = v & 0xff
|
|
70
|
+
b![1] = (v >> 8) & 0xff
|
|
71
|
+
b![2] = (v >> 16) & 0xff
|
|
72
|
+
b![3] = (v >> 24) & 0xff
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function LEPutUint64(b: $.Bytes, v: number): void {
|
|
76
|
+
const low = v >>> 0
|
|
77
|
+
const high = Math.floor(v / 0x100000000)
|
|
78
|
+
LEPutUint32(b, low)
|
|
79
|
+
LEPutUint32($.goSlice(b, 4, undefined), high)
|
|
80
|
+
}
|
package/gs/math/hypot.gs.test.ts
CHANGED
|
@@ -43,7 +43,9 @@ describe('Hypot', () => {
|
|
|
43
43
|
it('should handle very large values without overflow', () => {
|
|
44
44
|
const large = 1e150
|
|
45
45
|
const result = Hypot(large, large)
|
|
46
|
-
|
|
46
|
+
const expected = large * Math.sqrt(2)
|
|
47
|
+
// Use relative tolerance for very large numbers
|
|
48
|
+
expect(Math.abs(result - expected) / expected).toBeLessThan(1e-10)
|
|
47
49
|
expect(IsInf(result, 0)).toBe(false)
|
|
48
50
|
})
|
|
49
51
|
|
package/gs/math/pow10.gs.test.ts
CHANGED
|
@@ -26,10 +26,11 @@ describe('Pow10', () => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
it('should handle large positive exponents', () => {
|
|
29
|
-
|
|
30
|
-
expect(Pow10(
|
|
31
|
-
expect(Pow10(
|
|
32
|
-
expect(Pow10(
|
|
29
|
+
// Use relative tolerance for very large numbers
|
|
30
|
+
expect(Math.abs(Pow10(100) - 1e100) / 1e100).toBeLessThan(1e-10)
|
|
31
|
+
expect(Math.abs(Pow10(200) - 1e200) / 1e200).toBeLessThan(1e-10)
|
|
32
|
+
expect(Math.abs(Pow10(300) - 1e300) / 1e300).toBeLessThan(1e-10)
|
|
33
|
+
expect(Math.abs(Pow10(308) - 1e308) / 1e308).toBeLessThan(1e-10)
|
|
33
34
|
expect(Pow10(309)).toBe(Number.POSITIVE_INFINITY)
|
|
34
35
|
expect(Pow10(400)).toBe(Number.POSITIVE_INFINITY)
|
|
35
36
|
})
|
package/gs/reflect/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Export the main reflect functions organized like Go stdlib
|
|
2
2
|
export {
|
|
3
3
|
TypeOf,
|
|
4
|
+
TypeFor,
|
|
4
5
|
ValueOf,
|
|
5
6
|
Value,
|
|
6
7
|
Kind_String,
|
|
@@ -14,6 +15,7 @@ export {
|
|
|
14
15
|
RecvDir,
|
|
15
16
|
SendDir,
|
|
16
17
|
BothDir,
|
|
18
|
+
getInterfaceTypeByName,
|
|
17
19
|
} from './type.js'
|
|
18
20
|
export type { Type, ChanDir, Kind } from './type.js'
|
|
19
21
|
export { DeepEqual } from './deepequal.js'
|
|
@@ -33,19 +35,20 @@ export { Swapper } from './swapper.js'
|
|
|
33
35
|
// Export new types and constants
|
|
34
36
|
export {
|
|
35
37
|
StructTag,
|
|
38
|
+
StructTag_Get,
|
|
39
|
+
StructField,
|
|
36
40
|
ValueError,
|
|
37
|
-
SelectDir,
|
|
38
41
|
SelectSend,
|
|
39
42
|
SelectRecv,
|
|
40
43
|
SelectDefault,
|
|
44
|
+
SelectCase,
|
|
41
45
|
bitVector,
|
|
42
46
|
} from './types.js'
|
|
43
47
|
export type {
|
|
44
48
|
uintptr,
|
|
45
49
|
Pointer,
|
|
46
|
-
StructField,
|
|
47
50
|
Method,
|
|
48
|
-
|
|
51
|
+
SelectDir,
|
|
49
52
|
SliceHeader,
|
|
50
53
|
StringHeader,
|
|
51
54
|
MapIter,
|
package/gs/reflect/map.test.ts
CHANGED
|
@@ -11,20 +11,21 @@ describe('MapIter', () => {
|
|
|
11
11
|
const iter = new MapIter<string, number>(map)
|
|
12
12
|
|
|
13
13
|
expect(iter.current?.done === false).toBe(true)
|
|
14
|
-
|
|
15
|
-
expect(iter.
|
|
14
|
+
// Key() and Value() return reflect.Value objects now
|
|
15
|
+
expect(iter.Key().Interface()).toBe('one')
|
|
16
|
+
expect(iter.Value().Interface()).toBe(1)
|
|
16
17
|
|
|
17
18
|
expect(iter.Next()).toBe(true)
|
|
18
19
|
expect(iter.current?.done === false).toBe(true)
|
|
19
|
-
expect(
|
|
20
|
-
expect(
|
|
20
|
+
expect(iter.Key().Kind()).toBe(24) // String kind
|
|
21
|
+
expect(iter.Value().Kind()).toBe(2) // Int kind
|
|
21
22
|
|
|
22
23
|
const newMap = new Map<string, number>()
|
|
23
24
|
newMap.set('reset', 100)
|
|
24
25
|
iter.Reset(newMap)
|
|
25
26
|
|
|
26
27
|
expect(iter.current?.done === false).toBe(true)
|
|
27
|
-
expect(iter.Key()).toBe('reset')
|
|
28
|
-
expect(iter.Value()).toBe(100)
|
|
28
|
+
expect(iter.Key().Interface()).toBe('reset')
|
|
29
|
+
expect(iter.Value().Interface()).toBe(100)
|
|
29
30
|
})
|
|
30
31
|
})
|
package/gs/reflect/map.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Type, Kind, Value, Map as MapKind } from './type.js'
|
|
1
|
+
import { Type, Kind, Value, Map as MapKind, StructField, TypeOf } from './type.js'
|
|
2
2
|
|
|
3
3
|
// Simple MapOf implementation using JavaScript Map
|
|
4
4
|
export function MapOf(key: Type, elem: Type): Type {
|
|
@@ -20,26 +20,66 @@ class MapType implements Type {
|
|
|
20
20
|
return MapKind // Map kind
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
public Name(): string {
|
|
24
|
+
return '' // Map types are unnamed composite types
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
public Size(): number {
|
|
24
28
|
return 8 // pointer size
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
public Elem(): Type
|
|
31
|
+
public Elem(): Type {
|
|
28
32
|
return this._elemType
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
public Key(): Type
|
|
35
|
+
public Key(): Type {
|
|
32
36
|
return this._keyType
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
public NumField(): number {
|
|
36
40
|
return 0
|
|
37
41
|
}
|
|
42
|
+
|
|
43
|
+
public Field(_i: number): StructField {
|
|
44
|
+
throw new Error('reflect: Field of non-struct type map')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public Implements(u: Type | null): boolean {
|
|
48
|
+
if (!u) {
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
if (u.Kind() !== 20) {
|
|
52
|
+
// Interface kind
|
|
53
|
+
throw new Error('reflect: non-interface type passed to Type.Implements')
|
|
54
|
+
}
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public OverflowInt(_x: number): boolean {
|
|
59
|
+
throw new Error('reflect: OverflowInt of non-integer type map')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public OverflowUint(_x: number): boolean {
|
|
63
|
+
throw new Error('reflect: OverflowUint of non-integer type map')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public OverflowFloat(_x: number): boolean {
|
|
67
|
+
throw new Error('reflect: OverflowFloat of non-float type map')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public NumMethod(): number {
|
|
71
|
+
return 0
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public Bits(): number {
|
|
75
|
+
throw new Error('reflect: Bits of non-sized type map')
|
|
76
|
+
}
|
|
38
77
|
}
|
|
39
78
|
|
|
40
79
|
/**
|
|
41
80
|
* MapIter provides an iterator interface for Go maps.
|
|
42
81
|
* It wraps a JavaScript Map iterator and provides methods to iterate over key-value pairs.
|
|
82
|
+
* Returns reflect.Value for Key() and Value() to match Go's reflect.MapIter.
|
|
43
83
|
* @template K - The type of keys in the map
|
|
44
84
|
* @template V - The type of values in the map
|
|
45
85
|
*/
|
|
@@ -57,12 +97,14 @@ export class MapIter<K = unknown, V = unknown> {
|
|
|
57
97
|
return !this.current.done
|
|
58
98
|
}
|
|
59
99
|
|
|
60
|
-
public Key():
|
|
61
|
-
|
|
100
|
+
public Key(): Value {
|
|
101
|
+
const rawKey = this.current?.value?.[0] ?? null
|
|
102
|
+
return new Value(rawKey, TypeOf(rawKey))
|
|
62
103
|
}
|
|
63
104
|
|
|
64
|
-
public Value():
|
|
65
|
-
|
|
105
|
+
public Value(): Value {
|
|
106
|
+
const rawVal = this.current?.value?.[1] ?? null
|
|
107
|
+
return new Value(rawVal, TypeOf(rawVal))
|
|
66
108
|
}
|
|
67
109
|
|
|
68
110
|
public Reset(m: Map<K, V>): void {
|