goscript 0.1.0 → 0.1.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 (327) hide show
  1. package/README.md +267 -255
  2. package/cmd/goscript/cmd-test.go +193 -0
  3. package/cmd/goscript/cmd-test_test.go +76 -0
  4. package/cmd/goscript/main.go +1 -0
  5. package/compiler/build-flags.go +38 -0
  6. package/compiler/compile-request.go +2 -0
  7. package/compiler/compliance_test.go +0 -8
  8. package/compiler/gotest/owner.go +24 -0
  9. package/compiler/gotest/package-result.go +67 -0
  10. package/compiler/gotest/request.go +145 -0
  11. package/compiler/gotest/result.go +28 -0
  12. package/compiler/gotest/runner.go +588 -0
  13. package/compiler/gotest/runner_test.go +627 -0
  14. package/compiler/gotest/test.go +9 -0
  15. package/compiler/index.test.ts +1 -1
  16. package/compiler/lowered-program.go +71 -19
  17. package/compiler/lowering.go +5065 -569
  18. package/compiler/override-facts.go +307 -0
  19. package/compiler/override-registry.go +50 -189
  20. package/compiler/override-registry_test.go +47 -0
  21. package/compiler/package-graph.go +50 -27
  22. package/compiler/package-graph_test.go +37 -2
  23. package/compiler/package-test-function.go +9 -0
  24. package/compiler/package-test-graph-package.go +40 -0
  25. package/compiler/package-test-graph-variant.go +105 -0
  26. package/compiler/package-test-graph.go +117 -0
  27. package/compiler/package-test-graph_test.go +144 -0
  28. package/compiler/runtime-contract.go +189 -29
  29. package/compiler/runtime-contract_test.go +44 -30
  30. package/compiler/semantic-model-types.go +9 -6
  31. package/compiler/semantic-model.go +538 -38
  32. package/compiler/semantic-model_test.go +55 -0
  33. package/compiler/service.go +1 -1
  34. package/compiler/skeleton_test.go +679 -49
  35. package/compiler/tsworkspace/owner.go +334 -0
  36. package/compiler/tsworkspace/owner_test.go +93 -0
  37. package/compiler/tsworkspace/result.go +17 -0
  38. package/compiler/typescript-emitter.go +459 -82
  39. package/compiler/wasm/compile.go +1 -1
  40. package/compiler/wasm/compile_test.go +61 -11
  41. package/compiler/wasm_api.go +172 -7
  42. package/dist/gs/builtin/builtin.d.ts +20 -2
  43. package/dist/gs/builtin/builtin.js +194 -6
  44. package/dist/gs/builtin/builtin.js.map +1 -1
  45. package/dist/gs/builtin/channel.d.ts +8 -0
  46. package/dist/gs/builtin/channel.js +12 -0
  47. package/dist/gs/builtin/channel.js.map +1 -1
  48. package/dist/gs/builtin/slice.d.ts +22 -2
  49. package/dist/gs/builtin/slice.js +216 -44
  50. package/dist/gs/builtin/slice.js.map +1 -1
  51. package/dist/gs/builtin/type.d.ts +5 -2
  52. package/dist/gs/builtin/type.js +83 -24
  53. package/dist/gs/builtin/type.js.map +1 -1
  54. package/dist/gs/builtin/varRef.d.ts +5 -0
  55. package/dist/gs/builtin/varRef.js +23 -0
  56. package/dist/gs/builtin/varRef.js.map +1 -1
  57. package/dist/gs/bytes/buffer.gs.js +48 -44
  58. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  59. package/dist/gs/bytes/reader.gs.js +20 -18
  60. package/dist/gs/bytes/reader.gs.js.map +1 -1
  61. package/dist/gs/context/context.d.ts +5 -4
  62. package/dist/gs/context/context.js +10 -10
  63. package/dist/gs/context/context.js.map +1 -1
  64. package/dist/gs/crypto/internal/fips140deps/byteorder/index.d.ts +1 -0
  65. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js +2 -0
  66. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js.map +1 -0
  67. package/dist/gs/crypto/internal/fips140deps/godebug/index.d.ts +1 -0
  68. package/dist/gs/crypto/internal/fips140deps/godebug/index.js +2 -0
  69. package/dist/gs/crypto/internal/fips140deps/godebug/index.js.map +1 -0
  70. package/dist/gs/embed/index.d.ts +7 -0
  71. package/dist/gs/embed/index.js +16 -0
  72. package/dist/gs/embed/index.js.map +1 -0
  73. package/dist/gs/encoding/json/index.d.ts +1 -0
  74. package/dist/gs/encoding/json/index.js +18 -0
  75. package/dist/gs/encoding/json/index.js.map +1 -1
  76. package/dist/gs/errors/errors.d.ts +4 -0
  77. package/dist/gs/errors/errors.js +81 -0
  78. package/dist/gs/errors/errors.js.map +1 -1
  79. package/dist/gs/fmt/fmt.d.ts +4 -4
  80. package/dist/gs/fmt/fmt.js +42 -11
  81. package/dist/gs/fmt/fmt.js.map +1 -1
  82. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +35 -0
  83. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +211 -1
  84. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  85. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +189 -0
  86. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +825 -0
  87. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -0
  88. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +163 -0
  89. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +449 -0
  90. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -0
  91. package/dist/gs/github.com/klauspost/compress/internal/le/index.d.ts +9 -0
  92. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +71 -0
  93. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -0
  94. package/dist/gs/go/internal/scannerhooks/index.d.ts +3 -0
  95. package/dist/gs/go/internal/scannerhooks/index.js +5 -0
  96. package/dist/gs/go/internal/scannerhooks/index.js.map +1 -0
  97. package/dist/gs/go/scanner/index.d.ts +13 -0
  98. package/dist/gs/go/scanner/index.js +35 -0
  99. package/dist/gs/go/scanner/index.js.map +1 -1
  100. package/dist/gs/go/token/index.d.ts +156 -0
  101. package/dist/gs/go/token/index.js +500 -4
  102. package/dist/gs/go/token/index.js.map +1 -1
  103. package/dist/gs/internal/abi/index.d.ts +4 -0
  104. package/dist/gs/internal/abi/index.js +10 -0
  105. package/dist/gs/internal/abi/index.js.map +1 -1
  106. package/dist/gs/internal/bytealg/index.d.ts +2 -0
  107. package/dist/gs/internal/bytealg/index.js +14 -0
  108. package/dist/gs/internal/bytealg/index.js.map +1 -1
  109. package/dist/gs/internal/byteorder/index.d.ts +8 -2
  110. package/dist/gs/internal/byteorder/index.js +56 -25
  111. package/dist/gs/internal/byteorder/index.js.map +1 -1
  112. package/dist/gs/internal/godebug/index.d.ts +12 -0
  113. package/dist/gs/internal/godebug/index.js +30 -0
  114. package/dist/gs/internal/godebug/index.js.map +1 -0
  115. package/dist/gs/io/fs/index.d.ts +1 -0
  116. package/dist/gs/io/fs/index.js +1 -0
  117. package/dist/gs/io/fs/index.js.map +1 -1
  118. package/dist/gs/io/fs/readlink.d.ts +8 -0
  119. package/dist/gs/io/fs/readlink.js +64 -0
  120. package/dist/gs/io/fs/readlink.js.map +1 -0
  121. package/dist/gs/io/fs/walk.d.ts +3 -3
  122. package/dist/gs/io/fs/walk.js +7 -7
  123. package/dist/gs/io/fs/walk.js.map +1 -1
  124. package/dist/gs/io/io.d.ts +40 -6
  125. package/dist/gs/io/io.js +151 -26
  126. package/dist/gs/io/io.js.map +1 -1
  127. package/dist/gs/maps/iter.d.ts +3 -3
  128. package/dist/gs/maps/iter.js +3 -3
  129. package/dist/gs/maps/iter.js.map +1 -1
  130. package/dist/gs/maps/maps.d.ts +2 -2
  131. package/dist/gs/maps/maps.js +1 -1
  132. package/dist/gs/maps/maps.js.map +1 -1
  133. package/dist/gs/math/bits/index.d.ts +13 -4
  134. package/dist/gs/math/bits/index.js +66 -34
  135. package/dist/gs/math/bits/index.js.map +1 -1
  136. package/dist/gs/math/const.gs.d.ts +5 -5
  137. package/dist/gs/math/const.gs.js +4 -4
  138. package/dist/gs/math/const.gs.js.map +1 -1
  139. package/dist/gs/mime/index.d.ts +1 -0
  140. package/dist/gs/mime/index.js +50 -0
  141. package/dist/gs/mime/index.js.map +1 -0
  142. package/dist/gs/net/http/httptest/index.d.ts +11 -0
  143. package/dist/gs/net/http/httptest/index.js +21 -0
  144. package/dist/gs/net/http/httptest/index.js.map +1 -0
  145. package/dist/gs/net/http/index.d.ts +27 -0
  146. package/dist/gs/net/http/index.js +61 -0
  147. package/dist/gs/net/http/index.js.map +1 -0
  148. package/dist/gs/os/dir_unix.gs.js +2 -2
  149. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  150. package/dist/gs/os/types_js.gs.js.map +1 -1
  151. package/dist/gs/path/filepath/match.js +165 -3
  152. package/dist/gs/path/filepath/match.js.map +1 -1
  153. package/dist/gs/path/filepath/path.d.ts +3 -1
  154. package/dist/gs/path/filepath/path.js +133 -4
  155. package/dist/gs/path/filepath/path.js.map +1 -1
  156. package/dist/gs/path/path.d.ts +4 -1
  157. package/dist/gs/path/path.js +16 -4
  158. package/dist/gs/path/path.js.map +1 -1
  159. package/dist/gs/reflect/index.d.ts +1 -1
  160. package/dist/gs/reflect/index.js +1 -1
  161. package/dist/gs/reflect/index.js.map +1 -1
  162. package/dist/gs/reflect/map.js +3 -0
  163. package/dist/gs/reflect/map.js.map +1 -1
  164. package/dist/gs/reflect/type.d.ts +7 -4
  165. package/dist/gs/reflect/type.js +148 -7
  166. package/dist/gs/reflect/type.js.map +1 -1
  167. package/dist/gs/runtime/debug/index.d.ts +2 -0
  168. package/dist/gs/runtime/debug/index.js +8 -0
  169. package/dist/gs/runtime/debug/index.js.map +1 -0
  170. package/dist/gs/runtime/runtime.d.ts +35 -3
  171. package/dist/gs/runtime/runtime.js +72 -0
  172. package/dist/gs/runtime/runtime.js.map +1 -1
  173. package/dist/gs/slices/slices.d.ts +24 -5
  174. package/dist/gs/slices/slices.js +214 -5
  175. package/dist/gs/slices/slices.js.map +1 -1
  176. package/dist/gs/sort/slice.gs.d.ts +3 -3
  177. package/dist/gs/sort/slice.gs.js +6 -6
  178. package/dist/gs/sort/slice.gs.js.map +1 -1
  179. package/dist/gs/sort/sort.gs.d.ts +4 -4
  180. package/dist/gs/sort/sort.gs.js +11 -8
  181. package/dist/gs/sort/sort.gs.js.map +1 -1
  182. package/dist/gs/strings/builder.d.ts +1 -1
  183. package/dist/gs/strings/builder.js +3 -2
  184. package/dist/gs/strings/builder.js.map +1 -1
  185. package/dist/gs/sync/atomic/type.gs.d.ts +9 -8
  186. package/dist/gs/sync/atomic/type.gs.js +0 -2
  187. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  188. package/dist/gs/sync/sync.d.ts +2 -0
  189. package/dist/gs/sync/sync.js +27 -0
  190. package/dist/gs/sync/sync.js.map +1 -1
  191. package/dist/gs/syscall/constants.d.ts +36 -24
  192. package/dist/gs/syscall/constants.js +12 -0
  193. package/dist/gs/syscall/constants.js.map +1 -1
  194. package/dist/gs/syscall/errors.d.ts +2 -0
  195. package/dist/gs/syscall/errors.js +8 -0
  196. package/dist/gs/syscall/errors.js.map +1 -1
  197. package/dist/gs/syscall/fs.d.ts +43 -0
  198. package/dist/gs/syscall/fs.js +102 -0
  199. package/dist/gs/syscall/fs.js.map +1 -1
  200. package/dist/gs/syscall/js/index.d.ts +90 -0
  201. package/dist/gs/syscall/js/index.js +375 -0
  202. package/dist/gs/syscall/js/index.js.map +1 -0
  203. package/dist/gs/syscall/types.d.ts +22 -0
  204. package/dist/gs/syscall/types.js +45 -1
  205. package/dist/gs/syscall/types.js.map +1 -1
  206. package/dist/gs/testing/index.d.ts +1 -0
  207. package/dist/gs/testing/index.js +2 -0
  208. package/dist/gs/testing/index.js.map +1 -0
  209. package/dist/gs/testing/testing.d.ts +77 -0
  210. package/dist/gs/testing/testing.js +301 -0
  211. package/dist/gs/testing/testing.js.map +1 -0
  212. package/dist/gs/time/time.d.ts +41 -4
  213. package/dist/gs/time/time.js +205 -36
  214. package/dist/gs/time/time.js.map +1 -1
  215. package/dist/gs/unicode/unicode.d.ts +23 -1
  216. package/dist/gs/unicode/unicode.js +79 -10
  217. package/dist/gs/unicode/unicode.js.map +1 -1
  218. package/dist/gs/unicode/utf8/utf8.d.ts +4 -4
  219. package/dist/gs/unicode/utf8/utf8.js +24 -11
  220. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  221. package/dist/gs/unique/index.d.ts +11 -0
  222. package/dist/gs/unique/index.js +71 -0
  223. package/dist/gs/unique/index.js.map +1 -0
  224. package/go.sum +9 -0
  225. package/gs/builtin/builtin.ts +239 -8
  226. package/gs/builtin/channel.ts +22 -0
  227. package/gs/builtin/runtime-contract.test.ts +126 -0
  228. package/gs/builtin/slice.ts +259 -50
  229. package/gs/builtin/type.ts +109 -34
  230. package/gs/builtin/varRef.ts +38 -1
  231. package/gs/bytes/buffer.gs.ts +48 -44
  232. package/gs/bytes/meta.json +8 -3
  233. package/gs/bytes/reader.gs.ts +20 -19
  234. package/gs/context/context.test.ts +41 -0
  235. package/gs/context/context.ts +22 -26
  236. package/gs/crypto/internal/fips140deps/byteorder/index.ts +1 -0
  237. package/gs/crypto/internal/fips140deps/godebug/index.ts +1 -0
  238. package/gs/embed/index.ts +20 -0
  239. package/gs/embed/meta.json +5 -0
  240. package/gs/encoding/json/index.test.ts +15 -1
  241. package/gs/encoding/json/index.ts +24 -0
  242. package/gs/errors/errors.test.ts +82 -0
  243. package/gs/errors/errors.ts +104 -0
  244. package/gs/fmt/fmt.ts +56 -16
  245. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +73 -1
  246. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +297 -1
  247. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +159 -0
  248. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +1005 -0
  249. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +719 -0
  250. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +40 -0
  251. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +36 -0
  252. package/gs/github.com/klauspost/compress/internal/le/index.ts +114 -0
  253. package/gs/go/internal/scannerhooks/index.test.ts +14 -0
  254. package/gs/go/internal/scannerhooks/index.ts +9 -0
  255. package/gs/go/scanner/index.test.ts +22 -0
  256. package/gs/go/scanner/index.ts +47 -0
  257. package/gs/go/token/index.test.ts +47 -1
  258. package/gs/go/token/index.ts +570 -4
  259. package/gs/internal/abi/index.test.ts +18 -0
  260. package/gs/internal/abi/index.ts +14 -0
  261. package/gs/internal/bytealg/index.test.ts +18 -0
  262. package/gs/internal/bytealg/index.ts +16 -0
  263. package/gs/internal/byteorder/index.test.ts +39 -0
  264. package/gs/internal/byteorder/index.ts +100 -27
  265. package/gs/internal/godebug/index.test.ts +16 -0
  266. package/gs/internal/godebug/index.ts +35 -0
  267. package/gs/io/fs/index.ts +1 -0
  268. package/gs/io/fs/meta.json +5 -0
  269. package/gs/io/fs/readlink.test.ts +43 -0
  270. package/gs/io/fs/readlink.ts +77 -0
  271. package/gs/io/fs/walk.test.ts +61 -0
  272. package/gs/io/fs/walk.ts +9 -9
  273. package/gs/io/io.ts +174 -31
  274. package/gs/io/meta.json +10 -2
  275. package/gs/maps/iter.ts +12 -6
  276. package/gs/maps/maps.ts +8 -6
  277. package/gs/math/bits/index.ts +103 -47
  278. package/gs/math/const.gs.test.ts +11 -5
  279. package/gs/math/const.gs.ts +5 -6
  280. package/gs/mime/index.ts +54 -0
  281. package/gs/net/http/httptest/index.ts +25 -0
  282. package/gs/net/http/index.test.ts +20 -0
  283. package/gs/net/http/index.ts +81 -0
  284. package/gs/os/dir_unix.gs.ts +2 -3
  285. package/gs/os/types_js.gs.ts +2 -2
  286. package/gs/path/filepath/match.test.ts +31 -12
  287. package/gs/path/filepath/match.ts +178 -3
  288. package/gs/path/filepath/path.test.ts +25 -0
  289. package/gs/path/filepath/path.ts +159 -5
  290. package/gs/path/path.ts +20 -5
  291. package/gs/reflect/index.ts +1 -0
  292. package/gs/reflect/map.test.ts +19 -0
  293. package/gs/reflect/map.ts +4 -0
  294. package/gs/reflect/type.ts +197 -17
  295. package/gs/runtime/debug/index.test.ts +24 -0
  296. package/gs/runtime/debug/index.ts +8 -0
  297. package/gs/runtime/runtime.test.ts +19 -0
  298. package/gs/runtime/runtime.ts +98 -3
  299. package/gs/slices/slices.test.ts +94 -0
  300. package/gs/slices/slices.ts +245 -5
  301. package/gs/sort/meta.json +7 -0
  302. package/gs/sort/slice.gs.ts +16 -7
  303. package/gs/sort/sort.gs.ts +16 -13
  304. package/gs/strings/builder.ts +4 -3
  305. package/gs/sync/atomic/type.gs.ts +13 -14
  306. package/gs/sync/meta.json +3 -1
  307. package/gs/sync/sync.test.ts +13 -1
  308. package/gs/sync/sync.ts +27 -0
  309. package/gs/syscall/constants.ts +39 -24
  310. package/gs/syscall/errors.ts +10 -0
  311. package/gs/syscall/fs.ts +195 -0
  312. package/gs/syscall/js/index.ts +458 -0
  313. package/gs/syscall/js/meta.json +4 -0
  314. package/gs/syscall/net.test.ts +85 -0
  315. package/gs/syscall/types.ts +56 -0
  316. package/gs/testing/index.ts +1 -0
  317. package/gs/testing/meta.json +5 -0
  318. package/gs/testing/testing.test.ts +90 -0
  319. package/gs/testing/testing.ts +382 -0
  320. package/gs/time/time.test.ts +106 -0
  321. package/gs/time/time.ts +278 -57
  322. package/gs/unicode/unicode.test.ts +25 -0
  323. package/gs/unicode/unicode.ts +119 -9
  324. package/gs/unicode/utf8/utf8.test.ts +13 -0
  325. package/gs/unicode/utf8/utf8.ts +28 -16
  326. package/gs/unique/index.ts +91 -0
  327. package/package.json +2 -1
