goscript 0.1.3 → 0.2.0

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 (330) 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} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -165,7 +165,7 @@ describe('strings/Reader', () => {
165
165
  expect(err).not.toBeNull()
166
166
  })
167
167
 
168
- it('should write to writer', () => {
168
+ it('should write to writer', async () => {
169
169
  const r = new Reader({ s: 'hello world' })
170
170
  r.ReadByte() // advance position
171
171
 
@@ -177,7 +177,7 @@ describe('strings/Reader', () => {
177
177
  },
178
178
  }
179
179
 
180
- const [n, err] = r.WriteTo(writer)
180
+ const [n, err] = await r.WriteTo(writer)
181
181
  expect(n).toBe(10) // remaining bytes
182
182
  expect(err).toBeNull()
183
183
  expect(r.Len()).toBe(0)
@@ -188,7 +188,7 @@ export class Reader {
188
188
  }
189
189
 
190
190
  // WriteTo implements the [io.WriterTo] interface.
191
- public WriteTo(w: io.Writer): [number, $.GoError] {
191
+ public async WriteTo(w: io.Writer): Promise<[number, $.GoError]> {
192
192
  const r = this
193
193
  r!.prevRune = -1
194
194
  if (r!.i >= ($.len(r!.s) as number)) {
@@ -197,7 +197,7 @@ export class Reader {
197
197
  let s = $.sliceString(r!.s, r!.i, undefined)
198
198
  let m: number
199
199
  let err: $.GoError
200
- ;[m, err] = io.WriteString(w, s)
200
+ ;[m, err] = await io.WriteString(w, s)
201
201
  if (m > $.len(s)) {
202
202
  $.panic('strings.Reader.WriteTo: invalid WriteString count')
203
203
  }
@@ -434,11 +434,15 @@ export class Reader {
434
434
  },
435
435
  ],
436
436
  Reader,
437
- {
438
- s: { kind: $.TypeKind.Basic, name: 'string' },
439
- i: { kind: $.TypeKind.Basic, name: 'number' },
440
- prevRune: { kind: $.TypeKind.Basic, name: 'number' },
441
- },
437
+ [
438
+ { name: 's', key: 's', type: { kind: $.TypeKind.Basic, name: 'string' } },
439
+ { name: 'i', key: 'i', type: { kind: $.TypeKind.Basic, name: 'number' } },
440
+ {
441
+ name: 'prevRune',
442
+ key: 'prevRune',
443
+ type: { kind: $.TypeKind.Basic, name: 'number' },
444
+ },
445
+ ],
442
446
  )
443
447
  }
444
448
 
@@ -205,14 +205,22 @@ export class Replacer {
205
205
  },
206
206
  ],
207
207
  Replacer,
208
- {
209
- built: { kind: $.TypeKind.Basic, name: 'boolean' },
210
- r: 'replacer',
211
- oldnew: {
212
- kind: $.TypeKind.Slice,
213
- elemType: { kind: $.TypeKind.Basic, name: 'string' },
208
+ [
209
+ {
210
+ name: 'built',
211
+ key: 'built',
212
+ type: { kind: $.TypeKind.Basic, name: 'boolean' },
214
213
  },
215
- },
214
+ { name: 'r', key: 'r', type: 'replacer' },
215
+ {
216
+ name: 'oldnew',
217
+ key: 'oldnew',
218
+ type: {
219
+ kind: $.TypeKind.Slice,
220
+ elemType: { kind: $.TypeKind.Basic, name: 'string' },
221
+ },
222
+ },
223
+ ],
216
224
  )
217
225
  }
218
226
 
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import * as $ from '../builtin/index.js'
3
+ import * as unicode from '../unicode/unicode.js'
3
4
  import {
4
5
  Clone,
5
6
  Compare,
@@ -36,8 +37,12 @@ import {
36
37
  SplitN,
37
38
  Title,
38
39
  ToLower,
40
+ ToLowerSpecial,
39
41
  ToTitle,
42
+ ToTitleSpecial,
40
43
  ToUpper,
44
+ ToUpperSpecial,
45
+ ToValidUTF8,
41
46
  Trim,
42
47
  TrimFunc,
43
48
  TrimLeft,
@@ -390,8 +395,8 @@ describe('strings', () => {
390
395
 
391
396
  describe('ToTitle', () => {
392
397
  it('should convert to title case', () => {
393
- expect(ToTitle('hello world')).toBe('Hello World')
394
- expect(ToTitle('HELLO WORLD')).toBe('Hello World')
398
+ expect(ToTitle('hello world')).toBe('HELLO WORLD')
399
+ expect(ToTitle('HELLO WORLD')).toBe('HELLO WORLD')
395
400
  expect(ToTitle('')).toBe('')
396
401
  })
397
402
  })
@@ -404,6 +409,21 @@ describe('strings', () => {
404
409
  })
405
410
  })
406
411
 
412
+ describe('special casing and UTF-8 cleanup', () => {
413
+ it('should expose special-case string helpers', () => {
414
+ expect(ToUpperSpecial([], 'hello')).toBe('HELLO')
415
+ expect(ToLowerSpecial([], 'HELLO')).toBe('hello')
416
+ expect(ToTitleSpecial([], 'hello world')).toBe('HELLO WORLD')
417
+ expect(ToUpperSpecial(unicode.TurkishCase, 'iki')).toBe('İKİ')
418
+ expect(ToLowerSpecial(unicode.TurkishCase, 'Iİ')).toBe('ıi')
419
+ expect(ToTitleSpecial(unicode.TurkishCase, 'iki')).toBe('İKİ')
420
+ })
421
+
422
+ it('should preserve valid replacement runes', () => {
423
+ expect(ToValidUTF8('a\uFFFDb', '?')).toBe('a\uFFFDb')
424
+ })
425
+ })
426
+
407
427
  describe('Trim', () => {
408
428
  it('should trim cutset from both ends', () => {
409
429
  expect(Trim('!hello!', '!')).toBe('hello')
@@ -1,4 +1,5 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
+ import * as unicode from '@goscript/unicode/index.js'
2
3
 
3
4
  // Count counts the number of non-overlapping instances of substr in s.
4
5
  // If substr is an empty string, Count returns 1 + the number of Unicode code points in s.
@@ -355,14 +356,76 @@ export function ToUpper(s: string): string {
355
356
  return s.toUpperCase()
356
357
  }
357
358
 
359
+ export function ToUpperSpecial(c: unicode.SpecialCase, s: string): string {
360
+ if (isTurkishCase(c)) {
361
+ return mapTurkishCase(s, 'upper')
362
+ }
363
+ return ToUpper(s)
364
+ }
365
+
358
366
  // ToLower returns s with all Unicode letters mapped to their lower case.
359
367
  export function ToLower(s: string): string {
360
368
  return s.toLowerCase()
361
369
  }
362
370
 
371
+ export function ToLowerSpecial(c: unicode.SpecialCase, s: string): string {
372
+ if (isTurkishCase(c)) {
373
+ return mapTurkishCase(s, 'lower')
374
+ }
375
+ return ToLower(s)
376
+ }
377
+
363
378
  // ToTitle returns a copy of the string s with all Unicode letters mapped to their Unicode title case.
364
379
  export function ToTitle(s: string): string {
365
- // JavaScript doesn't have a direct toTitleCase, so we'll use a simple approximation
380
+ return s.toUpperCase()
381
+ }
382
+
383
+ export function ToTitleSpecial(c: unicode.SpecialCase, s: string): string {
384
+ if (isTurkishCase(c)) {
385
+ return mapTurkishCase(s, 'upper')
386
+ }
387
+ return ToTitle(s)
388
+ }
389
+
390
+ function isTurkishCase(c: unicode.SpecialCase): boolean {
391
+ return c === unicode.TurkishCase || c === unicode.AzeriCase
392
+ }
393
+
394
+ function mapTurkishCase(s: string, mode: 'upper' | 'lower'): string {
395
+ let out = ''
396
+ for (const char of s) {
397
+ if (mode === 'upper') {
398
+ if (char === 'i') {
399
+ out += 'İ'
400
+ continue
401
+ }
402
+ if (char === 'ı') {
403
+ out += 'I'
404
+ continue
405
+ }
406
+ out += char.toUpperCase()
407
+ continue
408
+ }
409
+ if (char === 'I') {
410
+ out += 'ı'
411
+ continue
412
+ }
413
+ if (char === 'İ') {
414
+ out += 'i'
415
+ continue
416
+ }
417
+ out += char.toLowerCase()
418
+ }
419
+ return out
420
+ }
421
+
422
+ export function ToValidUTF8(s: string, replacement: string): string {
423
+ void replacement
424
+ return s
425
+ }
426
+
427
+ // Title returns a copy of the string s with all Unicode letters that begin words mapped to their Unicode title case.
428
+ export function Title(s: string): string {
366
429
  return s
367
430
  .split(' ')
368
431
  .map((word) =>
@@ -373,11 +436,6 @@ export function ToTitle(s: string): string {
373
436
  .join(' ')
374
437
  }
375
438
 
376
- // Title returns a copy of the string s with all Unicode letters that begin words mapped to their Unicode title case.
377
- export function Title(s: string): string {
378
- return ToTitle(s)
379
- }
380
-
381
439
  // TrimSpace returns a slice of the string s, with all leading and trailing white space removed.
382
440
  export function TrimSpace(s: string): string {
383
441
  return s.trim()
@@ -62,7 +62,7 @@ export class Bool {
62
62
  new Bool(),
63
63
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "boolean" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "boolean" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "boolean" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "boolean" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }],
64
64
  Bool,
65
- {"v": { kind: $.TypeKind.Basic, name: "number" }}
65
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "number" } }]
66
66
  );
67
67
  }
68
68
 
@@ -138,7 +138,7 @@ export class Pointer<T> {
138
138
  new Pointer(),
139
139
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }], returns: [{ type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }, { name: "new", type: { kind: $.TypeKind.Pointer, elemType: { kind: $.TypeKind.Interface, methods: [] } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }],
140
140
  Pointer,
141
- {"v": { kind: $.TypeKind.Basic, name: "Pointer" }}
141
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "Pointer" } }]
142
142
  );
143
143
  }
144
144
 
@@ -218,7 +218,7 @@ export class Int32 {
218
218
  new Int32(),
219
219
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Add", args: [{ name: "delta", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "And", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Or", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }],
220
220
  Int32,
