goscript 0.1.4 → 0.2.1

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 (295) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +7 -0
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript-wasm/main.go +38 -6
  8. package/compiler/compile-request.go +12 -9
  9. package/compiler/compliance_test.go +0 -1
  10. package/compiler/config.go +2 -0
  11. package/compiler/diagnostic.go +104 -12
  12. package/compiler/diagnostic_test.go +106 -0
  13. package/compiler/gotest/request.go +28 -0
  14. package/compiler/gotest/runner.go +354 -44
  15. package/compiler/gotest/runner_test.go +293 -1
  16. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  17. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  18. package/compiler/index.test.ts +23 -0
  19. package/compiler/lowered-program.go +33 -24
  20. package/compiler/lowering.go +746 -194
  21. package/compiler/lowering_bench_test.go +42 -27
  22. package/compiler/lowering_internal_test.go +18 -0
  23. package/compiler/override-facts.go +15 -0
  24. package/compiler/override-parity-verifier.go +450 -0
  25. package/compiler/override-parity.go +122 -0
  26. package/compiler/override-registry_test.go +559 -0
  27. package/compiler/protobuf-ts-binding.go +567 -0
  28. package/compiler/protobuf-ts-binding_test.go +402 -0
  29. package/compiler/runtime-contract.go +4 -0
  30. package/compiler/runtime-contract_test.go +2 -0
  31. package/compiler/semantic-model-types.go +9 -4
  32. package/compiler/semantic-model.go +282 -70
  33. package/compiler/semantic-model_test.go +82 -1
  34. package/compiler/service.go +21 -1
  35. package/compiler/skeleton_test.go +118 -10
  36. package/compiler/typescript-emitter.go +128 -13
  37. package/compiler/wasm/compile_test.go +37 -4
  38. package/compiler/{wasm_api.go → wasm-api.go} +57 -7
  39. package/dist/gs/builtin/hostio.js +5 -0
  40. package/dist/gs/builtin/hostio.js.map +1 -1
  41. package/dist/gs/builtin/slice.d.ts +13 -2
  42. package/dist/gs/builtin/slice.js +187 -6
  43. package/dist/gs/builtin/slice.js.map +1 -1
  44. package/dist/gs/builtin/type.d.ts +13 -5
  45. package/dist/gs/builtin/type.js +153 -60
  46. package/dist/gs/builtin/type.js.map +1 -1
  47. package/dist/gs/builtin/varRef.d.ts +11 -0
  48. package/dist/gs/builtin/varRef.js +57 -2
  49. package/dist/gs/builtin/varRef.js.map +1 -1
  50. package/dist/gs/bytes/buffer.gs.js +1 -1
  51. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  52. package/dist/gs/bytes/reader.gs.js +1 -1
  53. package/dist/gs/bytes/reader.gs.js.map +1 -1
  54. package/dist/gs/compress/zlib/index.d.ts +10 -3
  55. package/dist/gs/compress/zlib/index.js +50 -16
  56. package/dist/gs/compress/zlib/index.js.map +1 -1
  57. package/dist/gs/encoding/json/index.d.ts +114 -0
  58. package/dist/gs/encoding/json/index.js +544 -36
  59. package/dist/gs/encoding/json/index.js.map +1 -1
  60. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +101 -0
  61. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +589 -0
  62. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  63. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +1 -0
  64. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +17 -11
  65. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  66. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  67. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  68. package/dist/gs/go/scanner/index.d.ts +2 -0
  69. package/dist/gs/go/scanner/index.js +29 -5
  70. package/dist/gs/go/scanner/index.js.map +1 -1
  71. package/dist/gs/go/token/index.js +22 -6
  72. package/dist/gs/go/token/index.js.map +1 -1
  73. package/dist/gs/hash/index.d.ts +6 -0
  74. package/dist/gs/hash/index.js +20 -0
  75. package/dist/gs/hash/index.js.map +1 -1
  76. package/dist/gs/internal/byteorder/index.js +2 -2
  77. package/dist/gs/internal/byteorder/index.js.map +1 -1
  78. package/dist/gs/internal/goarch/index.d.ts +43 -3
  79. package/dist/gs/internal/goarch/index.js +42 -10
  80. package/dist/gs/internal/goarch/index.js.map +1 -1
  81. package/dist/gs/io/fs/fs.js +26 -14
  82. package/dist/gs/io/fs/fs.js.map +1 -1
  83. package/dist/gs/io/fs/readdir.js +4 -2
  84. package/dist/gs/io/fs/readdir.js.map +1 -1
  85. package/dist/gs/io/fs/sub.js +8 -1
  86. package/dist/gs/io/fs/sub.js.map +1 -1
  87. package/dist/gs/io/io.d.ts +2 -0
  88. package/dist/gs/io/io.js.map +1 -1
  89. package/dist/gs/math/bits/index.d.ts +5 -0
  90. package/dist/gs/math/bits/index.js +16 -4
  91. package/dist/gs/math/bits/index.js.map +1 -1
  92. package/dist/gs/mime/index.d.ts +16 -0
  93. package/dist/gs/mime/index.js +315 -6
  94. package/dist/gs/mime/index.js.map +1 -1
  95. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  96. package/dist/gs/net/http/httptest/index.js +85 -6
  97. package/dist/gs/net/http/httptest/index.js.map +1 -1
  98. package/dist/gs/net/http/index.d.ts +300 -5
  99. package/dist/gs/net/http/index.js +1598 -58
  100. package/dist/gs/net/http/index.js.map +1 -1
  101. package/dist/gs/os/dir_unix.gs.js +1 -1
  102. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  103. package/dist/gs/os/error.gs.js +1 -1
  104. package/dist/gs/os/error.gs.js.map +1 -1
  105. package/dist/gs/os/exec.gs.d.ts +1 -0
  106. package/dist/gs/os/exec.gs.js +4 -8
  107. package/dist/gs/os/exec.gs.js.map +1 -1
  108. package/dist/gs/os/exec_posix.gs.js +1 -1
  109. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  110. package/dist/gs/os/index.d.ts +1 -1
  111. package/dist/gs/os/index.js +1 -1
  112. package/dist/gs/os/index.js.map +1 -1
  113. package/dist/gs/os/proc.gs.d.ts +4 -0
  114. package/dist/gs/os/proc.gs.js +12 -6
  115. package/dist/gs/os/proc.gs.js.map +1 -1
  116. package/dist/gs/os/root_js.gs.js +1 -1
  117. package/dist/gs/os/root_js.gs.js.map +1 -1
  118. package/dist/gs/os/types.gs.js +1 -1
  119. package/dist/gs/os/types.gs.js.map +1 -1
  120. package/dist/gs/os/types_js.gs.js +1 -1
  121. package/dist/gs/os/types_js.gs.js.map +1 -1
  122. package/dist/gs/os/types_unix.gs.js +1 -1
  123. package/dist/gs/os/types_unix.gs.js.map +1 -1
  124. package/dist/gs/path/path.js +11 -7
  125. package/dist/gs/path/path.js.map +1 -1
  126. package/dist/gs/reflect/index.d.ts +5 -4
  127. package/dist/gs/reflect/index.js +4 -3
  128. package/dist/gs/reflect/index.js.map +1 -1
  129. package/dist/gs/reflect/map.js +15 -0
  130. package/dist/gs/reflect/map.js.map +1 -1
  131. package/dist/gs/reflect/type.d.ts +25 -6
  132. package/dist/gs/reflect/type.js +1475 -228
  133. package/dist/gs/reflect/type.js.map +1 -1
  134. package/dist/gs/reflect/types.d.ts +14 -6
  135. package/dist/gs/reflect/types.js +35 -1
  136. package/dist/gs/reflect/types.js.map +1 -1
  137. package/dist/gs/reflect/value.d.ts +1 -0
  138. package/dist/gs/reflect/value.js +83 -41
  139. package/dist/gs/reflect/value.js.map +1 -1
  140. package/dist/gs/reflect/visiblefields.js +4 -140
  141. package/dist/gs/reflect/visiblefields.js.map +1 -1
  142. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  143. package/dist/gs/runtime/pprof/index.js +50 -30
  144. package/dist/gs/runtime/pprof/index.js.map +1 -1
  145. package/dist/gs/runtime/runtime.js +5 -4
  146. package/dist/gs/runtime/runtime.js.map +1 -1
  147. package/dist/gs/runtime/trace/index.js +5 -19
  148. package/dist/gs/runtime/trace/index.js.map +1 -1
  149. package/dist/gs/strconv/atoi.gs.js +1 -1
  150. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  151. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  152. package/dist/gs/strconv/complex.gs.js +148 -0
  153. package/dist/gs/strconv/complex.gs.js.map +1 -0
  154. package/dist/gs/strconv/index.d.ts +1 -0
  155. package/dist/gs/strconv/index.js +1 -0
  156. package/dist/gs/strconv/index.js.map +1 -1
  157. package/dist/gs/strings/builder.js +1 -1
  158. package/dist/gs/strings/reader.js +9 -5
  159. package/dist/gs/strings/reader.js.map +1 -1
  160. package/dist/gs/strings/replace.js +15 -7
  161. package/dist/gs/strings/replace.js.map +1 -1
  162. package/dist/gs/strings/strings.d.ts +5 -0
  163. package/dist/gs/strings/strings.js +57 -5
  164. package/dist/gs/strings/strings.js.map +1 -1
  165. package/dist/gs/sync/atomic/doc_64.gs.js +7 -6
  166. package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
  167. package/dist/gs/sync/atomic/type.gs.js +9 -9
  168. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  169. package/dist/gs/sync/atomic/value.gs.js +2 -2
  170. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  171. package/dist/gs/syscall/env.js +22 -14
  172. package/dist/gs/syscall/env.js.map +1 -1
  173. package/dist/gs/testing/testing.js +55 -13
  174. package/dist/gs/testing/testing.js.map +1 -1
  175. package/dist/gs/time/time.d.ts +24 -1
  176. package/dist/gs/time/time.js +43 -3
  177. package/dist/gs/time/time.js.map +1 -1
  178. package/dist/gs/unique/index.js +7 -1
  179. package/dist/gs/unique/index.js.map +1 -1
  180. package/go.mod +3 -3
  181. package/go.sum +16 -0
  182. package/gs/builtin/hostio.test.ts +16 -0
  183. package/gs/builtin/hostio.ts +7 -0
  184. package/gs/builtin/runtime-contract.test.ts +246 -21
  185. package/gs/builtin/slice.ts +269 -24
  186. package/gs/builtin/type.ts +226 -59
  187. package/gs/builtin/varRef.ts +85 -2
  188. package/gs/bytes/buffer.gs.ts +1 -1
  189. package/gs/bytes/reader.gs.ts +1 -1
  190. package/gs/compress/zlib/index.test.ts +62 -1
  191. package/gs/compress/zlib/index.ts +53 -16
  192. package/gs/compress/zlib/parity.json +51 -0
  193. package/gs/encoding/json/index.test.ts +360 -6
  194. package/gs/encoding/json/index.ts +679 -38
  195. package/gs/encoding/json/parity.json +81 -0
  196. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +373 -3
  197. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +893 -1
  198. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +18 -0
  199. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +17 -11
  200. package/gs/github.com/pkg/errors/errors.ts +54 -30
  201. package/gs/go/scanner/index.test.ts +39 -56
  202. package/gs/go/scanner/index.ts +33 -5
  203. package/gs/go/scanner/parity.json +27 -0
  204. package/gs/go/token/index.ts +22 -6
  205. package/gs/hash/index.test.ts +20 -33
  206. package/gs/hash/index.ts +28 -0
  207. package/gs/hash/parity.json +21 -0
  208. package/gs/internal/byteorder/index.test.ts +2 -2
  209. package/gs/internal/byteorder/index.ts +2 -2
  210. package/gs/internal/goarch/index.test.ts +32 -0
  211. package/gs/internal/goarch/index.ts +45 -13
  212. package/gs/internal/goarch/parity.json +144 -0
  213. package/gs/io/fs/fs.ts +26 -14
  214. package/gs/io/fs/readdir.ts +4 -4
  215. package/gs/io/fs/sub.ts +8 -1
  216. package/gs/io/io.ts +1 -0
  217. package/gs/io/parity.json +162 -0
  218. package/gs/math/bits/index.test.ts +14 -1
  219. package/gs/math/bits/index.ts +23 -4
  220. package/gs/math/bits/parity.json +156 -0
  221. package/gs/mime/index.test.ts +90 -0
  222. package/gs/mime/index.ts +369 -6
  223. package/gs/mime/parity.json +36 -0
  224. package/gs/net/http/httptest/index.test.ts +98 -2
  225. package/gs/net/http/httptest/index.ts +101 -6
  226. package/gs/net/http/httptest/parity.json +15 -0
  227. package/gs/net/http/index.test.ts +781 -12
  228. package/gs/net/http/index.ts +1860 -139
  229. package/gs/net/http/meta.json +16 -1
  230. package/gs/net/http/parity.json +193 -0
  231. package/gs/os/dir_unix.gs.ts +1 -1
  232. package/gs/os/error.gs.ts +1 -1
  233. package/gs/os/exec.gs.ts +4 -8
  234. package/gs/os/exec_posix.gs.ts +1 -1
  235. package/gs/os/index.test.ts +9 -0
  236. package/gs/os/index.ts +1 -0
  237. package/gs/os/parity.json +9 -0
  238. package/gs/os/proc.gs.ts +18 -5
  239. package/gs/os/proc.test.ts +26 -0
  240. package/gs/os/root_js.gs.ts +1 -1
  241. package/gs/os/types.gs.ts +1 -1
  242. package/gs/os/types_js.gs.ts +1 -1
  243. package/gs/os/types_unix.gs.ts +1 -1
  244. package/gs/path/path.ts +11 -7
  245. package/gs/reflect/field.test.ts +37 -15
  246. package/gs/reflect/function-types.test.ts +518 -22
  247. package/gs/reflect/index.ts +8 -6
  248. package/gs/reflect/map.ts +20 -0
  249. package/gs/reflect/meta.json +6 -4
  250. package/gs/reflect/parity.json +234 -0
  251. package/gs/reflect/sliceat.test.ts +156 -0
  252. package/gs/reflect/structof.test.ts +401 -0
  253. package/gs/reflect/type.ts +1961 -317
  254. package/gs/reflect/typefor.test.ts +530 -10
  255. package/gs/reflect/types.ts +43 -18
  256. package/gs/reflect/value.ts +105 -45
  257. package/gs/reflect/visiblefields.ts +5 -168
  258. package/gs/runtime/parity.json +24 -0
  259. package/gs/runtime/pprof/index.test.ts +29 -7
  260. package/gs/runtime/pprof/index.ts +56 -30
  261. package/gs/runtime/pprof/parity.json +27 -0
  262. package/gs/runtime/runtime.test.ts +3 -1
  263. package/gs/runtime/runtime.ts +4 -3
  264. package/gs/runtime/trace/index.test.ts +5 -3
  265. package/gs/runtime/trace/index.ts +8 -20
  266. package/gs/runtime/trace/parity.json +36 -0
  267. package/gs/strconv/atoi.gs.ts +1 -1
  268. package/gs/strconv/complex.gs.ts +174 -0
  269. package/gs/strconv/complex.test.ts +65 -0
  270. package/gs/strconv/index.ts +1 -0
  271. package/gs/strconv/parity.json +120 -0
  272. package/gs/strings/builder.ts +1 -1
  273. package/gs/strings/parity.json +186 -0
  274. package/gs/strings/reader.ts +9 -5
  275. package/gs/strings/replace.ts +15 -7
  276. package/gs/strings/strings.test.ts +22 -2
  277. package/gs/strings/strings.ts +64 -6
  278. package/gs/sync/atomic/doc_64.gs.ts +6 -7
  279. package/gs/sync/atomic/doc_64.test.ts +43 -0
  280. package/gs/sync/atomic/type.gs.ts +9 -9
  281. package/gs/sync/atomic/value.gs.ts +2 -2
  282. package/gs/syscall/env.ts +29 -14
  283. package/gs/testing/testing.test.ts +67 -0
  284. package/gs/testing/testing.ts +87 -19
  285. package/gs/time/parity.json +225 -0
  286. package/gs/time/time.test.ts +20 -2
  287. package/gs/time/time.ts +49 -7
  288. package/gs/unique/index.ts +7 -1
  289. package/package.json +4 -2
  290. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  291. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  292. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  293. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  294. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  295. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