@@ -1,6 +1,21 @@
1
1
  // Package filepath implements utility routines for manipulating filename paths
2
2
  // in a way compatible with the target operating system-defined file paths.
3
3
  import * as $ from '@goscript/builtin/index.js'
4
+ import { getHostRuntime } from '@goscript/builtin/hostio.js'
5
+
6
+ type JoinElement = string | $.Slice<string>
7
+
8
+ function normalizeJoinElements(elem: JoinElement[]): string[] {
9
+ if (elem.length === 1 && typeof elem[0] !== 'string') {
10
+ const slice = elem[0]
11
+ const parts: string[] = []
12
+ for (let i = 0; i < $.len(slice); i++) {
13
+ parts.push(slice![i])
14
+ }
15
+ return parts
16
+ }
17
+ return elem as string[]
18
+ }
4
19
 
5
20
  // Path separator constants
6
21
  export const Separator = $.stringToRune('/')
@@ -123,15 +138,16 @@ export function Clean(path: string): string {
123
138
  // are ignored. The result is Cleaned. However, if the argument
124
139
  // list is empty or all its elements are empty, Join returns
125
140
  // an empty string.
126
- export function Join(...elem: string[]): string {
127
- if (elem.length === 0) {
141
+ export function Join(...elem: JoinElement[]): string {
142
+ const partsArg = normalizeJoinElements(elem)
143
+ if (partsArg.length === 0) {
128
144
  return ''
129
145
  }
130
146
 
131
147
  // Filter out empty elements but handle absolute paths
132
148
  const parts: string[] = []
133
149
 
134
- for (const e of elem) {
150
+ for (const e of partsArg) {
135
151
  if (e === '') {
136
152
  continue
137
153
  }
@@ -307,8 +323,7 @@ export function Glob(_pattern: string): [string[], $.GoError] {
307
323
  export type WalkFunc = (path: string, info: any, err: $.GoError) => $.GoError
308
324
 
309
325
  export function Walk(root: string, walkFn: WalkFunc): $.GoError {
310
- // No filesystem support, just call the function with the root
311
- return walkFn(root, null, $.newError('filesystem not supported'))
326
+ return walkHost(root, walkFn)
312
327
  }
313
328
 
314
329
  export function WalkDir(_root: string, _walkFn: any): $.GoError {
@@ -320,3 +335,142 @@ export function WalkDir(_root: string, _walkFn: any): $.GoError {
320
335
  export function Localize(path: string): [string, $.GoError] {
321
336
  return [path, null]
322
337
  }
338
+
339
+ type HostStat = {
340
+ isDirectory?: boolean | (() => boolean)
341
+ mode?: number
342
+ mtimeMs?: number
343
+ size?: number
344
+ }
345
+
346
+ type HostEntry = {
347
+ name: string
348
+ isDir: boolean
349
+ }
350
+
351
+ function hostError(err: unknown): $.GoError {
352
+ const message =
353
+ err instanceof Error ? err.message
354
+ : typeof err === 'string' ? err
355
+ : String(err)
356
+ return { Error: () => message }
357
+ }
358
+
359
+ function statIsDir(stat: HostStat): boolean {
360
+ if (typeof stat.isDirectory === 'function') {
361
+ return stat.isDirectory()
362
+ }
363
+ return !!stat.isDirectory
364
+ }
365
+
366
+ function fileInfo(path: string, stat: HostStat): any {
367
+ return {
368
+ IsDir: () => statIsDir(stat),
369
+ ModTime: () => null,
370
+ Mode: () => (stat.mode ?? 0) + (statIsDir(stat) ? 2147483648 : 0),
371
+ Name: () => Base(path),
372
+ Size: () => stat.size ?? 0,
373
+ Sys: () => stat,
374
+ }
375
+ }
376
+
377
+ function statPath(path: string): [HostStat | null, $.GoError] {
378
+ const runtime = getHostRuntime()
379
+ if (runtime.deno?.statSync) {
380
+ try {
381
+ return [runtime.deno.statSync(path), null]
382
+ } catch (err) {
383
+ return [null, hostError(err)]
384
+ }
385
+ }
386
+
387
+ const nodeFS = runtime.nodeFS
388
+ if (nodeFS?.statSync) {
389
+ try {
390
+ return [nodeFS.statSync(path), null]
391
+ } catch (err) {
392
+ return [null, hostError(err)]
393
+ }
394
+ }
395
+
396
+ return [null, $.newError('filesystem not supported')]
397
+ }
398
+
399
+ function readDir(path: string): [HostEntry[] | null, $.GoError] {
400
+ const runtime = getHostRuntime()
401
+ if (runtime.deno?.readDirSync) {
402
+ try {
403
+ const entries: HostEntry[] = []
404
+ for (const entry of runtime.deno.readDirSync(path)) {
405
+ entries.push({ name: entry.name, isDir: !!entry.isDirectory })
406
+ }
407
+ entries.sort((a, b) => a.name.localeCompare(b.name))
408
+ return [entries, null]
409
+ } catch (err) {
410
+ return [null, hostError(err)]
411
+ }
412
+ }
413
+
414
+ const nodeFS = runtime.nodeFS
415
+ if (nodeFS?.readdirSync) {
416
+ try {
417
+ const entries = nodeFS
418
+ .readdirSync(path, { withFileTypes: true })
419
+ .map((entry: any) => ({
420
+ name: String(entry.name),
421
+ isDir:
422
+ typeof entry.isDirectory === 'function' ?
423
+ entry.isDirectory()
424
+ : false,
425
+ }))
426
+ entries.sort((a, b) => a.name.localeCompare(b.name))
427
+ return [entries, null]
428
+ } catch (err) {
429
+ return [null, hostError(err)]
430
+ }
431
+ }
432
+
433
+ return [null, $.newError('filesystem not supported')]
434
+ }
435
+
436
+ function walkHost(path: string, walkFn: WalkFunc): $.GoError {
437
+ const [stat, statErr] = statPath(path)
438
+ if (statErr !== null) {
439
+ return walkFn(path, null, statErr)
440
+ }
441
+
442
+ const visitErr = walkFn(path, fileInfo(path, stat!), null)
443
+ if (visitErr === SkipAll) {
444
+ return null
445
+ }
446
+ if (visitErr !== null) {
447
+ if (visitErr === SkipDir && statIsDir(stat!)) {
448
+ return null
449
+ }
450
+ return visitErr
451
+ }
452
+ if (!statIsDir(stat!)) {
453
+ return null
454
+ }
455
+
456
+ const [entries, readErr] = readDir(path)
457
+ if (readErr !== null) {
458
+ return walkFn(path, fileInfo(path, stat!), readErr)
459
+ }
460
+ for (const entry of entries!) {
461
+ const err = walkHost(Join(path, entry.name), walkFn)
462
+ if (err === SkipDir) {
463
+ if (entry.isDir) {
464
+ continue
465
+ }
466
+ return err
467
+ }
468
+ if (err === SkipAll) {
469
+ return null
470
+ }
471
+ if (err !== null) {
472
+ return err
473
+ }
474
+ }
475
+ return null
476
+ }
package/gs/path/path.ts CHANGED
@@ -1,5 +1,19 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
2
 
3
+ type JoinElement = string | $.Slice<string>
4
+
5
+ function normalizeJoinElements(elem: JoinElement[]): string[] {
6
+ if (elem.length === 1 && typeof elem[0] !== 'string') {
7
+ const slice = elem[0]
8
+ const parts: string[] = []
9
+ for (let i = 0; i < $.len(slice); i++) {
10
+ parts.push(slice![i])
11
+ }
12
+ return parts
13
+ }
14
+ return elem as string[]
15
+ }
16
+
3
17
  class lazybuf {
4
18
  public get s(): string {
5
19
  return this._fields.s.value
@@ -245,10 +259,11 @@ export function Split(path: string): [string, string] {
245
259
  // The result is Cleaned. However, if the argument list is
246
260
  // empty or all its elements are empty, Join returns
247
261
  // an empty string.
248
- export function Join(...elem: string[]): string {
262
+ export function Join(...elem: JoinElement[]): string {
263
+ const parts = normalizeJoinElements(elem)
249
264
  let size = 0
250
- for (let _i = 0; _i < $.len(elem); _i++) {
251
- const e = elem![_i]
265
+ for (let _i = 0; _i < $.len(parts); _i++) {
266
+ const e = parts![_i]
252
267
  {
253
268
  size += $.len(e)
254
269
  }
@@ -257,8 +272,8 @@ export function Join(...elem: string[]): string {
257
272
  return ''
258
273
  }
259
274
  let buf: string[] = []
260
- for (let _i = 0; _i < $.len(elem); _i++) {
261
- const e = elem![_i]
275
+ for (let _i = 0; _i < $.len(parts); _i++) {
276
+ const e = parts![_i]
262
277
  {
263
278
  if ($.len(buf) > 0 || e != '') {
264
279
  if ($.len(buf) > 0) {
@@ -2,6 +2,7 @@
2
2
  export {
3
3
  TypeOf,
4
4
  TypeFor,
5
+ TypeAssert,
5
6
  ValueOf,
6
7
  Value,
7
8
  Kind_String,
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import { MapIter } from './map.js'
3
+ import { ValueOf } from './type.js'
3
4
 
4
5
  describe('MapIter', () => {
5
6
  it('should iterate over map entries with proper typing', () => {
@@ -29,3 +30,21 @@ describe('MapIter', () => {
29
30
  expect(iter.Value().Interface()).toBe(100)
30
31
  })
31
32
  })
33
+
34
+ describe('Value.MapKeys', () => {
35
+ it('returns map keys as reflect values', () => {
36
+ const map = new Map<string, number>()
37
+ map.set('alpha', 1)
38
+ map.set('beta', 2)
39
+
40
+ const keys = ValueOf(map).MapKeys()
41
+
42
+ expect(keys?.map((key) => key.String()).sort()).toEqual(['alpha', 'beta'])
43
+ })
44
+
45
+ it('returns an empty slice for empty maps', () => {
46
+ const emptyMap = new Map<string, number>()
47
+
48
+ expect(ValueOf(emptyMap).MapKeys()).toEqual([])
49
+ })
50
+ })
package/gs/reflect/map.ts CHANGED
@@ -78,6 +78,10 @@ class MapType implements Type {
78
78
  return 0
79
79
  }
80
80
 
81
+ public Len(): number {
82
+ throw new Error('reflect: Len of non-array type map')
83
+ }
84
+
81
85
  public Bits(): number {
82
86
  throw new Error('reflect: Bits of non-sized type map')
83
87
  }
@@ -173,6 +173,20 @@ export const String: Kind = 24
173
173
  export const Struct: Kind = 25
174
174
  export const UnsafePointer: Kind = 26
175
175
 
176
+ const pointerAddressStride = 0x100000000
177
+ const pointerAddresses = new WeakMap<object, number>()
178
+ let nextPointerAddress = 1
179
+
180
+ function pointerAddress(value: object): number {
181
+ let address = pointerAddresses.get(value)
182
+ if (address === undefined) {
183
+ address = nextPointerAddress * pointerAddressStride
184
+ nextPointerAddress++
185
+ pointerAddresses.set(value, address)
186
+ }
187
+ return address
188
+ }
189
+
176
190
  // Type is the representation of a Go type.
177
191
  export interface Type {
178
192
  // String returns a string representation of the type.
@@ -226,6 +240,10 @@ export interface Type {
226
240
  // NumMethod returns the number of methods in the type's method set
227
241
  NumMethod(): number
228
242
 
243
+ // Len returns an array type's length.
244
+ // Panics if the type's Kind is not Array.
245
+ Len(): number
246
+
229
247
  // Bits returns the size of the type in bits
230
248
  // Panics if the type's Kind is not a sized type.
231
249
  Bits(): number
@@ -272,6 +290,9 @@ class InvalidTypeClass implements Type {
272
290
  NumMethod(): number {
273
291
  return 0
274
292
  }
293
+ Len(): number {
294
+ throw new Error('reflect: Len of invalid type')
295
+ }
275
296
  Bits(): number {
276
297
  throw new Error('reflect: Bits of invalid type')
277
298
  }
@@ -508,6 +529,45 @@ export class Value {
508
529
  return this._value
509
530
  }
510
531
 
532
+ public Pointer(): number {
533
+ const kind = this.Kind()
534
+ if (
535
+ kind !== Chan &&
536
+ kind !== Func &&
537
+ kind !== Map &&
538
+ kind !== Ptr &&
539
+ kind !== Slice &&
540
+ kind !== UnsafePointer
541
+ ) {
542
+ throw new ValueError({ Kind: kind, Method: 'Pointer' })
543
+ }
544
+ if (this._value === null || this._value === undefined) {
545
+ return 0
546
+ }
547
+ if ($.isVarRef(this._value)) {
548
+ const address = this._value.__goAddress?.()
549
+ if (address !== undefined) {
550
+ return address
551
+ }
552
+ return pointerAddress(this._value)
553
+ }
554
+ if (kind === Slice) {
555
+ const slice = this._value as $.Slice<unknown> | Uint8Array
556
+ try {
557
+ if ($.len(slice) === 0) {
558
+ return 0
559
+ }
560
+ return $.indexAddress(slice, 0)
561
+ } catch {
562
+ return 0
563
+ }
564
+ }
565
+ if (typeof this._value === 'object' || typeof this._value === 'function') {
566
+ return pointerAddress(this._value)
567
+ }
568
+ return 0
569
+ }
570
+
511
571
  public pointer(): unknown {
512
572
  return this._value
513
573
  }
@@ -607,9 +667,35 @@ export class Value {
607
667
  return new Value(null, new BasicType(Invalid, 'invalid'))
608
668
  }
609
669
 
610
- public Complex(): number | { real: number; imag: number } | null {
611
- // Placeholder for complex number support
612
- return this._value as number | { real: number; imag: number } | null
670
+ public MapKeys(): $.Slice<Value> {
671
+ if (this.Kind() !== Map) {
672
+ throw new ValueError({ Kind: this.Kind(), Method: 'MapKeys' })
673
+ }
674
+ if (this._value === null || this._value === undefined) {
675
+ return $.makeSlice<Value>(0)
676
+ }
677
+ if (!(this._value instanceof globalThis.Map)) {
678
+ throw new ValueError({ Kind: this.Kind(), Method: 'MapKeys' })
679
+ }
680
+ const keyType = this.Type().Key()
681
+ const keys: Value[] = []
682
+ for (const key of this._value.keys()) {
683
+ keys.push(new Value(key as ReflectValue, keyType))
684
+ }
685
+ return $.arrayToSlice(keys)
686
+ }
687
+
688
+ public Complex(): number | $.Complex | null {
689
+ const k = this.Kind()
690
+ if (k !== Complex64 && k !== Complex128) {
691
+ throw new Error(
692
+ 'reflect: call of reflect.Value.Complex on ' +
693
+ Kind_String(k) +
694
+ ' Value',
695
+ )
696
+ }
697
+ const value = this._parentVarRef ? this._parentVarRef.value : this._value
698
+ return value as number | $.Complex | null
613
699
  }
614
700
 
615
701
  // Send sends a value to a channel
@@ -755,6 +841,28 @@ export class Value {
755
841
  }
756
842
  }
757
843
 
844
+ // SetComplex sets v's underlying value to x
845
+ public SetComplex(x: number | $.Complex): void {
846
+ if (!this.CanSet()) {
847
+ throw new Error(
848
+ 'reflect: call of reflect.Value.SetComplex on unaddressable value',
849
+ )
850
+ }
851
+ const k = this.Kind()
852
+ if (k !== Complex64 && k !== Complex128) {
853
+ throw new Error(
854
+ 'reflect: call of reflect.Value.SetComplex on ' + k + ' Value',
855
+ )
856
+ }
857
+ this._value = x
858
+ if (this._parentVarRef) {
859
+ this._parentVarRef.value = x
860
+ }
861
+ if (this._parentStruct && this._fieldName) {
862
+ this._parentStruct[this._fieldName] = x
863
+ }
864
+ }
865
+
758
866
  // SetBytes sets v's underlying value to x
759
867
  public SetBytes(x: $.Slice<number>): void {
760
868
  if (!this.CanSet()) {
@@ -1056,6 +1164,14 @@ export class BasicType implements Type {
1056
1164
  return 0
1057
1165
  }
1058
1166
 
1167
+ public Len(): number {
1168
+ throw new Error(
1169
+ 'reflect: call of reflect.Type.Len on ' +
1170
+ Kind_String(this._kind) +
1171
+ ' Type',
1172
+ )
1173
+ }
1174
+
1059
1175
  public Bits(): number {
1060
1176
  const k = this._kind
1061
1177
  switch (k) {
@@ -1075,6 +1191,10 @@ export class BasicType implements Type {
1075
1191
  case Uint64:
1076
1192
  case Float64:
1077
1193
  return 64
1194
+ case Complex64:
1195
+ return 64
1196
+ case Complex128:
1197
+ return 128
1078
1198
  case Int:
1079
1199
  case Uint:
1080
1200
  case Uintptr:
@@ -1154,6 +1274,10 @@ class SliceType implements Type {
1154
1274
  return 0
1155
1275
  }
1156
1276
 
1277
+ public Len(): number {
1278
+ throw new Error('reflect: call of reflect.Type.Len on slice Type')
1279
+ }
1280
+
1157
1281
  public Bits(): number {
1158
1282
  throw new Error('reflect: call of reflect.Type.Bits on slice Type')
1159
1283
  }
@@ -1319,6 +1443,10 @@ class PointerType implements Type {
1319
1443
  return 0
1320
1444
  }
1321
1445
 
1446
+ public Len(): number {
1447
+ throw new Error('reflect: call of reflect.Type.Len on pointer Type')
1448
+ }
1449
+
1322
1450
  public Bits(): number {
1323
1451
  throw new Error('reflect: call of reflect.Type.Bits on pointer Type')
1324
1452
  }
@@ -1395,6 +1523,10 @@ class FunctionType implements Type {
1395
1523
  return 0
1396
1524
  }
1397
1525
 
1526
+ public Len(): number {
1527
+ throw new Error('reflect: call of reflect.Type.Len on func Type')
1528
+ }
1529
+
1398
1530
  public Bits(): number {
1399
1531
  throw new Error('reflect: call of reflect.Type.Bits on func Type')
1400
1532
  }
@@ -1474,6 +1606,10 @@ class MapType implements Type {
1474
1606
  return 0
1475
1607
  }
1476
1608
 
1609
+ public Len(): number {
1610
+ throw new Error('reflect: call of reflect.Type.Len on map Type')
1611
+ }
1612
+
1477
1613
  public Bits(): number {
1478
1614
  throw new Error('reflect: call of reflect.Type.Bits on map Type')
1479
1615
  }
@@ -1632,6 +1768,10 @@ class StructType implements Type {
1632
1768
  return 0
1633
1769
  }
1634
1770
 
1771
+ public Len(): number {
1772
+ throw new Error('reflect: call of reflect.Type.Len on struct Type')
1773
+ }
1774
+
1635
1775
  public Bits(): number {
1636
1776
  throw new Error('reflect: call of reflect.Type.Bits on struct Type')
1637
1777
  }
@@ -1651,6 +1791,10 @@ class StructType implements Type {
1651
1791
  return new BasicType(Bool, 'bool', 1)
1652
1792
  case 'float64':
1653
1793
  return new BasicType(Float64, ti, 8)
1794
+ case 'complex64':
1795
+ return new BasicType(Complex64, ti, 8)
1796
+ case 'complex128':
1797
+ return new BasicType(Complex128, ti, 16)
1654
1798
  case 'uint':
1655
1799
  case 'uint32':
1656
1800
  case 'uint64':
@@ -1677,6 +1821,10 @@ class StructType implements Type {
1677
1821
  return new BasicType(Bool, 'bool', 1)
1678
1822
  case 'float64':
1679
1823
  return new BasicType(Float64, 'float64', 8)
1824
+ case 'complex64':
1825
+ return new BasicType(Complex64, 'complex64', 8)
1826
+ case 'complex128':
1827
+ return new BasicType(Complex128, 'complex128', 16)
1680
1828
  default:
1681
1829
  return new BasicType(Invalid, name, 8)
1682
1830
  }
@@ -1794,6 +1942,10 @@ class ChannelType implements Type {
1794
1942
  return 0
1795
1943
  }
1796
1944
 
1945
+ public Len(): number {
1946
+ throw new Error('reflect: call of reflect.Type.Len on chan Type')
1947
+ }
1948
+
1797
1949
  public Bits(): number {
1798
1950
  throw new Error('reflect: call of reflect.Type.Bits on chan Type')
1799
1951
  }
@@ -1827,10 +1979,7 @@ class InterfaceType implements Type {
1827
1979
  }
1828
1980
 
1829
1981
  public PkgPath?(): string {
1830
- if (
1831
- this._name === 'interface{}' ||
1832
- this._name.startsWith('interface {')
1833
- ) {
1982
+ if (this._name === 'interface{}' || this._name.startsWith('interface {')) {
1834
1983
  return ''
1835
1984
  }
1836
1985
  const dotIndex = this._name.lastIndexOf('.')
@@ -1841,10 +1990,7 @@ class InterfaceType implements Type {
1841
1990
  }
1842
1991
 
1843
1992
  public Name(): string {
1844
- if (
1845
- this._name === 'interface{}' ||
1846
- this._name.startsWith('interface {')
1847
- ) {
1993
+ if (this._name === 'interface{}' || this._name.startsWith('interface {')) {
1848
1994
  return this._name
1849
1995
  }
1850
1996
  const dotIndex = this._name.lastIndexOf('.')
@@ -1892,6 +2038,10 @@ class InterfaceType implements Type {
1892
2038
  return 0
1893
2039
  }
1894
2040
 
2041
+ public Len(): number {
2042
+ throw new Error('reflect: call of reflect.Type.Len on interface Type')
2043
+ }
2044
+
1895
2045
  public Bits(): number {
1896
2046
  throw new Error('reflect: call of reflect.Type.Bits on interface Type')
1897
2047
  }
@@ -2003,6 +2153,15 @@ function getTypeOf(value: ReflectValue): Type {
2003
2153
  return new PointerType(elemType)
2004
2154
  }
2005
2155
 
2156
+ if (
2157
+ 'real' in value &&
2158
+ 'imag' in value &&
2159
+ typeof (value as $.Complex).real === 'number' &&
2160
+ typeof (value as $.Complex).imag === 'number'
2161
+ ) {
2162
+ return new BasicType(Complex128, 'complex128', 16)
2163
+ }
2164
+
2006
2165
  // Check for arrays
2007
2166
  if (globalThis.Array.isArray(value)) {
2008
2167
  if (value.length === 0) {
@@ -2101,7 +2260,7 @@ function getTypeOf(value: ReflectValue): Type {
2101
2260
  // Check if fieldInfo is a StructFieldInfo with type and tag
2102
2261
  if (isStructFieldInfo(fieldInfo)) {
2103
2262
  return {
2104
- name,
2263
+ name: fieldInfo.name ?? name,
2105
2264
  type: StructType.createTypeFromFieldInfo(fieldInfo.type),
2106
2265
  tag: fieldInfo.tag,
2107
2266
  }
@@ -2141,6 +2300,17 @@ export function ValueOf(i: ReflectValue): Value {
2141
2300
  return new Value(i, getTypeOf(i))
2142
2301
  }
2143
2302
 
2303
+ export function TypeAssert(
2304
+ typeArgs: $.GenericTypeArgs | undefined,
2305
+ v: Value,
2306
+ ): [any, boolean] {
2307
+ const descriptor = typeArgs?.T
2308
+ if (!descriptor?.type) {
2309
+ return [v.Interface(), true]
2310
+ }
2311
+ return $.typeAssertTuple<any>(v.Interface(), descriptor.type)
2312
+ }
2313
+
2144
2314
  export function ArrayOf(length: number, elem: Type): Type {
2145
2315
  return new ArrayType(elem, length)
2146
2316
  }
@@ -2196,12 +2366,16 @@ function typeFromTypeInfo(info: $.TypeInfo | string): Type {
2196
2366
  switch (info.kind) {
2197
2367
  case $.TypeKind.Array:
2198
2368
  return new ArrayType(
2199
- typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2369
+ typeFromTypeInfo(
2370
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2371
+ ),
2200
2372
  info.length,
2201
2373
  )
2202
2374
  case $.TypeKind.Channel:
2203
2375
  return new ChannelType(
2204
- typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2376
+ typeFromTypeInfo(
2377
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2378
+ ),
2205
2379
  chanDirFromTypeInfo(info.direction),
2206
2380
  )
2207
2381
  case $.TypeKind.Function:
@@ -2210,12 +2384,18 @@ function typeFromTypeInfo(info: $.TypeInfo | string): Type {
2210
2384
  return interfaceTypeFromInfo(info)
2211
2385
  case $.TypeKind.Map:
2212
2386
  return new MapType(
2213
- typeFromTypeInfo(info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2214
- typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2387
+ typeFromTypeInfo(
2388
+ info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2389
+ ),
2390
+ typeFromTypeInfo(
2391
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2392
+ ),
2215
2393
  )
2216
2394
  case $.TypeKind.Pointer:
2217
2395
  return new PointerType(
2218
- typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2396
+ typeFromTypeInfo(
2397
+ info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' },
2398
+ ),
2219
2399
  )
2220
2400
  default:
2221
2401
  return StructType.createTypeFromFieldInfo(info)
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ import { PrintStack, Stack } from './index.js'
4
+
5
+ describe('runtime/debug override', () => {
6
+ it('returns a stack trace as bytes', () => {
7
+ const stack = Stack()
8
+
9
+ expect(stack).toBeInstanceOf(Uint8Array)
10
+ expect(new TextDecoder().decode(stack)).toContain('Error')
11
+ })
12
+
13
+ it('prints the current stack trace', () => {
14
+ const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
15
+
16
+ try {
17
+ PrintStack()
18
+ expect(consoleError).toHaveBeenCalledTimes(1)
19
+ expect(consoleError.mock.calls[0][0]).toContain('Error')
20
+ } finally {
21
+ consoleError.mockRestore()
22
+ }
23
+ })
24
+ })
@@ -0,0 +1,8 @@
1
+ export function Stack(): Uint8Array {
2
+ const stack = new Error().stack ?? 'stack trace unavailable'
3
+ return new TextEncoder().encode(stack)
4
+ }
5
+
6
+ export function PrintStack(): void {
7
+ console.error(new TextDecoder().decode(Stack()))
8
+ }