221
- {"v": { kind: $.TypeKind.Basic, name: "number" }}
221
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "number" } }]
222
222
  );
223
223
  }
224
224
 
@@ -298,7 +298,7 @@ export class Int64 {
298
298
  new Int64(),
299
299
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Add", args: [{ name: "delta", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "And", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Or", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }],
300
300
  Int64,
301
- {"v": { kind: $.TypeKind.Basic, name: "number" }}
301
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "number" } }]
302
302
  );
303
303
  }
304
304
 
@@ -378,7 +378,7 @@ export class Uint32 {
378
378
  new Uint32(),
379
379
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Add", args: [{ name: "delta", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "And", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Or", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }],
380
380
  Uint32,
381
- {"v": { kind: $.TypeKind.Basic, name: "number" }}
381
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "number" } }]
382
382
  );
383
383
  }
384
384
 
@@ -458,7 +458,7 @@ export class Uint64 {
458
458
  new Uint64(),
459
459
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Add", args: [{ name: "delta", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "And", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Or", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }],
460
460
  Uint64,
461
- {"v": { kind: $.TypeKind.Basic, name: "number" }}
461
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "number" } }]
462
462
  );
463
463
  }
464
464
 
@@ -538,7 +538,7 @@ export class Uintptr {
538
538
  new Uintptr(),
539
539
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "uintptr" } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "uintptr" } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Basic, name: "uintptr" } }, { name: "new", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Add", args: [{ name: "delta", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "uintptr" } }] }, { name: "And", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "uintptr" } }] }, { name: "Or", args: [{ name: "mask", type: { kind: $.TypeKind.Basic, name: "uintptr" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "uintptr" } }] }],
540
540
  Uintptr,
541
- {"v": { kind: $.TypeKind.Basic, name: "uintptr" }}
541
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Basic, name: "uintptr" } }]
542
542
  );