@@ -1,8 +1,11 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import {
3
+ interfaceValue,
4
+ makeChannel,
3
5
  makeMap,
4
6
  mapGet,
5
7
  mapSet,
8
+ markAsStructValue,
6
9
  namedValueInterfaceValue,
7
10
  TypeKind,
8
11
  registerInterfaceType,
@@ -10,7 +13,19 @@ import {
10
13
  varRef,
11
14
  } from '../builtin/index.js'
12
15
  import { StructField } from './types.js'
13
- import { Int, Ptr, Struct, TypeFor, TypeOf, Uint64, ValueOf } from './type.js'
16
+ import { SelectCase, SelectRecv } from './types.js'
17
+ import {
18
+ Chan,
19
+ Int,
20
+ Ptr,
21
+ Struct,
22
+ StructOf,
23
+ TypeFor,
24
+ TypeOf,
25
+ Uint64,
26
+ ValueOf,
27
+ } from './type.js'
28
+ import { Indirect, New, Select, Zero } from './value.js'
14
29
 
15
30
  describe('TypeFor', () => {
16
31
  it('exposes StructField PkgPath and exported semantics', () => {
@@ -50,6 +65,101 @@ describe('TypeFor', () => {
50
65
  expect(namedIntType.Kind()).toBe(Int)
51
66
  })
52
67
 
68
+ it('preserves generic method signatures for named basic types', () => {
69
+ const stringResult = { kind: TypeKind.Basic, name: 'string' } as const
70
+ const namedIntDescriptor = {
71
+ kind: TypeKind.Basic,
72
+ name: 'int',
73
+ typeName: 'main.MyInt',
74
+ } as const
75
+ const methodSignatures = [
76
+ {
77
+ name: 'String',
78
+ args: [],
79
+ returns: [{ type: stringResult }],
80
+ },
81
+ ]
82
+ const preexisting = TypeFor({
83
+ T: {
84
+ type: namedIntDescriptor,
85
+ zero: () => 0,
86
+ },
87
+ })
88
+
89
+ const namedIntType = TypeFor({
90
+ T: {
91
+ type: namedIntDescriptor,
92
+ zero: () => 0,
93
+ methods: { String: (receiver: number) => String(receiver) },
94
+ methodSignatures,
95
+ },
96
+ })
97
+ const stringerType = TypeFor({
98
+ T: {
99
+ type: {
100
+ kind: TypeKind.Interface,
101
+ methods: methodSignatures,
102
+ },
103
+ zero: () => null,
104
+ },
105
+ })
106
+
107
+ expect(namedIntType).toBe(preexisting)
108
+ expect(namedIntType.NumMethod()).toBe(1)
109
+ const [method, ok] = namedIntType.MethodByName('String')
110
+ expect(ok).toBe(true)
111
+ expect(method.Type.NumIn()).toBe(1)
112
+ expect(method.Type.NumOut()).toBe(1)
113
+ expect(method.Type.Out(0).String()).toBe('string')
114
+ expect(namedIntType.Implements(stringerType)).toBe(true)
115
+ })
116
+
117
+ it('preserves generic method signatures for pointers to named basic types', () => {
118
+ const stringResult = { kind: TypeKind.Basic, name: 'string' } as const
119
+ const methodSignatures = [
120
+ {
121
+ name: 'String',
122
+ args: [],
123
+ returns: [{ type: stringResult }],
124
+ },
125
+ ]
126
+ const pointerType = TypeFor({
127
+ T: {
128
+ type: {
129
+ kind: TypeKind.Pointer,
130
+ elemType: {
131
+ kind: TypeKind.Basic,
132
+ name: 'bool',
133
+ typeName: 'main.MyBool',
134
+ },
135
+ },
136
+ zero: () => null,
137
+ methods: { String: () => 'true' },
138
+ methodSignatures,
139
+ },
140
+ })
141
+ const stringerType = TypeFor({
142
+ T: {
143
+ type: {
144
+ kind: TypeKind.Interface,
145
+ methods: methodSignatures,
146
+ },
147
+ zero: () => null,
148
+ },
149
+ })
150
+
151
+ expect(pointerType.Kind()).toBe(Ptr)
152
+ expect(pointerType.String()).toBe('*main.MyBool')
153
+ expect(pointerType.NumMethod()).toBe(1)
154
+ const [method, ok] = pointerType.MethodByName('String')
155
+ expect(ok).toBe(true)
156
+ expect(method.Type.NumIn()).toBe(1)
157
+ expect(method.Type.In(0)).toBe(pointerType)
158
+ expect(method.Type.NumOut()).toBe(1)
159
+ expect(method.Type.Out(0).String()).toBe('string')
160
+ expect(pointerType.Implements(stringerType)).toBe(true)
161
+ })
162
+
53
163
  it('preserves named pointer type metadata on interface boxes', () => {
54
164
  const target = varRef(0)
55
165
  const boxed = namedValueInterfaceValue(
@@ -78,6 +188,22 @@ describe('TypeFor', () => {
78
188
  expect(target.value).toBe(15)
79
189
  })
80
190
 
191
+ it('preserves channel type metadata on interface boxes', () => {
192
+ const ch = makeChannel<{}>(0, {}, 'both')
193
+ const chanValue = ValueOf(interfaceValue(ch, '<-chan struct{}'))
194
+
195
+ expect(chanValue.Type().Kind()).toBe(Chan)
196
+ expect(chanValue.Type().String()).toBe('<-chan struct {}')
197
+ expect(chanValue.Type().Elem().Kind()).toBe(Struct)
198
+
199
+ const [chosen, recv, ok] = Select([
200
+ new SelectCase({ Dir: SelectRecv, Chan: chanValue }),
201
+ ])
202
+ expect(chosen).toBe(0)
203
+ expect(ok).toBe(true)
204
+ expect(recv.Type().String()).toBe('struct {}')
205
+ })
206
+
81
207
  it('formats literal interface methods from type metadata', () => {
82
208
  const ifaceType = TypeFor({
83
209
  T: {
@@ -92,6 +218,130 @@ describe('TypeFor', () => {
92
218
  expect(ifaceType.String()).toBe('interface { SomeMethod() }')
93
219
  })
94
220
 
221
+ it('handles recursive interface method metadata', () => {
222
+ const recursiveMethod = {
223
+ name: 'Visit',
224
+ args: [{ name: 'next', type: 'main.RecursiveInterface' }],
225
+ returns: [{ name: '_r0', type: 'main.RecursiveInterface' }],
226
+ }
227
+ registerInterfaceType('main.RecursiveInterface', null, [recursiveMethod])
228
+
229
+ class RecursiveImpl {
230
+ public Visit(next: unknown): unknown {
231
+ return next
232
+ }
233
+ }
234
+
235
+ const typeInfo = registerStructType(
236
+ 'main.RecursiveImpl',
237
+ new RecursiveImpl(),
238
+ [recursiveMethod],
239
+ RecursiveImpl,
240
+ [],
241
+ )
242
+ ;(RecursiveImpl as any).__typeInfo = typeInfo
243
+
244
+ const ifaceType = TypeFor({
245
+ T: { type: 'main.RecursiveInterface', zero: () => null },
246
+ })
247
+
248
+ expect(ifaceType.String()).toBe(
249
+ 'interface { Visit(main.RecursiveInterface) main.RecursiveInterface }',
250
+ )
251
+ expect(ifaceType.AssignableTo(ifaceType)).toBe(true)
252
+ expect(TypeOf(new RecursiveImpl()).AssignableTo(ifaceType)).toBe(true)
253
+ })
254
+
255
+ it('handles recursive struct field metadata', () => {
256
+ class RecursiveNode {
257
+ public Next: RecursiveNode | null = null
258
+ }
259
+
260
+ const typeInfo = registerStructType(
261
+ 'main.RecursiveNode',
262
+ new RecursiveNode(),
263
+ [],
264
+ RecursiveNode,
265
+ [
266
+ {
267
+ name: 'Next',
268
+ key: 'Next',
269
+ type: {
270
+ kind: TypeKind.Pointer,
271
+ elemType: 'main.RecursiveNode',
272
+ },
273
+ },
274
+ ],
275
+ )
276
+ Object.assign(RecursiveNode, { __typeInfo: typeInfo })
277
+
278
+ const nodeType = TypeFor({
279
+ T: { type: 'main.RecursiveNode', zero: () => new RecursiveNode() },
280
+ })
281
+
282
+ expect(nodeType.Kind()).toBe(Struct)
283
+ expect(nodeType.Field(0).Name).toBe('Next')
284
+ expect(nodeType.Field(0).Type.String()).toBe('*main.RecursiveNode')
285
+ expect(nodeType.Field(0).Type.Elem().NumField()).toBe(1)
286
+ expect(nodeType.Field(0).Type.Elem().Field(0).Type.String()).toBe(
287
+ '*main.RecursiveNode',
288
+ )
289
+ expect(TypeOf(new RecursiveNode()).Field(0).Type.String()).toBe(
290
+ '*main.RecursiveNode',
291
+ )
292
+ expect(TypeOf(new RecursiveNode()).Field(0).Type.Elem().NumField()).toBe(1)
293
+ })
294
+
295
+ it('keeps mutually recursive registered struct identity canonical', () => {
296
+ class RecursiveA {
297
+ public B: RecursiveB | null = null
298
+ }
299
+ class RecursiveB {
300
+ public A: RecursiveA | null = null
301
+ }
302
+
303
+ const aInfo = registerStructType(
304
+ 'main.RecursiveA',
305
+ new RecursiveA(),
306
+ [],
307
+ RecursiveA,
308
+ [
309
+ {
310
+ name: 'B',
311
+ key: 'B',
312
+ type: { kind: TypeKind.Pointer, elemType: 'main.RecursiveB' },
313
+ },
314
+ ],
315
+ )
316
+ const bInfo = registerStructType(
317
+ 'main.RecursiveB',
318
+ new RecursiveB(),
319
+ [],
320
+ RecursiveB,
321
+ [
322
+ {
323
+ name: 'A',
324
+ key: 'A',
325
+ type: { kind: TypeKind.Pointer, elemType: 'main.RecursiveA' },
326
+ },
327
+ ],
328
+ )
329
+ Object.assign(RecursiveA, { __typeInfo: aInfo })
330
+ Object.assign(RecursiveB, { __typeInfo: bInfo })
331
+
332
+ const aType = TypeFor({
333
+ T: { type: 'main.RecursiveA', zero: () => new RecursiveA() },
334
+ })
335
+ const bType = TypeFor({
336
+ T: { type: 'main.RecursiveB', zero: () => new RecursiveB() },
337
+ })
338
+ const bFromA = aType.Field(0).Type.Elem()
339
+
340
+ expect(bFromA.NumField()).toBe(1)
341
+ expect(bFromA).toBe(bType)
342
+ expect(bType.Field(0).Type.Elem()).toBe(aType)
343
+ })
344
+
95
345
  it('formats unnamed function signatures from type metadata', () => {
96
346
  const fnType = TypeFor({
97
347
  T: {
@@ -105,6 +355,194 @@ describe('TypeFor', () => {
105
355
  })
106
356
 
107
357
  expect(fnType.String()).toBe('func(int) string')
358
+ expect(fnType.NumIn()).toBe(1)
359
+ expect(fnType.In(0).String()).toBe('int')
360
+ expect(fnType.NumOut()).toBe(1)
361
+ expect(fnType.Out(0).String()).toBe('string')
362
+ expect(fnType.IsVariadic()).toBe(false)
363
+ })
364
+
365
+ it('preserves named and variadic function descriptors', () => {
366
+ const namedFnType = TypeFor({
367
+ T: {
368
+ type: {
369
+ kind: TypeKind.Function,
370
+ name: 'example.test.Callback',
371
+ params: [{ kind: TypeKind.Basic, name: 'int' }],
372
+ results: [{ kind: TypeKind.Basic, name: 'string' }],
373
+ },
374
+ zero: () => null,
375
+ },
376
+ })
377
+
378
+ expect(namedFnType.String()).toBe('example.test.Callback')
379
+ expect(namedFnType.PkgPath()).toBe('example.test')
380
+ expect(namedFnType.Name()).toBe('Callback')
381
+ expect(namedFnType.NumIn()).toBe(1)
382
+ expect(namedFnType.In(0).String()).toBe('int')
383
+ expect(namedFnType.NumOut()).toBe(1)
384
+ expect(namedFnType.Out(0).String()).toBe('string')
385
+
386
+ const variadicFnType = TypeFor({
387
+ T: {
388
+ type: {
389
+ kind: TypeKind.Function,
390
+ params: [
391
+ {
392
+ kind: TypeKind.Slice,
393
+ elemType: { kind: TypeKind.Basic, name: 'string' },
394
+ },
395
+ ],
396
+ results: [{ kind: TypeKind.Basic, name: 'int' }],
397
+ isVariadic: true,
398
+ },
399
+ zero: () => null,
400
+ },
401
+ })
402
+
403
+ expect(variadicFnType.String()).toBe('func(...string) int')
404
+ expect(variadicFnType.NumIn()).toBe(1)
405
+ expect(variadicFnType.In(0).String()).toBe('[]string')
406
+ expect(variadicFnType.NumOut()).toBe(1)
407
+ expect(variadicFnType.Out(0).String()).toBe('int')
408
+ expect(variadicFnType.IsVariadic()).toBe(true)
409
+ })
410
+
411
+ it('rehydrates anonymous struct descriptors as unnamed struct types', () => {
412
+ const intType = TypeOf(0)
413
+ const descriptor = {
414
+ kind: TypeKind.Struct,
415
+ methods: [],
416
+ fields: [
417
+ {
418
+ name: 'X',
419
+ key: 'X',
420
+ type: { kind: TypeKind.Basic, name: 'int' },
421
+ tag: 'json:"x"',
422
+ index: [0],
423
+ offset: 0,
424
+ exported: true,
425
+ },
426
+ ],
427
+ } as const
428
+
429
+ const typ = TypeFor({
430
+ T: {
431
+ type: descriptor,
432
+ zero: () => ({ X: 0 }),
433
+ },
434
+ })
435
+ const dynamic = StructOf([
436
+ new StructField({
437
+ Name: 'X',
438
+ Type: intType,
439
+ Tag: 'json:"x"',
440
+ }),
441
+ ])
442
+
443
+ expect(typ.String()).toBe('struct { X int "json:\\"x\\"" }')
444
+ expect(typ.Name()).toBe('')
445
+ expect(typ.PkgPath()).toBe('')
446
+ expect(typ.NumField()).toBe(1)
447
+ expect(typ.Field(0).Name).toBe('X')
448
+ expect(typ.Field(0).Tag.Get('json')).toBe('x')
449
+ expect(typ.AssignableTo(dynamic)).toBe(true)
450
+ expect(dynamic.AssignableTo(typ)).toBe(true)
451
+ })
452
+
453
+ it('uses full anonymous struct identity in method signatures', () => {
454
+ const baseField = {
455
+ name: 'X',
456
+ key: 'X',
457
+ type: { kind: TypeKind.Basic, name: 'int' },
458
+ index: [0],
459
+ offset: 0,
460
+ exported: true,
461
+ } as const
462
+ const taggedParam = {
463
+ kind: TypeKind.Struct,
464
+ methods: [],
465
+ fields: [{ ...baseField, tag: 'json:"a"' }],
466
+ } as const
467
+ const methodSignatures = [
468
+ {
469
+ name: 'Accept',
470
+ args: [{ type: taggedParam }],
471
+ returns: [],
472
+ },
473
+ ]
474
+ const receiverType = TypeFor({
475
+ T: {
476
+ type: { kind: TypeKind.Basic, name: 'int', typeName: 'main.Receiver' },
477
+ zero: () => 0,
478
+ methodSignatures,
479
+ },
480
+ })
481
+ const sameInterface = TypeFor({
482
+ T: {
483
+ type: {
484
+ kind: TypeKind.Interface,
485
+ methods: methodSignatures,
486
+ },
487
+ zero: () => null,
488
+ },
489
+ })
490
+ const differentTagInterface = TypeFor({
491
+ T: {
492
+ type: {
493
+ kind: TypeKind.Interface,
494
+ methods: [
495
+ {
496
+ name: 'Accept',
497
+ args: [
498
+ {
499
+ type: {
500
+ kind: TypeKind.Struct,
501
+ methods: [],
502
+ fields: [{ ...baseField, tag: 'json:"b"' }],
503
+ },
504
+ },
505
+ ],
506
+ returns: [],
507
+ },
508
+ ],
509
+ },
510
+ zero: () => null,
511
+ },
512
+ })
513
+ const differentEmbeddingInterface = TypeFor({
514
+ T: {
515
+ type: {
516
+ kind: TypeKind.Interface,
517
+ methods: [
518
+ {
519
+ name: 'Accept',
520
+ args: [
521
+ {
522
+ type: {
523
+ kind: TypeKind.Struct,
524
+ methods: [],
525
+ fields: [
526
+ {
527
+ ...baseField,
528
+ tag: 'json:"a"',
529
+ anonymous: true,
530
+ },
531
+ ],
532
+ },
533
+ },
534
+ ],
535
+ returns: [],
536
+ },
537
+ ],
538
+ },
539
+ zero: () => null,
540
+ },
541
+ })
542
+
543
+ expect(receiverType.Implements(sameInterface)).toBe(true)
544
+ expect(receiverType.Implements(differentTagInterface)).toBe(false)
545
+ expect(receiverType.Implements(differentEmbeddingInterface)).toBe(false)
108
546
  })
109
547
 
110
548
  it('resolves registered type names from descriptors', () => {
@@ -115,25 +553,39 @@ describe('TypeFor', () => {
115
553
  new RegisteredStruct(),
116
554
  [],
117
555
  RegisteredStruct,
118
- {},
556
+ [],
119
557
  )
120
558
  registerStructType(
121
559
  'main.RegisteredWithFields',
122
560
  new RegisteredWithFields(),
123
561
  [],
124
562
  RegisteredWithFields,
125
- {
126
- Name: { kind: TypeKind.Basic, name: 'string' },
127
- Count: {
563
+ [
564
+ {
565
+ name: 'Name',
566
+ key: 'Name',
567
+ type: { kind: TypeKind.Basic, name: 'string' },
568
+ },
569
+ {
570
+ key: 'Count',
128
571
  name: 'Total',
129
572
  type: { kind: TypeKind.Basic, name: 'int' },
130
573
  tag: 'json:"total"',
574
+ pkgPath: 'main',
575
+ anonymous: true,
576
+ index: [3],
577
+ offset: 24,
578
+ exported: false,
131
579
  },
132
- Items: {
133
- kind: TypeKind.Slice,
134
- elemType: 'main.RegisteredStruct',
580
+ {
581
+ name: 'Items',
582
+ key: 'Items',
583
+ type: {
584
+ kind: TypeKind.Slice,
585
+ elemType: 'main.RegisteredStruct',
586
+ },
135
587
  },
136
- },
588
+ ],
137
589
  )
138
590
  registerInterfaceType('main.RegisteredInterface', null, [
139
591
  { name: 'SomeMethod', args: [], returns: [] },
@@ -160,9 +612,77 @@ describe('TypeFor', () => {
160
612
  expect(fieldsType.Field(0).Name).toBe('Name')
161
613
  expect(fieldsType.Field(0).Type.String()).toBe('string')
162
614
  expect(fieldsType.Field(1).Name).toBe('Total')
615
+ expect(fieldsType.Field(1).PkgPath).toBe('main')
616
+ expect(fieldsType.Field(1).IsExported()).toBe(false)
617
+ expect(fieldsType.Field(1).Anonymous).toBe(true)
618
+ expect(fieldsType.Field(1).Index).toEqual([3])
619
+ expect(fieldsType.Field(1).Offset).toBe(24)
163
620
  expect(fieldsType.Field(1).Tag.Get('json')).toBe('total')
164
621
  expect(fieldsType.Field(2).Type.String()).toBe('[]main.RegisteredStruct')
165
- expect(fieldsType.Field(2).Type.Elem().String()).toBe('main.RegisteredStruct')
622
+ expect(fieldsType.Field(2).Type.Elem().String()).toBe(
623
+ 'main.RegisteredStruct',
624
+ )
625
+ })
626
+
627
+ it('allocates registered struct zero values through the named constructor', () => {
628
+ class RegisteredZero {
629
+ public get Name(): string {
630
+ return this._fields.Name.value
631
+ }
632
+ public set Name(value: string) {
633
+ this._fields.Name.value = value
634
+ }
635
+
636
+ public _fields: {
637
+ Name: ReturnType<typeof varRef<string>>
638
+ }
639
+
640
+ constructor(init?: Partial<{ Name?: string }>) {
641
+ this._fields = {
642
+ Name: varRef(init?.Name ?? ''),
643
+ }
644
+ }
645
+
646
+ public clone(): RegisteredZero {
647
+ return markAsStructValue(new RegisteredZero({ Name: this.Name }))
648
+ }
649
+ }
650
+
651
+ const typeInfo = registerStructType(
652
+ 'main.RegisteredZero',
653
+ () => new RegisteredZero(),
654
+ [],
655
+ RegisteredZero,
656
+ [
657
+ {
658
+ name: 'Name',
659
+ key: 'Name',
660
+ type: { kind: TypeKind.Basic, name: 'string' },
661
+ index: [0],
662
+ offset: 0,
663
+ exported: true,
664
+ },
665
+ ],
666
+ )
667
+ ;(RegisteredZero as any).__typeInfo = typeInfo
668
+
669
+ const typ = TypeOf(new RegisteredZero())
670
+ expect(Zero(typ).Interface()).toBeInstanceOf(RegisteredZero)
671
+ expect(TypeOf(Zero(typ).Interface()).String()).toBe('main.RegisteredZero')
672
+
673
+ const ptr = New(typ)
674
+ expect(ptr.Elem().Interface()).toBeInstanceOf(RegisteredZero)
675
+ ptr.Elem().FieldByName('Name').SetString('Ada')
676
+ expect((ptr.Elem().Interface() as RegisteredZero).Name).toBe('Ada')
677
+ })
678
+
679
+ it('unwraps New pointers through Indirect', () => {
680
+ const pointer = New(TypeOf(0))
681
+ const value = Indirect(pointer)
682
+
683
+ expect(value.Int()).toBe(0)
684
+ value.SetInt(7)
685
+ expect(pointer.Elem().Int()).toBe(7)
166
686
  })
167
687
 
168
688
  it('interns runtime type descriptors for reflect.Type map keys', () => {
@@ -11,6 +11,8 @@ export interface UnsafePointer {
11
11
 
12
12
  export type Pointer = UnsafePointer | null
13
13
 
14
+ export type ReflectFunc = (...args: unknown[]) => unknown
15
+
14
16
  // Define the possible JavaScript values that can be reflected
15
17
  export type ReflectValue =
16
18
  | null
@@ -20,7 +22,7 @@ export type ReflectValue =
20
22
  | bigint
21
23
  | string
22
24
  | symbol
23
- | Function //eslint-disable-line @typescript-eslint/no-unsafe-function-type
25
+ | ReflectFunc
24
26
  | object
25
27
  | unknown[]
26
28
  | Map<unknown, unknown>
@@ -37,6 +39,10 @@ export type ReflectValue =
37
39
  // Import Type and Kind from the main type module
38
40
  import { Type, Kind, Value, Kind_String, ChanDir } from './type.js'
39
41
 
42
+ type StructFieldInit = Omit<Partial<StructField>, 'Tag'> & {
43
+ Tag?: StructTag | string
44
+ }
45
+
40
46
  // Struct field representation
41
47
  export class StructField {
42
48
  public Name: string = ''
@@ -47,9 +53,13 @@ export class StructField {
47
53
  public Index: number[] = []
48
54
  public Anonymous: boolean = false
49
55
 
50
- constructor(init?: Partial<StructField>) {
56
+ constructor(init?: StructFieldInit) {
51
57
  if (init) {
52
- Object.assign(this, init)
58
+ const { Tag, ...rest } = init
59
+ Object.assign(this, rest)
60
+ if (Tag !== undefined) {
61
+ this.Tag = typeof Tag === 'string' ? new StructTag(Tag) : Tag
62
+ }
53
63
  }
54
64
  }
55
65
 
@@ -102,12 +112,17 @@ export function StructTag_Get(tag: StructTag | undefined, key: string): string {
102
112
  return tag.Get(key)
103
113
  }
104
114
 
105
- // Method representation
106
- export interface Method {
107
- Name: string
108
- Type: Type
109
- Func: Function //eslint-disable-line @typescript-eslint/no-unsafe-function-type
110
- Index: number
115
+ export class Method {
116
+ public Name = ''
117
+ public Type!: Type
118
+ public Func!: ReflectFunc
119
+ public Index = 0
120
+
121
+ constructor(init?: Partial<Method>) {
122
+ if (init) {
123
+ Object.assign(this, init)
124
+ }
125
+ }
111
126
  }
112
127
 
113
128
  // Channel type for reflection
@@ -139,17 +154,27 @@ export const SelectSend: SelectDir = 1
139
154
  export const SelectRecv: SelectDir = 2
140
155
  export const SelectDefault: SelectDir = 3
141
156
 
142
- // Slice header (internal representation)
143
- export interface SliceHeader {
144
- Data: uintptr
145
- Len: number
146
- Cap: number
157
+ export class SliceHeader {
158
+ public Data: uintptr = 0
159
+ public Len = 0
160
+ public Cap = 0
161
+
162
+ constructor(init?: Partial<SliceHeader>) {
163
+ if (init) {
164
+ Object.assign(this, init)
165
+ }
166
+ }
147
167
  }
148
168
 
149
- // String header (internal representation)
150
- export interface StringHeader {
151
- Data: uintptr
152
- Len: number
169
+ export class StringHeader {
170
+ public Data: uintptr = 0
171
+ public Len = 0
172
+
173
+ constructor(init?: Partial<StringHeader>) {
174
+ if (init) {
175
+ Object.assign(this, init)
176
+ }
177
+ }
153
178
  }
154
179
 
155
180
  // Map iterator with proper typing