goscript 0.2.5 → 0.2.7

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 (264) hide show
  1. package/cmd/goscript/cmd-compile.go +7 -0
  2. package/cmd/goscript/cmd_compile_test.go +83 -0
  3. package/compiler/compile-request.go +3 -0
  4. package/compiler/compiler-cache.go +828 -0
  5. package/compiler/compiler-cache_test.go +705 -0
  6. package/compiler/config.go +2 -0
  7. package/compiler/index.test.ts +26 -1
  8. package/compiler/index.ts +5 -0
  9. package/compiler/lowered-program.go +31 -20
  10. package/compiler/lowering.go +349 -93
  11. package/compiler/lowering_bench_test.go +1 -0
  12. package/compiler/override-facts.go +309 -8
  13. package/compiler/override-parity-verifier.go +45 -1
  14. package/compiler/override-parity-verifier_test.go +100 -0
  15. package/compiler/override-registry_test.go +1 -0
  16. package/compiler/package-graph.go +40 -12
  17. package/compiler/package-graph_test.go +29 -0
  18. package/compiler/runtime-contract.go +8 -0
  19. package/compiler/service.go +98 -11
  20. package/compiler/skeleton_test.go +110 -14
  21. package/compiler/typescript-emitter.go +120 -23
  22. package/dist/compiler/index.d.ts +2 -0
  23. package/dist/compiler/index.js +3 -0
  24. package/dist/compiler/index.js.map +1 -1
  25. package/dist/gs/builtin/builtin.d.ts +24 -33
  26. package/dist/gs/builtin/builtin.js +54 -61
  27. package/dist/gs/builtin/builtin.js.map +1 -1
  28. package/dist/gs/builtin/hostio.d.ts +1 -0
  29. package/dist/gs/builtin/hostio.js +1 -1
  30. package/dist/gs/builtin/hostio.js.map +1 -1
  31. package/dist/gs/builtin/index.d.ts +1 -0
  32. package/dist/gs/builtin/index.js +1 -0
  33. package/dist/gs/builtin/index.js.map +1 -1
  34. package/dist/gs/builtin/panic.d.ts +18 -0
  35. package/dist/gs/builtin/panic.js +98 -0
  36. package/dist/gs/builtin/panic.js.map +1 -0
  37. package/dist/gs/builtin/slice.d.ts +10 -0
  38. package/dist/gs/builtin/slice.js +110 -53
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.js +15 -3
  41. package/dist/gs/builtin/type.js.map +1 -1
  42. package/dist/gs/builtin/varRef.d.ts +1 -1
  43. package/dist/gs/builtin/varRef.js +3 -2
  44. package/dist/gs/builtin/varRef.js.map +1 -1
  45. package/dist/gs/bytes/bytes.gs.js +51 -38
  46. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  47. package/dist/gs/bytes/reader.gs.d.ts +1 -1
  48. package/dist/gs/bytes/reader.gs.js +6 -7
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/cmp/index.d.ts +1 -1
  51. package/dist/gs/cmp/index.js +43 -10
  52. package/dist/gs/cmp/index.js.map +1 -1
  53. package/dist/gs/context/context.d.ts +2 -2
  54. package/dist/gs/context/context.js +1 -1
  55. package/dist/gs/context/context.js.map +1 -1
  56. package/dist/gs/embed/index.js +1 -1
  57. package/dist/gs/embed/index.js.map +1 -1
  58. package/dist/gs/encoding/binary/index.js +201 -8
  59. package/dist/gs/encoding/binary/index.js.map +1 -1
  60. package/dist/gs/encoding/json/index.d.ts +5 -0
  61. package/dist/gs/encoding/json/index.js +388 -25
  62. package/dist/gs/encoding/json/index.js.map +1 -1
  63. package/dist/gs/errors/errors.js +17 -24
  64. package/dist/gs/errors/errors.js.map +1 -1
  65. package/dist/gs/fmt/fmt.js +129 -35
  66. package/dist/gs/fmt/fmt.js.map +1 -1
  67. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1 -1
  68. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -1
  69. package/dist/gs/internal/bytealg/index.js +43 -8
  70. package/dist/gs/internal/bytealg/index.js.map +1 -1
  71. package/dist/gs/internal/byteorder/index.d.ts +2 -2
  72. package/dist/gs/internal/byteorder/index.js +2 -2
  73. package/dist/gs/internal/byteorder/index.js.map +1 -1
  74. package/dist/gs/io/fs/format.js +2 -2
  75. package/dist/gs/io/fs/format.js.map +1 -1
  76. package/dist/gs/io/fs/fs.d.ts +1 -1
  77. package/dist/gs/io/fs/fs.js +1 -1
  78. package/dist/gs/io/fs/fs.js.map +1 -1
  79. package/dist/gs/io/io.d.ts +21 -21
  80. package/dist/gs/io/io.js +49 -50
  81. package/dist/gs/io/io.js.map +1 -1
  82. package/dist/gs/math/bits/index.js +26 -8
  83. package/dist/gs/math/bits/index.js.map +1 -1
  84. package/dist/gs/math/copysign.gs.js +10 -17
  85. package/dist/gs/math/copysign.gs.js.map +1 -1
  86. package/dist/gs/math/pow.gs.js +5 -0
  87. package/dist/gs/math/pow.gs.js.map +1 -1
  88. package/dist/gs/math/signbit.gs.js +6 -2
  89. package/dist/gs/math/signbit.gs.js.map +1 -1
  90. package/dist/gs/mime/index.js +1 -0
  91. package/dist/gs/mime/index.js.map +1 -1
  92. package/dist/gs/net/http/index.d.ts +6 -6
  93. package/dist/gs/net/http/index.js +507 -43
  94. package/dist/gs/net/http/index.js.map +1 -1
  95. package/dist/gs/os/stat.gs.d.ts +2 -2
  96. package/dist/gs/os/types.gs.d.ts +1 -1
  97. package/dist/gs/os/types.gs.js +1 -1
  98. package/dist/gs/os/types.gs.js.map +1 -1
  99. package/dist/gs/os/types_js.gs.d.ts +1 -1
  100. package/dist/gs/os/types_js.gs.js +7 -7
  101. package/dist/gs/os/types_js.gs.js.map +1 -1
  102. package/dist/gs/os/types_unix.gs.d.ts +1 -1
  103. package/dist/gs/os/types_unix.gs.js +1 -1
  104. package/dist/gs/os/types_unix.gs.js.map +1 -1
  105. package/dist/gs/os/zero_copy_posix.gs.d.ts +1 -1
  106. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  107. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  108. package/dist/gs/path/filepath/match.js +8 -4
  109. package/dist/gs/path/filepath/match.js.map +1 -1
  110. package/dist/gs/path/filepath/path.js +216 -42
  111. package/dist/gs/path/filepath/path.js.map +1 -1
  112. package/dist/gs/path/match.js +6 -3
  113. package/dist/gs/path/match.js.map +1 -1
  114. package/dist/gs/reflect/type.d.ts +5 -4
  115. package/dist/gs/reflect/type.js +29 -11
  116. package/dist/gs/reflect/type.js.map +1 -1
  117. package/dist/gs/slices/slices.js +11 -11
  118. package/dist/gs/slices/slices.js.map +1 -1
  119. package/dist/gs/strconv/atof.gs.js +156 -43
  120. package/dist/gs/strconv/atof.gs.js.map +1 -1
  121. package/dist/gs/strconv/atoi.gs.d.ts +3 -2
  122. package/dist/gs/strconv/atoi.gs.js +86 -67
  123. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  124. package/dist/gs/strconv/ftoa.gs.js +73 -3
  125. package/dist/gs/strconv/ftoa.gs.js.map +1 -1
  126. package/dist/gs/strconv/itoa.gs.d.ts +4 -4
  127. package/dist/gs/strconv/itoa.gs.js +5 -4
  128. package/dist/gs/strconv/itoa.gs.js.map +1 -1
  129. package/dist/gs/strconv/quote.gs.d.ts +1 -1
  130. package/dist/gs/strconv/quote.gs.js +311 -103
  131. package/dist/gs/strconv/quote.gs.js.map +1 -1
  132. package/dist/gs/strings/reader.d.ts +1 -1
  133. package/dist/gs/strings/reader.js +8 -8
  134. package/dist/gs/strings/reader.js.map +1 -1
  135. package/dist/gs/strings/strings.js +87 -61
  136. package/dist/gs/strings/strings.js.map +1 -1
  137. package/dist/gs/sync/atomic/doc_64.gs.d.ts +14 -14
  138. package/dist/gs/sync/atomic/doc_64.gs.js +10 -10
  139. package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
  140. package/dist/gs/sync/atomic/type.gs.d.ts +22 -22
  141. package/dist/gs/sync/atomic/type.gs.js +4 -4
  142. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  143. package/dist/gs/sync/sync.js +50 -12
  144. package/dist/gs/sync/sync.js.map +1 -1
  145. package/dist/gs/syscall/fs.d.ts +6 -6
  146. package/dist/gs/syscall/fs.js +1 -1
  147. package/dist/gs/syscall/fs.js.map +1 -1
  148. package/dist/gs/time/time.d.ts +18 -18
  149. package/dist/gs/time/time.js +58 -55
  150. package/dist/gs/time/time.js.map +1 -1
  151. package/dist/gs/unicode/tables.d.ts +11 -0
  152. package/dist/gs/unicode/tables.js +635 -0
  153. package/dist/gs/unicode/tables.js.map +1 -0
  154. package/dist/gs/unicode/unicode.d.ts +58 -38
  155. package/dist/gs/unicode/unicode.js +362 -278
  156. package/dist/gs/unicode/unicode.js.map +1 -1
  157. package/go.sum +13 -0
  158. package/gs/builtin/builtin.ts +83 -93
  159. package/gs/builtin/hostio.ts +1 -1
  160. package/gs/builtin/index.ts +1 -0
  161. package/gs/builtin/panic.test.ts +189 -0
  162. package/gs/builtin/panic.ts +107 -0
  163. package/gs/builtin/runtime-contract.test.ts +5 -5
  164. package/gs/builtin/slice.test.ts +23 -0
  165. package/gs/builtin/slice.ts +133 -95
  166. package/gs/builtin/type.ts +16 -3
  167. package/gs/builtin/varRef.ts +4 -2
  168. package/gs/builtin/wide-int.test.ts +41 -0
  169. package/gs/bytes/bytes.gs.ts +54 -41
  170. package/gs/bytes/bytes.test.ts +18 -1
  171. package/gs/bytes/reader.gs.ts +7 -8
  172. package/gs/cmp/index.test.ts +55 -0
  173. package/gs/cmp/index.ts +45 -9
  174. package/gs/context/context.ts +3 -3
  175. package/gs/embed/index.ts +2 -2
  176. package/gs/encoding/binary/index.test.ts +104 -0
  177. package/gs/encoding/binary/index.ts +259 -11
  178. package/gs/encoding/json/index.test.ts +107 -0
  179. package/gs/encoding/json/index.ts +400 -29
  180. package/gs/errors/errors.test.ts +44 -1
  181. package/gs/errors/errors.ts +15 -31
  182. package/gs/fmt/fmt.test.ts +70 -2
  183. package/gs/fmt/fmt.ts +128 -34
  184. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1 -1
  185. package/gs/internal/bytealg/index.test.ts +26 -1
  186. package/gs/internal/bytealg/index.ts +44 -8
  187. package/gs/internal/byteorder/index.ts +6 -4
  188. package/gs/io/fs/format.ts +2 -2
  189. package/gs/io/fs/fs.ts +2 -2
  190. package/gs/io/fs/stat.test.ts +2 -2
  191. package/gs/io/fs/sub.test.ts +2 -2
  192. package/gs/io/fs/walk.test.ts +2 -2
  193. package/gs/io/io.test.ts +47 -5
  194. package/gs/io/io.ts +73 -73
  195. package/gs/io/limit.test.ts +103 -0
  196. package/gs/math/bits/index.test.ts +128 -0
  197. package/gs/math/bits/index.ts +26 -8
  198. package/gs/math/copysign.gs.test.ts +3 -1
  199. package/gs/math/copysign.gs.ts +10 -22
  200. package/gs/math/pow.gs.test.ts +4 -5
  201. package/gs/math/pow.gs.ts +5 -0
  202. package/gs/math/signbit.gs.test.ts +2 -1
  203. package/gs/math/signbit.gs.ts +6 -3
  204. package/gs/mime/index.ts +1 -0
  205. package/gs/net/http/index.test.ts +683 -2
  206. package/gs/net/http/index.ts +598 -57
  207. package/gs/net/http/meta.json +3 -0
  208. package/gs/os/stat.gs.ts +2 -2
  209. package/gs/os/types.gs.ts +2 -2
  210. package/gs/os/types_js.gs.ts +9 -9
  211. package/gs/os/types_unix.gs.ts +2 -2
  212. package/gs/os/zero_copy_posix.gs.ts +2 -2
  213. package/gs/path/filepath/match.test.ts +16 -0
  214. package/gs/path/filepath/match.ts +8 -4
  215. package/gs/path/filepath/path.test.ts +91 -9
  216. package/gs/path/filepath/path.ts +223 -49
  217. package/gs/path/match.test.ts +32 -0
  218. package/gs/path/match.ts +6 -3
  219. package/gs/reflect/deepequal.test.ts +1 -1
  220. package/gs/reflect/field.test.ts +1 -1
  221. package/gs/reflect/function-types.test.ts +6 -6
  222. package/gs/reflect/sliceat.test.ts +13 -13
  223. package/gs/reflect/structof.test.ts +4 -4
  224. package/gs/reflect/type.ts +34 -14
  225. package/gs/reflect/typefor.test.ts +5 -5
  226. package/gs/runtime/pprof/index.test.ts +20 -0
  227. package/gs/runtime/trace/index.test.ts +3 -0
  228. package/gs/slices/slices.test.ts +31 -0
  229. package/gs/slices/slices.ts +11 -11
  230. package/gs/strconv/append.test.ts +99 -0
  231. package/gs/strconv/atof.gs.ts +156 -42
  232. package/gs/strconv/atof.test.ts +45 -0
  233. package/gs/strconv/atoi.gs.ts +87 -69
  234. package/gs/strconv/atoi.test.ts +49 -0
  235. package/gs/strconv/ftoa.gs.ts +85 -10
  236. package/gs/strconv/ftoa.test.ts +43 -0
  237. package/gs/strconv/itoa.gs.ts +10 -9
  238. package/gs/strconv/quote.gs.ts +335 -108
  239. package/gs/strconv/quote.test.ts +111 -0
  240. package/gs/strings/reader.test.ts +10 -10
  241. package/gs/strings/reader.ts +9 -9
  242. package/gs/strings/strings.test.ts +18 -5
  243. package/gs/strings/strings.ts +81 -68
  244. package/gs/sync/atomic/doc_64.gs.ts +24 -24
  245. package/gs/sync/atomic/doc_64.test.ts +5 -5
  246. package/gs/sync/atomic/type.gs.ts +28 -28
  247. package/gs/sync/sync.test.ts +109 -1
  248. package/gs/sync/sync.ts +46 -12
  249. package/gs/syscall/fs.ts +8 -8
  250. package/gs/syscall/net.test.ts +1 -1
  251. package/gs/time/parse.test.ts +45 -0
  252. package/gs/time/time.test.ts +46 -23
  253. package/gs/time/time.ts +69 -66
  254. package/gs/unicode/gen.go +198 -0
  255. package/gs/unicode/tables.ts +646 -0
  256. package/gs/unicode/unicode.test.ts +69 -0
  257. package/gs/unicode/unicode.ts +396 -312
  258. package/package.json +2 -2
  259. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +0 -20
  260. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +0 -134
  261. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +0 -1
  262. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +0 -30
  263. package/gs/github.com/aperturerobotics/util/conc/index.ts +0 -172
  264. package/gs/github.com/aperturerobotics/util/conc/meta.json +0 -9