543
543
  }
544
544
 
@@ -570,7 +570,7 @@ class noCopy {
570
570
  new noCopy(),
571
571
  [{ name: "Lock", args: [], returns: [] }, { name: "Unlock", args: [], returns: [] }],
572
572
  noCopy,
573
- {}
573
+ []
574
574
  );
575
575
  }
576
576
 
@@ -595,6 +595,6 @@ class align64 {
595
595
  new align64(),
596
596
  [],
597
597
  align64,
598
- {}
598
+ []
599
599
  );
600
600
  }
@@ -96,7 +96,7 @@ export class Value {
96
96
  new Value(),
97
97
  [{ name: "Load", args: [], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }] }, { name: "Store", args: [{ name: "val", type: { kind: $.TypeKind.Interface, methods: [] } }], returns: [] }, { name: "Swap", args: [{ name: "new", type: { kind: $.TypeKind.Interface, methods: [] } }], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }] }, { name: "CompareAndSwap", args: [{ name: "old", type: { kind: $.TypeKind.Interface, methods: [] } }, { name: "new", type: { kind: $.TypeKind.Interface, methods: [] } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }],
98
98
  Value,
99
- {"v": { kind: $.TypeKind.Interface, methods: [] }}
99
+ [{ name: "v", key: "v", type: { kind: $.TypeKind.Interface, methods: [] } }]
100
100
  );
101
101
  }
102
102
 
@@ -143,7 +143,7 @@ class efaceWords {
143
143
  new efaceWords(),
144
144
  [],
145
145
  efaceWords,
146
- {"data": { kind: $.TypeKind.Basic, name: "Pointer" }, "typ": { kind: $.TypeKind.Basic, name: "Pointer" }}
146
+ [{ name: "data", key: "data", type: { kind: $.TypeKind.Basic, name: "Pointer" } }, { name: "typ", key: "typ", type: { kind: $.TypeKind.Basic, name: "Pointer" } }]
147
147
  );
148
148
  }
149
149
 
package/gs/sync/meta.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "WaitGroup.Wait": true,
11
11
  "Once.Do": true,
12
12
  "Cond.Wait": true,
13
+ "Pool.Get": true,
13
14
  "Map.CompareAndDelete": true,
14
15
  "Map.Delete": true,
15
16
  "Map.Load": true,
@@ -1,6 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
- import { Cond, Map, Mutex, RWMutex, WaitGroup } from './sync.js'
3
+ import * as $ from '@goscript/builtin/index.js'
4
+
5
+ import { Cond, Map, Mutex, Pool, RWMutex, WaitGroup } from './sync.js'
4
6
 
5
7
  describe('sync.WaitGroup', () => {
6
8
  it('Go tracks scheduled work and unblocks Wait after completion', async () => {
@@ -89,4 +91,42 @@ describe('sync.Map', () => {
89
91
 
90
92
  expect(visited).toEqual(['a:1'])
91
93
  })
94
+
95
+ it('matches boxed comparable interface keys', async () => {
96
+ const m = new Map()
97
+ const first = $.namedValueInterfaceValue(8, 'uint16', {}, {
98
+ kind: $.TypeKind.Basic,
99
+ name: 'uint16',
100
+ })
101
+ const second = $.namedValueInterfaceValue(8, 'uint16', {}, {
102
+ kind: $.TypeKind.Basic,
103
+ name: 'uint16',
104
+ })
105
+
106
+ await m.Store(first, 'compressor')
107
+ expect(await m.Load(second)).toEqual(['compressor', true])
108
+ expect(await m.LoadOrStore(second, 'duplicate')).toEqual([
109
+ 'compressor',
110
+ true,
111
+ ])
112
+ expect(await m.CompareAndSwap(second, 'compressor', 'updated')).toBe(true)
113
+ expect(await m.Load(first)).toEqual(['updated', true])
114
+ expect(await m.CompareAndDelete(first, 'updated')).toBe(true)
115
+ expect(await m.Load(second)).toEqual([undefined, false])
116
+ })
117
+ })
118
+
119
+ describe('sync.Pool', () => {
120
+ it('awaits async New functions before returning a pooled value', async () => {
121
+ const pool = new Pool({
122
+ New: async () => {
123
+ await Promise.resolve()
124
+ return 'created'
125
+ },
126
+ })
127
+
128
+ expect(await pool.Get()).toBe('created')
129
+ pool.Put('reused')
130
+ expect(await pool.Get()).toBe('reused')
131
+ })
92
132
  })
package/gs/sync/sync.ts CHANGED
@@ -3,6 +3,8 @@
3
3
  // low-level library routines. Higher-level synchronization is better done via
4
4
  // channels and communication.
5
5
 
6
+ import { comparableEqual } from '@goscript/builtin/index.js'
7
+
6
8
  // Locker represents an object that can be locked and unlocked
7
9
  export interface Locker {
8
10
  Lock(): Promise<void>
@@ -334,7 +336,10 @@ export class Map {
334
336
  public async Delete(key: any): Promise<void> {
335
337
  await this._m.Lock()
336
338
  try {
337
- this._data.delete(key)
339
+ const entry = this.findEntry(key)
340
+ if (entry.found) {
341
+ this._data.delete(entry.key)
342
+ }
338
343
  } finally {
339
344
  this._m.Unlock()
340
345
  }
@@ -344,10 +349,11 @@ export class Map {
344
349
  public async CompareAndDelete(key: any, old: any): Promise<boolean> {
345
350
  await this._m.Lock()
346
351
  try {
347
- if (!this._data.has(key) || this._data.get(key) !== old) {
352
+ const entry = this.findEntry(key)
353
+ if (!entry.found || !comparableEqual(entry.value, old)) {
348
354
  return false
349
355
  }
350
- this._data.delete(key)
356
+ this._data.delete(entry.key)
351
357
  return true
352
358
  } finally {
353
359
  this._m.Unlock()
@@ -356,10 +362,11 @@ export class Map {
356
362
 
357
363
  // CompareAndSwap swaps the old and new values for key if the stored value is old.
358
364
  public CompareAndSwap(key: any, old: any, value: any): boolean {
359
- if (!this._data.has(key) || this._data.get(key) !== old) {
365
+ const entry = this.findEntry(key)
366
+ if (!entry.found || !comparableEqual(entry.value, old)) {
360
367
  return false
361
368
  }
362
- this._data.set(key, value)
369
+ this._data.set(entry.key, value)
363
370
  return true
364
371
  }
365
372
 
@@ -367,8 +374,8 @@ export class Map {
367
374
  public async Load(key: any): Promise<[any, boolean]> {
368
375
  await this._m.RLock()
369
376
  try {
370
- const value = this._data.get(key)
371
- return [value, this._data.has(key)]
377
+ const entry = this.findEntry(key)
378
+ return entry.found ? [entry.value, true] : [undefined, false]
372
379
  } finally {
373
380
  this._m.RUnlock()
374
381
  }
@@ -378,10 +385,12 @@ export class Map {
378
385
  public async LoadAndDelete(key: any): Promise<[any, boolean]> {
379
386
  await this._m.Lock()
380
387
  try {
381
- const value = this._data.get(key)
382
- const loaded = this._data.has(key)
383
- this._data.delete(key)
384
- return [value, loaded]
388
+ const entry = this.findEntry(key)
389
+ if (!entry.found) {
390
+ return [undefined, false]
391
+ }
392
+ this._data.delete(entry.key)
393
+ return [entry.value, true]
385
394
  } finally {
386
395
  this._m.Unlock()
387
396
  }
@@ -391,8 +400,9 @@ export class Map {
391
400
  public async LoadOrStore(key: any, value: any): Promise<[any, boolean]> {
392
401
  await this._m.Lock()
393
402
  try {
394
- if (this._data.has(key)) {
395
- return [this._data.get(key), true]
403
+ const entry = this.findEntry(key)
404
+ if (entry.found) {
405
+ return [entry.value, true]
396
406
  }
397
407
  this._data.set(key, value)
398
408
  return [value, false]
@@ -423,12 +433,27 @@ export class Map {
423
433
  public async Store(key: any, value: any): Promise<void> {
424
434
  await this._m.Lock()
425
435
  try {
426
- this._data.set(key, value)
436
+ const entry = this.findEntry(key)
437
+ this._data.set(entry.found ? entry.key : key, value)
427
438
  } finally {
428
439
  this._m.Unlock()
429
440
  }
430
441
  }
431
442
 
443
+ private findEntry(
444
+ key: any,
445
+ ): { found: false } | { found: true; key: any; value: any } {
446
+ if (this._data.has(key)) {
447
+ return { found: true, key, value: this._data.get(key) }
448
+ }
449
+ for (const [candidate, value] of this._data.entries()) {
450
+ if (candidate !== key && comparableEqual(candidate, key)) {
451
+ return { found: true, key: candidate, value }
452
+ }
453
+ }
454
+ return { found: false }
455
+ }
456
+
432
457
  // Swap swaps the value for a key and returns the previous value if any
433
458
  public async Swap(key: any, value: any): Promise<[any, boolean]> {
434
459
  await this._m.Lock()
@@ -458,12 +483,12 @@ export class Pool {
458
483
  }
459
484
 
460
485
  // Get selects an arbitrary item from the Pool, removes it from the Pool, and returns it to the caller
461
- public Get(): any {
486
+ public async Get(): Promise<any> {
462
487
  if (this._pool.length > 0) {
463
488
  return this._pool.pop()
464
489
  }
465
490
  if (this.New) {
466
- return this.New()
491
+ return await this.New()
467
492
  }
468
493
  return null
469
494
  }
package/gs/syscall/env.ts CHANGED
@@ -1,47 +1,62 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
2
 
3
+ type ProcessEnv = Record<string, string | undefined>
4
+
5
+ interface ProcessLike {
6
+ env?: ProcessEnv
7
+ }
8
+
9
+ function hostEnv(): ProcessEnv | undefined {
10
+ return (globalThis as { process?: ProcessLike }).process?.env
11
+ }
12
+
3
13
  // Environment variable functions using Node.js/browser APIs
4
14
  export function Getenv(key: string): [string, boolean] {
5
- if (typeof process !== 'undefined' && process.env) {
6
- const value = process.env[key]
15
+ const env = hostEnv()
16
+ if (env !== undefined) {
17
+ const value = env[key]
7
18
  return value !== undefined ? [value, true] : ['', false]
8
19
  }
9
20
  return ['', false]
10
21
  }
11
22
 
12
23
  export function Setenv(key: string, value: string): $.GoError {
13
- if (typeof process !== 'undefined' && process.env) {
14
- process.env[key] = value
24
+ const env = hostEnv()
25
+ if (env !== undefined) {
26
+ env[key] = value
15
27
  return null
16
28
  }
17
29
  return { Error: () => 'setenv not supported' }
18
30
  }
19
31
 
20
32
  export function Unsetenv(key: string): $.GoError {
21
- if (typeof process !== 'undefined' && process.env) {
22
- delete process.env[key]
33
+ const env = hostEnv()
34
+ if (env !== undefined) {
35
+ delete env[key]
23
36
  return null
24
37
  }
25
38
  return { Error: () => 'unsetenv not supported' }
26
39
  }
27
40
 
28
41
  export function Clearenv(): void {
29
- if (typeof process !== 'undefined' && process.env) {
30
- for (const key in process.env) {
31
- delete process.env[key]
42
+ const env = hostEnv()
43
+ if (env !== undefined) {
44
+ for (const key in env) {
45
+ delete env[key]
32
46
  }
33
47
  }
34
48
  }
35
49
 
36
50
  export function Environ(): $.Slice<string> {
37
- if (typeof process !== 'undefined' && process.env) {
38
- const env: string[] = []
39
- for (const [key, value] of Object.entries(process.env)) {
51
+ const host = hostEnv()
52
+ if (host !== undefined) {
53
+ const values: string[] = []
54
+ for (const [key, value] of Object.entries(host)) {
40
55
  if (value !== undefined) {
41
- env.push(`${key}=${value}`)
56
+ values.push(`${key}=${value}`)
42
57
  }
43
58
  }
44
- return $.arrayToSlice(env)
59
+ return $.arrayToSlice(values)
45
60
  }
46
61
  return $.arrayToSlice([])
47
62
  }
@@ -0,0 +1,18 @@
1
+ import { describe, expect, test } from 'vitest'
2
+
3
+ import * as $ from '@goscript/builtin/index.js'
4
+
5
+ import { ValueOf } from './index.js'
6
+
7
+ describe('syscall/js override', () => {
8
+ test('ValueOf unwraps generated interface numeric boxes', () => {
9
+ const value = ValueOf(
10
+ $.namedValueInterfaceValue(41, 'int', {}, {
11
+ kind: $.TypeKind.Basic,
12
+ name: 'int',
13
+ }),
14
+ )
15
+
16
+ expect(value.Int()).toBe(41)
17
+ })
18
+ })
@@ -365,6 +365,9 @@ export function ValueOf(x: unknown): Value {
365
365
  if (x instanceof Func) {
366
366
  return x.Value.clone()
367
367
  }
368
+ if (isGoInterfaceValue(x)) {
369
+ return ValueOf(x.__goValue)
370
+ }
368
371
  if (x === null || x === undefined) {
369
372
  return Null()
370
373
  }
@@ -394,6 +397,15 @@ export function ValueOf(x: unknown): Value {
394
397
  return new Value({ raw: x })
395
398
  }
396
399
 
400
+ function isGoInterfaceValue(value: unknown): value is { __goValue: unknown } {
401
+ return (
402
+ value !== null &&
403
+ typeof value === 'object' &&
404
+ '__goValue' in value &&
405
+ typeof (value as { __goType?: unknown }).__goType === 'string'
406
+ )
407
+ }
408
+
397
409
  export function FuncOf(
398
410
  fn: (this$: Value, args: $.Slice<Value>) => unknown,
399
411
  ): Func {