@@ -1,3 +1,4 @@
1
+ import { runtimePanic } from './panic.js'
1
2
  import {
2
3
  isOwnedPointerHandle,
3
4
  isVarRef,
@@ -123,6 +124,18 @@ export type Slice<T> =
123
124
  | null
124
125
  | (T extends number ? Uint8Array : never)
125
126
 
127
+ // outOfRangeIndex panics with Go's index-out-of-range runtime message. Go omits
128
+ // the "with length" suffix for negative indices and includes it otherwise, so
129
+ // callers route every element bounds failure through here to stay byte-faithful.
130
+ function outOfRangeIndex(index: number, length: number): never {
131
+ if (index < 0) {
132
+ runtimePanic(`runtime error: index out of range [${index}]`)
133
+ }
134
+ runtimePanic(
135
+ `runtime error: index out of range [${index}] with length ${length}`,
136
+ )
137
+ }
138
+
126
139
  /**
127
140
  * wrapSliceProxy wraps a SliceProxy in a Proxy to intercept index access
128
141
  * and route it through the backing array.
@@ -137,7 +150,7 @@ function wrapSliceProxy<T>(proxy: SliceProxy<T>): SliceProxy<T> {
137
150
  if (index < meta.length) {
138
151
  return meta.backing[meta.offset + index]
139
152
  }
140
- throw new Error(`Slice index out of range: ${index} >= ${meta.length}`)
153
+ outOfRangeIndex(index, meta.length)
141
154
  }
142
155
 
143
156
  if (prop === 'length') {
@@ -159,7 +172,7 @@ function wrapSliceProxy<T>(proxy: SliceProxy<T>): SliceProxy<T> {
159
172
  target[index] = value // Also update the proxy target for consistency
160
173
  return true
161
174
  }
162
- throw new Error(`Slice index out of range: ${index} >= ${meta.length}`)
175
+ outOfRangeIndex(index, meta.length)
163
176
  }
164
177
 
165
178
  if (prop === 'length' || prop === '__meta__') {
@@ -222,8 +235,8 @@ export function sliceToArray<T>(
222
235
  typeHint?: string,
223
236
  ): T[] | Uint8Array {
224
237
  if (len(slice) < length) {
225
- throw new Error(
226
- `runtime error: cannot convert slice with length ${len(slice)} to array with length ${length}`,
238
+ runtimePanic(
239
+ `runtime error: cannot convert slice with length ${len(slice)} to array or pointer to array with length ${length}`,
227
240
  )
228
241
  }
229
242
  if (typeHint === 'byte') {
@@ -240,8 +253,8 @@ export function sliceToArrayPointer<T>(
240
253
  typeHint?: string,
241
254
  ): VarRef<T[] | Uint8Array> {
242
255
  if (len(slice) < length) {
243
- throw new Error(
244
- `runtime error: cannot convert slice with length ${len(slice)} to array pointer with length ${length}`,
256
+ runtimePanic(
257
+ `runtime error: cannot convert slice with length ${len(slice)} to array or pointer to array with length ${length}`,
245
258
  )
246
259
  }
247
260
  if (typeHint === 'byte') {
@@ -323,8 +336,10 @@ export const makeSlice = <T>(
323
336
  if (typeHint === 'byte') {
324
337
  const actualCapacity = capacity === undefined ? length : capacity
325
338
  if (length < 0 || actualCapacity < 0 || length > actualCapacity) {
326
- throw new Error(
327
- `Invalid slice length (${length}) or capacity (${actualCapacity})`,
339
+ runtimePanic(
340
+ actualCapacity < 0 ?
341
+ 'runtime error: makeslice: cap out of range'
342
+ : 'runtime error: makeslice: len out of range',
328
343
  )
329
344
  }
330
345
 
@@ -343,8 +358,10 @@ export const makeSlice = <T>(
343
358
 
344
359
  const actualCapacity = capacity === undefined ? length : capacity
345
360
  if (length < 0 || actualCapacity < 0 || length > actualCapacity) {
346
- throw new Error(
347
- `Invalid slice length (${length}) or capacity (${actualCapacity})`,
361
+ runtimePanic(
362
+ actualCapacity < 0 ?
363
+ 'runtime error: makeslice: cap out of range'
364
+ : 'runtime error: makeslice: len out of range',
348
365
  )
349
366
  }
350
367
 
@@ -399,7 +416,7 @@ export const makeSlice = <T>(
399
416
  if (index < target.__meta__.length) {
400
417
  return target.__meta__.backing[target.__meta__.offset + index]
401
418
  }
402
- throw new Error(
419
+ runtimePanic(
403
420
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
404
421
  )
405
422
  }
@@ -423,7 +440,7 @@ export const makeSlice = <T>(
423
440
  target[index] = value // Also update the proxy target for consistency
424
441
  return true
425
442
  }
426
- throw new Error(
443
+ runtimePanic(
427
444
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
428
445
  )
429
446
  }
@@ -480,7 +497,7 @@ export function goSlice<T>( // T can be number for Uint8Array case
480
497
  if (index < target.__meta__.length) {
481
498
  return target.__meta__.backing[target.__meta__.offset + index]
482
499
  }
483
- throw new Error(
500
+ runtimePanic(
484
501
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
485
502
  )
486
503
  }
@@ -528,7 +545,7 @@ export function goSlice<T>( // T can be number for Uint8Array case
528
545
  target.__meta__.length++
529
546
  return true
530
547
  }
531
- throw new Error(
548
+ runtimePanic(
532
549
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
533
550
  )
534
551
  }
@@ -556,8 +573,8 @@ export function goSlice<T>( // T can be number for Uint8Array case
556
573
  actualLow > baseCapacity ||
557
574
  actualHigh > baseCapacity
558
575
  ) {
559
- throw new Error(
560
- `Invalid slice indices: low ${actualLow}, high ${actualHigh} for Uint8Array with capacity ${baseCapacity}`,
576
+ runtimePanic(
577
+ `runtime error: slice bounds out of range [${actualLow}:${actualHigh}] with capacity ${baseCapacity}`,
561
578
  )
562
579
  }
563
580
 
@@ -566,8 +583,8 @@ export function goSlice<T>( // T can be number for Uint8Array case
566
583
  if (max !== undefined) {
567
584
  if (max < actualHigh || max > baseCapacity) {
568
585
  // max is relative to the original s.length (capacity)
569
- throw new Error(
570
- `Invalid max index: ${max}. Constraints: low ${actualLow} <= high ${actualHigh} <= max <= capacity ${baseCapacity}`,
586
+ runtimePanic(
587
+ `runtime error: slice bounds out of range [:${actualHigh}:${max}] with capacity ${baseCapacity}`,
571
588
  )
572
589
  }
573
590
 
@@ -594,17 +611,17 @@ export function goSlice<T>( // T can be number for Uint8Array case
594
611
  high = high ?? 0
595
612
 
596
613
  if (low < 0 || high < low) {
597
- throw new Error(`Invalid slice indices: ${low}:${high}`)
614
+ runtimePanic(`runtime error: slice bounds out of range [${low}:${high}]`)
598
615
  }
599
616
 
600
617
  if (low !== 0 || high !== 0) {
601
- throw new Error(
618
+ runtimePanic(
602
619
  `runtime error: slice bounds out of range [:${high}] with capacity 0`,
603
620
  )
604
621
  }
605
622
 
606
623
  if (max !== undefined && max !== 0) {
607
- throw new Error(
624
+ runtimePanic(
608
625
  `runtime error: slice bounds out of range [::${max}] with capacity 0`,
609
626
  )
610
627
  }
@@ -617,13 +634,13 @@ export function goSlice<T>( // T can be number for Uint8Array case
617
634
  high = high ?? slen
618
635
 
619
636
  if (low < 0 || high < low) {
620
- throw new Error(`Invalid slice indices: ${low}:${high}`)
637
+ runtimePanic(`runtime error: slice bounds out of range [${low}:${high}]`)
621
638
  }
622
639
 
623
640
  // In Go, high can be up to capacity, not just length
624
641
  const scap = cap(s)
625
642
  if (high > scap) {
626
- throw new Error(`Slice index out of range: ${high} > ${scap}`)
643
+ runtimePanic(`Slice index out of range: ${high} > ${scap}`)
627
644
  }
628
645
 
629
646
  if (
@@ -652,15 +669,13 @@ export function goSlice<T>( // T can be number for Uint8Array case
652
669
  let newCap
653
670
  if (max !== undefined) {
654
671
  if (max < high) {
655
- throw new Error(`Invalid slice indices: ${low}:${high}:${max}`)
672
+ runtimePanic(`runtime error: slice bounds out of range [:${high}:${max}]`)
656
673
  }
657
674
  if (isComplexSlice(s) && max > oldOffset + oldCap) {
658
- throw new Error(
659
- `Slice index out of range: ${max} > ${oldOffset + oldCap}`,
660
- )
675
+ runtimePanic(`Slice index out of range: ${max} > ${oldOffset + oldCap}`)
661
676
  }
662
677
  if (!isComplexSlice(s) && max > s.length) {
663
- throw new Error(`Slice index out of range: ${max} > ${s.length}`)
678
+ runtimePanic(`Slice index out of range: ${max} > ${s.length}`)
664
679
  }
665
680
  newCap = max - low
666
681
  } else {
@@ -735,7 +750,7 @@ export const arrayToSlice = <T>(
735
750
  if (index < target.__meta__.length) {
736
751
  return target.__meta__.backing[target.__meta__.offset + index]
737
752
  }
738
- throw new Error(
753
+ runtimePanic(
739
754
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
740
755
  )
741
756
  }
@@ -781,7 +796,7 @@ export const arrayToSlice = <T>(
781
796
  target.__meta__.length++
782
797
  return true
783
798
  }
784
- throw new Error(
799
+ runtimePanic(
785
800
  `Slice index out of range: ${index} >= ${target.__meta__.length}`,
786
801
  )
787
802
  }
@@ -1330,34 +1345,66 @@ export function index<T>(
1330
1345
  index: number,
1331
1346
  ): T | number {
1332
1347
  if (collection === null || collection === undefined) {
1333
- throw new Error('runtime error: index on nil or undefined collection')
1348
+ runtimePanic('runtime error: index on nil or undefined collection')
1334
1349
  }
1335
1350
 
1336
1351
  if (isGoStringValue(collection)) {
1337
1352
  return indexString(collection, index) // Use the existing indexString for byte access
1338
1353
  } else if (collection instanceof Uint8Array) {
1339
1354
  if (index < 0 || index >= collection.length) {
1340
- throw new Error(
1341
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1342
- )
1355
+ outOfRangeIndex(index, collection.length)
1343
1356
  }
1344
1357
  return collection[index]
1345
1358
  } else if (isComplexSlice(collection)) {
1346
1359
  if (index < 0 || index >= collection.__meta__.length) {
1347
- throw new Error(
1348
- `runtime error: index out of range [${index}] with length ${collection.__meta__.length}`,
1349
- )
1360
+ outOfRangeIndex(index, collection.__meta__.length)
1350
1361
  }
1351
1362
  return collection.__meta__.backing[collection.__meta__.offset + index]
1352
1363
  } else if (Array.isArray(collection)) {
1353
1364
  if (index < 0 || index >= collection.length) {
1354
- throw new Error(
1355
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1356
- )
1365
+ outOfRangeIndex(index, collection.length)
1357
1366
  }
1358
1367
  return collection[index]
1359
1368
  }
1360
- throw new Error('runtime error: index on unsupported type')
1369
+ runtimePanic('runtime error: index on unsupported type')
1370
+ }
1371
+
1372
+ /**
1373
+ * arrayIndex reads collection[index] with Go bounds-check semantics, panicking
1374
+ * with the Go runtime message when index is out of range. Strings and maps are
1375
+ * lowered through their own helpers, so this covers Go arrays and slices. The
1376
+ * overloads reproduce the element type of a direct collection[index]: a byte
1377
+ * collection yields number, an element slice yields its element type.
1378
+ */
1379
+ export function arrayIndex(collection: Uint8Array, index: number): number
1380
+ export function arrayIndex<T>(collection: Slice<T> | T[], index: number): T
1381
+ export function arrayIndex<T>(
1382
+ collection: Slice<T> | T[] | Uint8Array,
1383
+ index: number,
1384
+ ): T | number {
1385
+ if (collection === null || collection === undefined) {
1386
+ outOfRangeIndex(index, 0)
1387
+ }
1388
+ if (collection instanceof Uint8Array) {
1389
+ if (index < 0 || index >= collection.length) {
1390
+ outOfRangeIndex(index, collection.length)
1391
+ }
1392
+ return collection[index]
1393
+ }
1394
+ if (isComplexSlice(collection)) {
1395
+ const length = collection.__meta__.length
1396
+ if (index < 0 || index >= length) {
1397
+ outOfRangeIndex(index, length)
1398
+ }
1399
+ return collection.__meta__.backing[collection.__meta__.offset + index]
1400
+ }
1401
+ if (Array.isArray(collection)) {
1402
+ if (index < 0 || index >= collection.length) {
1403
+ outOfRangeIndex(index, collection.length)
1404
+ }
1405
+ return collection[index]
1406
+ }
1407
+ runtimePanic('runtime error: index on unsupported type')
1361
1408
  }
1362
1409
 
1363
1410
  /**
@@ -1368,13 +1415,11 @@ export function indexRef<T>(
1368
1415
  index: number,
1369
1416
  ): VarRef<T> {
1370
1417
  if (collection === null || collection === undefined) {
1371
- throw new Error('runtime error: index on nil or undefined collection')
1418
+ runtimePanic('runtime error: index on nil or undefined collection')
1372
1419
  }
1373
1420
  if (collection instanceof Uint8Array) {
1374
1421
  if (index < 0 || index >= collection.length) {
1375
- throw new Error(
1376
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1377
- )
1422
+ outOfRangeIndex(index, collection.length)
1378
1423
  }
1379
1424
  const ref: VarRef<T> = {
1380
1425
  get value() {
@@ -1393,9 +1438,7 @@ export function indexRef<T>(
1393
1438
  }
1394
1439
  if (isComplexSlice(collection)) {
1395
1440
  if (index < 0 || index >= collection.__meta__.length) {
1396
- throw new Error(
1397
- `runtime error: index out of range [${index}] with length ${collection.__meta__.length}`,
1398
- )
1441
+ outOfRangeIndex(index, collection.__meta__.length)
1399
1442
  }
1400
1443
  const backingIndex = collection.__meta__.offset + index
1401
1444
  const ref: VarRef<T> = {
@@ -1415,9 +1458,7 @@ export function indexRef<T>(
1415
1458
  }
1416
1459
  if (Array.isArray(collection)) {
1417
1460
  if (index < 0 || index >= collection.length) {
1418
- throw new Error(
1419
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1420
- )
1461
+ outOfRangeIndex(index, collection.length)
1421
1462
  }
1422
1463
  const ref: VarRef<T> = {
1423
1464
  get value() {
@@ -1434,7 +1475,7 @@ export function indexRef<T>(
1434
1475
  ref.__goPointer = collectionPointer(ref, collection, index)
1435
1476
  return ref
1436
1477
  }
1437
- throw new Error('runtime error: index on unsupported type')
1478
+ runtimePanic('runtime error: index on unsupported type')
1438
1479
  }
1439
1480
 
1440
1481
  function collectionPointer<T>(
@@ -1448,7 +1489,7 @@ function collectionPointer<T>(
1448
1489
  __goRef: () => ref,
1449
1490
  __goSlice: (length: number) => {
1450
1491
  if (length < 0) {
1451
- throw new Error('runtime error: unsafe slice length out of range')
1492
+ runtimePanic('runtime error: unsafe slice length out of range')
1452
1493
  }
1453
1494
  return goSlice(collection as any, index, index + length, index + length)
1454
1495
  },
@@ -1517,7 +1558,7 @@ export function indexAddress<T>(
1517
1558
  index: number,
1518
1559
  ): number {
1519
1560
  if (collection === null || collection === undefined) {
1520
- throw new Error('runtime error: index on nil or undefined collection')
1561
+ runtimePanic('runtime error: index on nil or undefined collection')
1521
1562
  }
1522
1563
 
1523
1564
  let backing: object
@@ -1536,13 +1577,11 @@ export function indexAddress<T>(
1536
1577
  backingIndex = index
1537
1578
  length = collection.length
1538
1579
  } else {
1539
- throw new Error('runtime error: index on unsupported type')
1580
+ runtimePanic('runtime error: index on unsupported type')
1540
1581
  }
1541
1582
 
1542
1583
  if (index < 0 || index >= length) {
1543
- throw new Error(
1544
- `runtime error: index out of range [${index}] with length ${length}`,
1545
- )
1584
+ outOfRangeIndex(index, length)
1546
1585
  }
1547
1586
 
1548
1587
  let base = addressBases.get(backing)
@@ -1619,14 +1658,12 @@ export function indexByteAddress<T>(
1619
1658
  elementByteSize: number,
1620
1659
  ): number {
1621
1660
  if (collection === null || collection === undefined) {
1622
- throw new Error('runtime error: index on nil or undefined collection')
1661
+ runtimePanic('runtime error: index on nil or undefined collection')
1623
1662
  }
1624
1663
 
1625
1664
  if (collection instanceof Uint8Array) {
1626
1665
  if (index < 0 || index >= collection.length) {
1627
- throw new Error(
1628
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1629
- )
1666
+ outOfRangeIndex(index, collection.length)
1630
1667
  }
1631
1668
  const view = new Uint8Array(collection.buffer)
1632
1669
  const base = byteAddressBase(collection.buffer, {
@@ -1643,9 +1680,7 @@ export function indexByteAddress<T>(
1643
1680
 
1644
1681
  if (isComplexSlice(collection)) {
1645
1682
  if (index < 0 || index >= collection.__meta__.length) {
1646
- throw new Error(
1647
- `runtime error: index out of range [${index}] with length ${collection.__meta__.length}`,
1648
- )
1683
+ outOfRangeIndex(index, collection.__meta__.length)
1649
1684
  }
1650
1685
  const backing = collection.__meta__.backing as unknown as number[]
1651
1686
  const byteSize = Math.max(1, Math.trunc(elementByteSize))
@@ -1655,9 +1690,7 @@ export function indexByteAddress<T>(
1655
1690
 
1656
1691
  if (Array.isArray(collection)) {
1657
1692
  if (index < 0 || index >= collection.length) {
1658
- throw new Error(
1659
- `runtime error: index out of range [${index}] with length ${collection.length}`,
1660
- )
1693
+ outOfRangeIndex(index, collection.length)
1661
1694
  }
1662
1695
  const byteSize = Math.max(1, Math.trunc(elementByteSize))
1663
1696
  const base = byteAddressBase(
@@ -1667,7 +1700,7 @@ export function indexByteAddress<T>(
1667
1700
  return base + index * byteSize
1668
1701
  }
1669
1702
 
1670
- throw new Error('runtime error: index on unsupported type')
1703
+ runtimePanic('runtime error: index on unsupported type')
1671
1704
  }
1672
1705
 
1673
1706
  /**
@@ -1685,7 +1718,7 @@ export function unsafePointerRef<T>(address: number | bigint): VarRef<T> {
1685
1718
  }
1686
1719
  const offset = numericAddress - base
1687
1720
  if (offset < 0 || offset >= source.byteLength) {
1688
- throw new Error('runtime error: unsafe pointer address out of range')
1721
+ runtimePanic('runtime error: unsafe pointer address out of range')
1689
1722
  }
1690
1723
  return {
1691
1724
  get value(): T {
@@ -1709,7 +1742,7 @@ function byteArrayFromAddress(
1709
1742
  const index = sliceIndexProperty(prop)
1710
1743
  if (index >= 0) {
1711
1744
  if (index >= length) {
1712
- throw new Error(`Slice index out of range: ${index} >= ${length}`)
1745
+ runtimePanic(`Slice index out of range: ${index} >= ${length}`)
1713
1746
  }
1714
1747
  return unsafePointerRef<number>(start + index).value
1715
1748
  }
@@ -1719,7 +1752,7 @@ function byteArrayFromAddress(
1719
1752
  const index = sliceIndexProperty(prop)
1720
1753
  if (index >= 0) {
1721
1754
  if (index >= length) {
1722
- throw new Error(`Slice index out of range: ${index} >= ${length}`)
1755
+ runtimePanic(`Slice index out of range: ${index} >= ${length}`)
1723
1756
  }
1724
1757
  unsafePointerRef<number>(start + index).value = value
1725
1758
  return true
@@ -1773,7 +1806,26 @@ export const stringToRune = (str: string): number => {
1773
1806
  * @returns The resulting string.
1774
1807
  */
1775
1808
  export const runesToString = (runes: Slice<number>): string => {
1776
- return runes?.length ? String.fromCharCode(...runes) : ''
1809
+ if (!runes?.length) {
1810
+ return ''
1811
+ }
1812
+ let out = ''
1813
+ for (const r of runes) {
1814
+ out += runeToString(r)
1815
+ }
1816
+ return out
1817
+ }
1818
+
1819
+ // runeToString encodes one rune as Go's string(rune) does: a valid Unicode
1820
+ // scalar value becomes its character including code points above U+FFFF (astral
1821
+ // planes), and a negative, out-of-range, or surrogate rune becomes U+FFFD
1822
+ // (utf8.RuneError), never a throw. String.fromCharCode truncated astral runes to
1823
+ // a single broken UTF-16 unit; String.fromCodePoint preserves the full rune.
1824
+ export function runeToString(r: number): string {
1825
+ if (r < 0 || r > 0x10ffff || (r >= 0xd800 && r <= 0xdfff)) {
1826
+ return '�'
1827
+ }
1828
+ return String.fromCodePoint(r)
1777
1829
  }
1778
1830
 
1779
1831
  /**
@@ -1802,30 +1854,22 @@ export const indexString = (
1802
1854
  // Bytes - access directly
1803
1855
  if (str instanceof Uint8Array) {
1804
1856
  if (index < 0 || index >= str.length) {
1805
- throw new Error(
1806
- `runtime error: index out of range [${index}] with length ${str.length}`,
1807
- )
1857
+ outOfRangeIndex(index, str.length)
1808
1858
  }
1809
1859
  return str[index]
1810
1860
  }
1811
1861
  // Array or null
1812
1862
  if (str === null || str === undefined) {
1813
- throw new Error(
1814
- `runtime error: index out of range [${index}] with length 0`,
1815
- )
1863
+ outOfRangeIndex(index, 0)
1816
1864
  }
1817
1865
  if (index < 0 || index >= str.length) {
1818
- throw new Error(
1819
- `runtime error: index out of range [${index}] with length ${str.length}`,
1820
- )
1866
+ outOfRangeIndex(index, str.length)
1821
1867
  }
1822
1868
  return str[index]
1823
1869
  }
1824
1870
  const bytes = goStringBytes(str)
1825
1871
  if (index < 0 || index >= bytes.length) {
1826
- throw new Error(
1827
- `runtime error: index out of range [${index}] with length ${bytes.length}`,
1828
- )
1872
+ outOfRangeIndex(index, bytes.length)
1829
1873
  }
1830
1874
  return bytes[index]
1831
1875
  }
@@ -1871,7 +1915,7 @@ export const sliceString = (
1871
1915
  ) {
1872
1916
  return ''
1873
1917
  }
1874
- throw new Error(
1918
+ runtimePanic(
1875
1919
  `runtime error: slice bounds out of range [${actualLow}:${actualHigh}] with length ${bytes.length}`,
1876
1920
  )
1877
1921
  }
@@ -2142,22 +2186,16 @@ export function indexStringOrBytes(
2142
2186
  } else if (value instanceof Uint8Array) {
2143
2187
  // For Uint8Array, direct access returns the byte value
2144
2188
  if (index < 0 || index >= value.length) {
2145
- throw new Error(
2146
- `runtime error: index out of range [${index}] with length ${value.length}`,
2147
- )
2189
+ outOfRangeIndex(index, value.length)
2148
2190
  }
2149
2191
  return value[index]
2150
2192
  } else if (value === null) {
2151
- throw new Error(
2152
- `runtime error: index out of range [${index}] with length 0`,
2153
- )
2193
+ outOfRangeIndex(index, 0)
2154
2194
  } else {
2155
2195
  // For Slice<number> (including SliceProxy)
2156
2196
  const length = len(value)
2157
2197
  if (index < 0 || index >= length) {
2158
- throw new Error(
2159
- `runtime error: index out of range [${index}] with length ${length}`,
2160
- )
2198
+ outOfRangeIndex(index, length)
2161
2199
  }
2162
2200
  return (value as any)[index] as number
2163
2201
  }
@@ -285,6 +285,19 @@ export const registerInterfaceType = (
285
285
  return typeInfo
286
286
  }
287
287
 
288
+ // The builtin error interface is predeclared in Go. Register it so a bare
289
+ // "error" type assertion (x.(error)), which the compiler emits by the universe
290
+ // type name, resolves to its method set instead of an unmatched basic type. Any
291
+ // value with an Error() string method, including recovered runtime panics,
292
+ // then satisfies it.
293
+ registerInterfaceType('error', null, [
294
+ {
295
+ name: 'Error',
296
+ args: [],
297
+ returns: [{ type: { kind: TypeKind.Basic, name: 'string' } }],
298
+ },
299
+ ])
300
+
288
301
  /**
289
302
  * Gets a registered type by name from the type registry.
290
303
  * Returns undefined if the type is not registered.
@@ -632,20 +645,20 @@ function validateMapKey(key: any, keyTypeInfo: TypeInfo): boolean {
632
645
  */
633
646
  function matchesBasicType(value: any, info: TypeInfo): boolean {
634
647
  if (info.name === 'string') return typeof value === 'string'
648
+ if (info.name === 'int64' || info.name === 'uint64')
649
+ return typeof value === 'bigint'
635
650
  if (
636
651
  info.name === 'number' ||
637
652
  info.name === 'int' ||
638
653
  info.name === 'int8' ||
639
654
  info.name === 'int16' ||
640
655
  info.name === 'int32' ||
641
- info.name === 'int64' ||
642
656
  info.name === 'uint' ||
657
+ info.name === 'uintptr' ||
643
658
  info.name === 'uint8' ||
644
659
  info.name === 'byte' ||
645
660
  info.name === 'uint16' ||
646
661
  info.name === 'uint32' ||
647
- info.name === 'uint64' ||
648
- info.name === 'uintptr' ||
649
662
  info.name === 'float32' ||
650
663
  info.name === 'float64'
651
664
  )
@@ -1,3 +1,5 @@
1
+ import { runtimePanic } from './panic.js'
2
+
1
3
  export interface OwnedPointerHandle<T = unknown> {
2
4
  readonly __goOwnedPointer: true
3
5
  __goAddress: () => number
@@ -126,10 +128,10 @@ export function ownedPointerRef<T>(pointer: OwnedPointerHandle<T>): VarRef<T> {
126
128
  return pointer.__goRef()
127
129
  }
128
130
 
129
- /** Dereference a variable reference, throws on null simulates Go panic. */
131
+ /** Dereference a variable reference; a null ref raises a Go runtime panic. */
130
132
  export function unref<T>(b: VarRef<T>): T {
131
133
  if (b === null) {
132
- throw new Error(
134
+ runtimePanic(
133
135
  'runtime error: invalid memory address or nil pointer dereference',
134
136
  )
135
137
  }
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { uint, uint64, uint64Add, uint64Shr } from './builtin.js'
4
+
5
+ // Go represents uint/uintptr as a TypeScript number, but values above 2^53
6
+ // cannot round-trip through a JS number. uint() keeps those as a runtime bigint
7
+ // (typed number) so full 64-bit width survives, matching Go semantics such as
8
+ // ^uint(0) == 2^64-1. int64/uint64 stay bigint unconditionally.
9
+ describe('uint full 64-bit width (Go uint semantics)', () => {
10
+ const maxUint = 18446744073709551615n // ^uint(0)
11
+
12
+ it('preserves ^uint(0) without precision loss', () => {
13
+ const v = uint(maxUint, 64)
14
+ expect(v).toBe(maxUint as unknown as number)
15
+ })
16
+
17
+ it('keeps small uint values as plain numbers', () => {
18
+ expect(uint(5n, 64)).toBe(5)
19
+ expect(typeof uint(5n, 64)).toBe('number')
20
+ expect(typeof uint(maxUint, 64)).toBe('bigint')
21
+ })
22
+
23
+ it('right-shifting ^uint(0) yields a 64-bit-wide result, not 0 or 1', () => {
24
+ // uintBitLen-style loop: repeated >>1 from 2^64-1 must count 64 bits.
25
+ let n: number | bigint = uint(maxUint, 64)
26
+ let bits = 0
27
+ while ((n as bigint) !== 0n && (n as number) !== 0) {
28
+ bits++
29
+ n = uint(uint64Shr(n, 1), 64)
30
+ }
31
+ expect(bits).toBe(64)
32
+ })
33
+
34
+ it('uint64 modular wraparound preserves full width', () => {
35
+ // (2^64-1) + 1 wraps to 0 under uint64.
36
+ expect(uint64Add(maxUint, 1n)).toBe(0n)
37
+ // uint64 always yields bigint regardless of magnitude.
38
+ expect(uint64(7)).toBe(7n)
39
+ expect(typeof uint64(7)).toBe('bigint')
40
+ })
41
+ })