goscript 0.0.83 → 0.1.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 (197) hide show
  1. package/README.md +13 -1
  2. package/cmd/goscript/cmd_compile.go +70 -69
  3. package/cmd/goscript/cmd_compile_test.go +79 -0
  4. package/cmd/goscript/main.go +10 -5
  5. package/compiler/compile-request.go +218 -0
  6. package/compiler/compiler.go +16 -1336
  7. package/compiler/compliance_test.go +196 -0
  8. package/compiler/config.go +6 -13
  9. package/compiler/diagnostic.go +70 -0
  10. package/compiler/index.test.ts +28 -28
  11. package/compiler/index.ts +40 -72
  12. package/compiler/lowered-program.go +132 -0
  13. package/compiler/lowering.go +3576 -0
  14. package/compiler/override-registry.go +422 -0
  15. package/compiler/override-registry_test.go +207 -0
  16. package/compiler/package-graph.go +231 -0
  17. package/compiler/package-graph_test.go +281 -0
  18. package/compiler/result.go +13 -0
  19. package/compiler/runtime-contract.go +279 -0
  20. package/compiler/runtime-contract_test.go +90 -0
  21. package/compiler/semantic-model-types.go +110 -0
  22. package/compiler/semantic-model.go +922 -0
  23. package/compiler/semantic-model_test.go +416 -0
  24. package/compiler/service.go +133 -0
  25. package/compiler/skeleton_test.go +1145 -0
  26. package/compiler/typescript-emitter.go +663 -0
  27. package/compiler/wasm/compile.go +2 -3
  28. package/compiler/wasm/compile_test.go +29 -0
  29. package/compiler/wasm_api.go +10 -159
  30. package/dist/compiler/index.d.ts +1 -3
  31. package/dist/compiler/index.js +31 -55
  32. package/dist/compiler/index.js.map +1 -1
  33. package/dist/gs/builtin/builtin.d.ts +13 -0
  34. package/dist/gs/builtin/builtin.js +27 -7
  35. package/dist/gs/builtin/builtin.js.map +1 -1
  36. package/dist/gs/builtin/channel.d.ts +3 -3
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/hostio.d.ts +86 -0
  39. package/dist/gs/builtin/hostio.js +266 -0
  40. package/dist/gs/builtin/hostio.js.map +1 -0
  41. package/dist/gs/builtin/index.d.ts +1 -0
  42. package/dist/gs/builtin/index.js +1 -0
  43. package/dist/gs/builtin/index.js.map +1 -1
  44. package/dist/gs/builtin/print.d.ts +8 -0
  45. package/dist/gs/builtin/print.js +111 -0
  46. package/dist/gs/builtin/print.js.map +1 -0
  47. package/dist/gs/builtin/slice.d.ts +1 -1
  48. package/dist/gs/builtin/slice.js.map +1 -1
  49. package/dist/gs/builtin/type.d.ts +11 -0
  50. package/dist/gs/builtin/type.js +55 -1
  51. package/dist/gs/builtin/type.js.map +1 -1
  52. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  53. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  54. package/dist/gs/bytes/reader.gs.js.map +1 -1
  55. package/dist/gs/context/context.js.map +1 -1
  56. package/dist/gs/crypto/rand/index.d.ts +5 -0
  57. package/dist/gs/crypto/rand/index.js +77 -0
  58. package/dist/gs/crypto/rand/index.js.map +1 -0
  59. package/dist/gs/encoding/json/index.d.ts +3 -0
  60. package/dist/gs/encoding/json/index.js +160 -0
  61. package/dist/gs/encoding/json/index.js.map +1 -0
  62. package/dist/gs/fmt/fmt.js +2 -22
  63. package/dist/gs/fmt/fmt.js.map +1 -1
  64. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
  65. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
  66. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  67. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  68. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  69. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  70. package/dist/gs/go/scanner/index.d.ts +29 -0
  71. package/dist/gs/go/scanner/index.js +120 -0
  72. package/dist/gs/go/scanner/index.js.map +1 -0
  73. package/dist/gs/go/token/index.d.ts +31 -0
  74. package/dist/gs/go/token/index.js +82 -0
  75. package/dist/gs/go/token/index.js.map +1 -0
  76. package/dist/gs/internal/abi/index.js.map +1 -1
  77. package/dist/gs/io/fs/fs.js.map +1 -1
  78. package/dist/gs/io/fs/readdir.js.map +1 -1
  79. package/dist/gs/io/fs/readfile.js.map +1 -1
  80. package/dist/gs/io/fs/stat.js.map +1 -1
  81. package/dist/gs/io/fs/sub.js.map +1 -1
  82. package/dist/gs/io/io.js.map +1 -1
  83. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  84. package/dist/gs/os/error.gs.js +2 -4
  85. package/dist/gs/os/error.gs.js.map +1 -1
  86. package/dist/gs/os/exec.gs.js.map +1 -1
  87. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  88. package/dist/gs/os/rawconn_js.gs.js.map +1 -1
  89. package/dist/gs/os/root_js.gs.js.map +1 -1
  90. package/dist/gs/os/tempfile.gs.js +66 -9
  91. package/dist/gs/os/tempfile.gs.js.map +1 -1
  92. package/dist/gs/os/types.gs.js.map +1 -1
  93. package/dist/gs/os/types_js.gs.d.ts +2 -51
  94. package/dist/gs/os/types_js.gs.js +67 -105
  95. package/dist/gs/os/types_js.gs.js.map +1 -1
  96. package/dist/gs/os/types_unix.gs.js.map +1 -1
  97. package/dist/gs/path/filepath/match.js.map +1 -1
  98. package/dist/gs/path/match.js.map +1 -1
  99. package/dist/gs/path/path.js.map +1 -1
  100. package/dist/gs/reflect/index.d.ts +2 -2
  101. package/dist/gs/reflect/index.js +1 -1
  102. package/dist/gs/reflect/index.js.map +1 -1
  103. package/dist/gs/reflect/map.js.map +1 -1
  104. package/dist/gs/reflect/type.d.ts +2 -1
  105. package/dist/gs/reflect/type.js +85 -14
  106. package/dist/gs/reflect/type.js.map +1 -1
  107. package/dist/gs/reflect/types.js.map +1 -1
  108. package/dist/gs/reflect/visiblefields.js.map +1 -1
  109. package/dist/gs/runtime/runtime.js.map +1 -1
  110. package/dist/gs/sort/sort.gs.js.map +1 -1
  111. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  112. package/dist/gs/strconv/quote.gs.js.map +1 -1
  113. package/dist/gs/strings/builder.js.map +1 -1
  114. package/dist/gs/strings/reader.js.map +1 -1
  115. package/dist/gs/strings/replace.js.map +1 -1
  116. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  117. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  118. package/dist/gs/sync/sync.d.ts +1 -0
  119. package/dist/gs/sync/sync.js +12 -0
  120. package/dist/gs/sync/sync.js.map +1 -1
  121. package/dist/gs/time/time.js.map +1 -1
  122. package/dist/gs/unicode/unicode.js.map +1 -1
  123. package/go.mod +2 -2
  124. package/gs/builtin/builtin.ts +31 -6
  125. package/gs/builtin/hostio.test.ts +246 -0
  126. package/gs/builtin/hostio.ts +413 -0
  127. package/gs/builtin/index.ts +1 -0
  128. package/gs/builtin/print.test.ts +48 -0
  129. package/gs/builtin/print.ts +154 -0
  130. package/gs/builtin/runtime-contract.test.ts +230 -0
  131. package/gs/builtin/type.ts +84 -1
  132. package/gs/crypto/rand/index.test.ts +32 -0
  133. package/gs/crypto/rand/index.ts +90 -0
  134. package/gs/crypto/rand/meta.json +5 -0
  135. package/gs/encoding/json/index.test.ts +65 -0
  136. package/gs/encoding/json/index.ts +186 -0
  137. package/gs/fmt/fmt.test.ts +41 -30
  138. package/gs/fmt/fmt.ts +2 -22
  139. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
  140. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
  141. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
  142. package/gs/go/scanner/index.test.ts +50 -0
  143. package/gs/go/scanner/index.ts +157 -0
  144. package/gs/go/token/index.test.ts +21 -0
  145. package/gs/go/token/index.ts +120 -0
  146. package/gs/os/file_unix_js.test.ts +103 -0
  147. package/gs/os/meta.json +1 -2
  148. package/gs/os/tempfile.gs.test.ts +85 -0
  149. package/gs/os/tempfile.gs.ts +71 -11
  150. package/gs/os/types_js.gs.ts +74 -153
  151. package/gs/reflect/index.ts +1 -1
  152. package/gs/reflect/type.ts +106 -17
  153. package/gs/reflect/typefor.test.ts +75 -0
  154. package/gs/sync/sync.test.ts +24 -0
  155. package/gs/sync/sync.ts +12 -0
  156. package/package.json +13 -13
  157. package/compiler/analysis.go +0 -3475
  158. package/compiler/analysis_test.go +0 -338
  159. package/compiler/assignment.go +0 -580
  160. package/compiler/builtin_test.go +0 -92
  161. package/compiler/code-writer.go +0 -115
  162. package/compiler/compiler_test.go +0 -149
  163. package/compiler/composite-lit.go +0 -779
  164. package/compiler/config_test.go +0 -62
  165. package/compiler/constraint.go +0 -86
  166. package/compiler/decl.go +0 -801
  167. package/compiler/expr-call-async.go +0 -188
  168. package/compiler/expr-call-builtins.go +0 -208
  169. package/compiler/expr-call-helpers.go +0 -382
  170. package/compiler/expr-call-make.go +0 -318
  171. package/compiler/expr-call-type-conversion.go +0 -520
  172. package/compiler/expr-call.go +0 -413
  173. package/compiler/expr-selector.go +0 -343
  174. package/compiler/expr-star.go +0 -82
  175. package/compiler/expr-type.go +0 -442
  176. package/compiler/expr-value.go +0 -89
  177. package/compiler/expr.go +0 -773
  178. package/compiler/field.go +0 -183
  179. package/compiler/gs_dependencies_test.go +0 -298
  180. package/compiler/lit.go +0 -322
  181. package/compiler/output.go +0 -72
  182. package/compiler/primitive.go +0 -149
  183. package/compiler/protobuf.go +0 -697
  184. package/compiler/sanitize.go +0 -100
  185. package/compiler/spec-struct.go +0 -995
  186. package/compiler/spec-value.go +0 -540
  187. package/compiler/spec.go +0 -725
  188. package/compiler/stmt-assign.go +0 -664
  189. package/compiler/stmt-for.go +0 -266
  190. package/compiler/stmt-range.go +0 -475
  191. package/compiler/stmt-select.go +0 -262
  192. package/compiler/stmt-type-switch.go +0 -147
  193. package/compiler/stmt.go +0 -1308
  194. package/compiler/type-assert.go +0 -386
  195. package/compiler/type-info.go +0 -156
  196. package/compiler/type-utils.go +0 -207
  197. package/compiler/type.go +0 -892
@@ -0,0 +1,85 @@
1
+ import { basename, join } from 'node:path'
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { tmpdir } from 'node:os'
4
+ import { afterEach, describe, expect, it, vi } from 'vitest'
5
+
6
+ import { ErrUnimplemented } from './error.gs.js'
7
+ import { CreateTemp, MkdirTemp } from './tempfile.gs.js'
8
+
9
+ const tempRoots: string[] = []
10
+
11
+ afterEach(() => {
12
+ vi.restoreAllMocks()
13
+ vi.unstubAllGlobals()
14
+ for (const root of tempRoots.splice(0)) {
15
+ rmSync(root, { force: true, recursive: true })
16
+ }
17
+ })
18
+
19
+ function makeTempRoot(): string {
20
+ const root = mkdtempSync(join(tmpdir(), 'goscript-os-temp-'))
21
+ tempRoots.push(root)
22
+ return root
23
+ }
24
+
25
+ function stubRandomBytes(bytes: number[]): void {
26
+ vi.stubGlobal('crypto', {
27
+ getRandomValues: vi.fn((dst: Uint8Array) => {
28
+ for (let i = 0; i < dst.length; i++) {
29
+ dst[i] = bytes[i] ?? 0
30
+ }
31
+ return dst
32
+ }),
33
+ })
34
+ }
35
+
36
+ function forbidMathRandom(): void {
37
+ vi.spyOn(Math, 'random').mockImplementation(() => {
38
+ throw new Error('os temp names must not use Math.random')
39
+ })
40
+ }
41
+
42
+ describe('os temp files', () => {
43
+ it('uses Web Crypto bytes for temp names', () => {
44
+ const root = makeTempRoot()
45
+ stubRandomBytes([0x78, 0x56, 0x34, 0x12])
46
+ forbidMathRandom()
47
+
48
+ const [dir, dirErr] = MkdirTemp(root, 'dir-*.tmp')
49
+ expect(dirErr).toBeNull()
50
+ expect(basename(dir)).toBe('dir-305419896.tmp')
51
+ expect(existsSync(dir)).toBe(true)
52
+
53
+ const [file, fileErr] = CreateTemp(root, 'file-*.tmp')
54
+ expect(fileErr).toBeNull()
55
+ expect(file).not.toBeNull()
56
+ expect(basename(file!.Name())).toBe('file-305419896.tmp')
57
+ expect(existsSync(file!.Name())).toBe(true)
58
+ file!.Close()
59
+ })
60
+
61
+ it('does not truncate an existing path after a random collision', () => {
62
+ const root = makeTempRoot()
63
+ const existing = join(root, 'file-305419896.tmp')
64
+ writeFileSync(existing, 'keep')
65
+ stubRandomBytes([0x78, 0x56, 0x34, 0x12])
66
+ forbidMathRandom()
67
+
68
+ const [file, err] = CreateTemp(root, 'file-*.tmp')
69
+
70
+ expect(file).toBeNull()
71
+ expect(err).not.toBeNull()
72
+ expect(readFileSync(existing, 'utf8')).toBe('keep')
73
+ })
74
+
75
+ it('reports ErrUnimplemented without a secure random source', () => {
76
+ const root = makeTempRoot()
77
+ vi.stubGlobal('crypto', {})
78
+ forbidMathRandom()
79
+
80
+ const [dir, err] = MkdirTemp(root, 'dir-*')
81
+
82
+ expect(dir).toBe('')
83
+ expect(err).toBe(ErrUnimplemented)
84
+ })
85
+ })
@@ -1,8 +1,8 @@
1
1
  import * as $ from "@goscript/builtin/index.js";
2
2
  import { ErrUnimplemented } from "./error.gs.js";
3
3
  import { TempDir } from "./file_constants_js.gs.js";
4
- import { Create, Mkdir } from "./file_js.gs.js";
5
- import { File } from "./types_js.gs.js";
4
+ import { Mkdir } from "./file_js.gs.js";
5
+ import { createHostFile, File, getDeno, getNodeFS, newHostError } from "./types_js.gs.js";
6
6
 
7
7
  export function joinPath(dir: string, file: string): string {
8
8
  if (dir === "" || dir === ".") {
@@ -20,33 +20,93 @@ export function joinPath(dir: string, file: string): string {
20
20
  return dir + "/" + file
21
21
  }
22
22
 
23
- function nextTempPath(dir: string, pattern: string): string {
23
+ function nextTempPath(dir: string, pattern: string): [string, $.GoError] {
24
24
  const baseDir = dir === "" ? TempDir() : dir
25
- const suffix = Math.random().toString(36).slice(2, 10) + Date.now().toString(36)
26
- const name = pattern.includes("*") ? pattern.replace("*", suffix) : pattern + suffix
27
- return joinPath(baseDir, name)
25
+ const [suffix, err] = nextRandom()
26
+ if (err !== null) {
27
+ return ["", err]
28
+ }
29
+ const star = pattern.lastIndexOf("*")
30
+ const name =
31
+ star >= 0
32
+ ? pattern.slice(0, star) + suffix + pattern.slice(star + 1)
33
+ : pattern + suffix
34
+ return [joinPath(baseDir, name), null]
35
+ }
36
+
37
+ function nextRandom(): [string, $.GoError] {
38
+ const crypto = globalThis.crypto
39
+ if (!crypto || typeof crypto.getRandomValues !== "function") {
40
+ return ["", ErrUnimplemented]
41
+ }
42
+ const bytes = new Uint8Array(4)
43
+ crypto.getRandomValues(bytes)
44
+ const value =
45
+ bytes[0] |
46
+ (bytes[1] << 8) |
47
+ (bytes[2] << 16) |
48
+ (bytes[3] << 24)
49
+ return [(value >>> 0).toString(10), null]
50
+ }
51
+
52
+ function createTempFile(path: string): [File | null, $.GoError] {
53
+ const denoObj = getDeno()
54
+ if (denoObj?.openSync) {
55
+ try {
56
+ const handle = denoObj.openSync(path, {
57
+ createNew: true,
58
+ mode: 0o600,
59
+ read: true,
60
+ write: true,
61
+ })
62
+ return [createHostFile(path, handle?.rid ?? -1, handle), null]
63
+ } catch (err) {
64
+ return [null, newHostError(err)]
65
+ }
66
+ }
67
+
68
+ const nodeFS = getNodeFS()
69
+ if (nodeFS?.openSync) {
70
+ try {
71
+ return [createHostFile(path, nodeFS.openSync(path, "wx+", 0o600)), null]
72
+ } catch (err) {
73
+ return [null, newHostError(err)]
74
+ }
75
+ }
76
+
77
+ return [null, ErrUnimplemented]
28
78
  }
29
79
 
30
80
  export function CreateTemp(dir: string, pattern: string): [File | null, $.GoError] {
31
81
  const template = pattern === "" ? "tmp-*" : pattern
82
+ let lastErr: $.GoError = ErrUnimplemented
32
83
  for (let i = 0; i < 16; i++) {
33
- const path = nextTempPath(dir, template)
34
- const [file, err] = Create(path)
84
+ const [path, randErr] = nextTempPath(dir, template)
85
+ if (randErr !== null) {
86
+ return [null, randErr]
87
+ }
88
+ const [file, err] = createTempFile(path)
35
89
  if (err === null) {
36
90
  return [file, null]
37
91
  }
92
+ lastErr = err
38
93
  }
39
- return [null, ErrUnimplemented]
94
+ return [null, lastErr]
40
95
  }
41
96
 
42
97
  export function MkdirTemp(dir: string, pattern: string): [string, $.GoError] {
43
98
  const template = pattern === "" ? "tmp-*" : pattern
99
+ let lastErr: $.GoError = ErrUnimplemented
44
100
  for (let i = 0; i < 16; i++) {
45
- const path = nextTempPath(dir, template)
101
+ const [path, randErr] = nextTempPath(dir, template)
102
+ if (randErr !== null) {
103
+ return ["", randErr]
104
+ }
46
105
  const err = Mkdir(path, 0o700)
47
106
  if (err === null) {
48
107
  return [path, null]
49
108
  }
109
+ lastErr = err
50
110
  }
51
- return ["", ErrUnimplemented]
111
+ return ["", lastErr]
52
112
  }
@@ -5,50 +5,16 @@ import * as fs from "@goscript/io/fs/index.js"
5
5
  import * as io from "@goscript/io/index.js"
6
6
  import * as time from "@goscript/time/index.js"
7
7
  import * as syscall from "@goscript/syscall/index.js"
8
+ import {
9
+ DenoFileLike,
10
+ DenoStream,
11
+ getHostRuntime,
12
+ HostUnsupportedError,
13
+ NodeFSModule,
14
+ resetHostRuntimeForTests,
15
+ } from "@goscript/builtin/hostio.js"
8
16
  import { newRawConn } from "./rawconn_js.gs.js"
9
17
 
10
- export type NodeFSModule = {
11
- readSync(fd: number, buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number
12
- writeSync(fd: number, buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number
13
- closeSync?(fd: number): void
14
- fstatSync?(fd: number): HostStatLike
15
- fsyncSync?(fd: number): void
16
- ftruncateSync?(fd: number, len?: number): void
17
- openSync?(path: string, flags: number | string, mode?: number): number
18
- chmodSync?(path: string, mode: number): void
19
- chownSync?(path: string, uid: number, gid: number): void
20
- lchownSync?(path: string, uid: number, gid: number): void
21
- linkSync?(existingPath: string, newPath: string): void
22
- lstatSync?(path: string): HostStatLike
23
- mkdirSync?(path: string, options?: number | { mode?: number, recursive?: boolean }): void
24
- readFileSync?(path: string): Uint8Array
25
- readdirSync?(path: string, options?: { withFileTypes?: boolean }): any[]
26
- readlinkSync?(path: string): string
27
- renameSync?(oldPath: string, newPath: string): void
28
- rmSync?(path: string, options?: { force?: boolean, recursive?: boolean }): void
29
- rmdirSync?(path: string): void
30
- statSync?(path: string): HostStatLike
31
- symlinkSync?(target: string, path: string): void
32
- truncateSync?(path: string, len?: number): void
33
- unlinkSync?(path: string): void
34
- utimesSync?(path: string, atime: Date | number, mtime: Date | number): void
35
- writeFileSync?(path: string, data: Uint8Array, options?: { mode?: number }): void
36
- }
37
-
38
- export type DenoStream = {
39
- readSync?(buffer: Uint8Array): number | null
40
- writeSync?(buffer: Uint8Array): number
41
- }
42
-
43
- export type DenoFileLike = DenoStream & {
44
- close?(): void
45
- rid?: number
46
- seekSync?(offset: number, whence: number): number
47
- syncSync?(): void
48
- statSync?(): HostStatLike
49
- truncateSync?(len?: number): void
50
- }
51
-
52
18
  export type HostStatLike = {
53
19
  isDirectory(): boolean
54
20
  isSymbolicLink?(): boolean
@@ -66,90 +32,24 @@ export function newHostError(err: unknown): $.GoError {
66
32
  return { Error: () => message }
67
33
  }
68
34
 
69
- export function getDynamicRequire(): ((specifier: string) => unknown) | null {
70
- try {
71
- return Function(
72
- "return typeof require !== 'undefined' ? require : null",
73
- )() as ((specifier: string) => unknown) | null
74
- } catch {
75
- return null
76
- }
77
- }
78
-
79
35
  export function getNodeFS(): NodeFSModule | null {
80
- const processObj = (globalThis as any).process
81
- if (processObj && typeof processObj.getBuiltinModule === "function") {
82
- const module = processObj.getBuiltinModule("fs")
83
- if (module && typeof module.readSync === "function" && typeof module.writeSync === "function") {
84
- return module as NodeFSModule
85
- }
86
- }
87
-
88
- const requireFn = getDynamicRequire()
89
- if (requireFn) {
90
- for (const specifier of ["node:fs", "fs"]) {
91
- try {
92
- const module = requireFn(specifier) as NodeFSModule | null
93
- if (module && typeof module.readSync === "function" && typeof module.writeSync === "function") {
94
- return module
95
- }
96
- } catch {
97
- // Try the next fallback.
98
- }
99
- }
100
- }
101
-
102
- return null
36
+ return getHostRuntime().nodeFS
103
37
  }
104
38
 
105
39
  export function getDeno(): any | null {
106
- return (globalThis as any).Deno ?? null
40
+ return getHostRuntime().deno
107
41
  }
108
42
 
109
43
  export function getPlatform(): string {
110
- const denoObj = getDeno()
111
- if (denoObj?.build?.os) {
112
- return denoObj.build.os
113
- }
114
-
115
- const processObj = (globalThis as any).process
116
- if (processObj?.platform) {
117
- return processObj.platform
118
- }
119
-
120
- return "unknown"
44
+ return getHostRuntime().platform
121
45
  }
122
46
 
123
47
  export function getEnv(name: string): string {
124
- const denoObj = getDeno()
125
- if (denoObj?.env?.get) {
126
- try {
127
- return denoObj.env.get(name) ?? ""
128
- } catch {
129
- return ""
130
- }
131
- }
132
-
133
- const processObj = (globalThis as any).process
134
- return processObj?.env?.[name] ?? ""
48
+ return getHostRuntime().getEnv(name)
135
49
  }
136
50
 
137
51
  export function getDenoStream(fd: number): DenoStream | null {
138
- const denoObj = getDeno()
139
- if (!denoObj) {
140
- return null
141
- }
142
-
143
- switch (fd) {
144
- case 0:
145
- return denoObj.stdin ?? null
146
- case 1:
147
- return denoObj.stdout ?? null
148
- case 2:
149
- return denoObj.stderr ?? null
150
- default:
151
- return null
152
- }
52
+ return getHostRuntime().getStdioHandle(fd)
153
53
  }
154
54
 
155
55
  function readFD(fd: number, b: Uint8Array): [number, $.GoError] {
@@ -157,33 +57,18 @@ function readFD(fd: number, b: Uint8Array): [number, $.GoError] {
157
57
  return [0, null]
158
58
  }
159
59
 
160
- const denoStream = getDenoStream(fd)
161
- if (denoStream && typeof denoStream.readSync === "function") {
162
- try {
163
- const n = denoStream.readSync(b)
164
- if (n === null || n === 0) {
165
- return [0, io.EOF]
166
- }
167
- return [n, null]
168
- } catch (err) {
169
- return [0, newHostError(err)]
60
+ try {
61
+ const n = getHostRuntime().readFD(fd, b)
62
+ if (n === null || n === 0) {
63
+ return [0, io.EOF]
170
64
  }
171
- }
172
-
173
- const nodeFS = getNodeFS()
174
- if (nodeFS) {
175
- try {
176
- const n = nodeFS.readSync(fd, b, 0, b.length, null)
177
- if (n === 0) {
178
- return [0, io.EOF]
179
- }
180
- return [n, null]
181
- } catch (err) {
182
- return [0, newHostError(err)]
65
+ return [n, null]
66
+ } catch (err) {
67
+ if (err instanceof HostUnsupportedError) {
68
+ return [0, ErrUnimplemented]
183
69
  }
70
+ return [0, newHostError(err)]
184
71
  }
185
-
186
- return [0, ErrUnimplemented]
187
72
  }
188
73
 
189
74
  function writeFD(fd: number, b: Uint8Array): [number, $.GoError] {
@@ -191,25 +76,51 @@ function writeFD(fd: number, b: Uint8Array): [number, $.GoError] {
191
76
  return [0, null]
192
77
  }
193
78
 
194
- const denoStream = getDenoStream(fd)
195
- if (denoStream && typeof denoStream.writeSync === "function") {
196
- try {
197
- return [denoStream.writeSync(b), null]
198
- } catch (err) {
199
- return [0, newHostError(err)]
79
+ try {
80
+ return [getHostRuntime().writeFD(fd, b), null]
81
+ } catch (err) {
82
+ if (err instanceof HostUnsupportedError) {
83
+ return [0, ErrUnimplemented]
200
84
  }
85
+ return [0, newHostError(err)]
201
86
  }
87
+ }
202
88
 
203
- const nodeFS = getNodeFS()
204
- if (nodeFS) {
205
- try {
206
- return [nodeFS.writeSync(fd, b, 0, b.length, null), null]
207
- } catch (err) {
208
- return [0, newHostError(err)]
89
+ function readHandle(handle: DenoFileLike, b: Uint8Array): [number, $.GoError] {
90
+ if (typeof handle.readSync !== "function") {
91
+ return [0, ErrUnimplemented]
92
+ }
93
+ try {
94
+ const n = handle.readSync(b)
95
+ if (n === null || n === 0) {
96
+ return [0, io.EOF]
209
97
  }
98
+ return [n, null]
99
+ } catch (err) {
100
+ return [0, newHostError(err)]
210
101
  }
102
+ }
211
103
 
212
- return [0, ErrUnimplemented]
104
+ function writeHandle(handle: DenoFileLike, b: Uint8Array): [number, $.GoError] {
105
+ if (typeof handle.writeSync !== "function") {
106
+ return [0, ErrUnimplemented]
107
+ }
108
+ try {
109
+ let offset = 0
110
+ while (offset < b.length) {
111
+ const n = handle.writeSync(b.subarray(offset))
112
+ if (!Number.isFinite(n) || n < 0) {
113
+ throw new Error(`invalid write result: ${n}`)
114
+ }
115
+ if (n === 0) {
116
+ throw new Error("short write")
117
+ }
118
+ offset += n
119
+ }
120
+ return [b.length, null]
121
+ } catch (err) {
122
+ return [0, newHostError(err)]
123
+ }
213
124
  }
214
125
 
215
126
  class hostFileInfo {
@@ -281,11 +192,13 @@ export function createFileInfo(name: string, stat: HostStatLike): fs.FileInfo {
281
192
  export function createHostFile(name: string, fd: number = -1, handle: DenoFileLike | null = null): File {
282
193
  return new File({
283
194
  fd,
284
- file: new file({ handle, path: name }),
195
+ file: new file({ handle: handle ?? getHostRuntime().getStdioHandle(fd), path: name }),
285
196
  name,
286
197
  })
287
198
  }
288
199
 
200
+ export { resetHostRuntimeForTests }
201
+
289
202
  // Re-export essential types
290
203
  export type Time = time.Time;
291
204
  export type FileInfo = fs.FileInfo;
@@ -371,7 +284,11 @@ export class File {
371
284
  return [0, null]
372
285
  }
373
286
  const buf = $.bytesToUint8Array(b)
374
- const [n, err] = readFD(this.fd, buf)
287
+ const handle = this.file?.handle
288
+ const [n, err] =
289
+ handle && typeof handle.readSync === "function"
290
+ ? readHandle(handle, buf)
291
+ : readFD(this.fd, buf)
375
292
  if (!(b instanceof Uint8Array) && n > 0) {
376
293
  $.copy(b, buf.subarray(0, n))
377
294
  }
@@ -408,7 +325,11 @@ export class File {
408
325
  if (b === null) {
409
326
  return [0, null]
410
327
  }
411
- return writeFD(this.fd, $.bytesToUint8Array(b))
328
+ const buf = $.bytesToUint8Array(b)
329
+ const handle = this.file?.handle
330
+ return handle && typeof handle.writeSync === "function"
331
+ ? writeHandle(handle, buf)
332
+ : writeFD(this.fd, buf)
412
333
  }
413
334
 
414
335
  public WriteAt(b: $.Bytes, off: number): [number, $.GoError] {
@@ -47,7 +47,6 @@ export {
47
47
  } from './types.js'
48
48
  export type {
49
49
  uintptr,
50
- Pointer,
51
50
  Method,
52
51
  SelectDir,
53
52
  SliceHeader,
@@ -80,6 +79,7 @@ export {
80
79
  Interface,
81
80
  Map,
82
81
  Ptr,
82
+ Pointer,
83
83
  Slice,
84
84
  String,
85
85
  Struct,
@@ -167,6 +167,7 @@ export const Func: Kind = 19
167
167
  export const Interface: Kind = 20
168
168
  export const Map: Kind = 21
169
169
  export const Ptr: Kind = 22
170
+ export const Pointer: Kind = Ptr
170
171
  export const Slice: Kind = 23
171
172
  export const String: Kind = 24
172
173
  export const Struct: Kind = 25
@@ -1945,22 +1946,7 @@ function getTypeOf(value: ReflectValue): Type {
1945
1946
  typeInfo.params &&
1946
1947
  typeInfo.results
1947
1948
  ) {
1948
- // Build proper function signature from type info
1949
- const paramTypes = typeInfo.params
1950
- .map((p: any) => (typeof p === 'string' ? p : p.name || 'any'))
1951
- .join(', ')
1952
- const resultTypes = typeInfo.results.map((r: any) =>
1953
- typeof r === 'string' ? r : r.name || 'any',
1954
- )
1955
-
1956
- let signature = `func(${paramTypes})`
1957
- if (resultTypes.length === 1) {
1958
- signature += ` ${resultTypes[0]}`
1959
- } else if (resultTypes.length > 1) {
1960
- signature += ` (${resultTypes.join(', ')})`
1961
- }
1962
-
1963
- return new FunctionType(signature)
1949
+ return functionTypeFromInfo(typeInfo)
1964
1950
  }
1965
1951
  }
1966
1952
 
@@ -2180,10 +2166,113 @@ export function ChanOf(dir: ChanDir, t: Type): Type {
2180
2166
  return new ChannelType(t, dir)
2181
2167
  }
2182
2168
 
2183
- export function TypeFor(): Type {
2169
+ export function TypeFor(typeArgs?: $.GenericTypeArgs): Type {
2170
+ const descriptor = typeArgs?.T
2171
+ if (descriptor?.type) {
2172
+ return typeFromTypeInfo(descriptor.type)
2173
+ }
2174
+ if (descriptor?.methods) {
2175
+ const methods = Object.keys(descriptor.methods)
2176
+ if (methods.length !== 0) {
2177
+ return new InterfaceType(
2178
+ `interface { ${methods.map((method) => method + '()').join('; ')} }`,
2179
+ )
2180
+ }
2181
+ }
2182
+ if (descriptor?.zero) {
2183
+ return getTypeOf(descriptor.zero())
2184
+ }
2184
2185
  return new InterfaceType('interface{}')
2185
2186
  }
2186
2187
 
2188
+ function typeFromTypeInfo(info: $.TypeInfo | string): Type {
2189
+ if (typeof info === 'string') {
2190
+ const registered = builtinGetTypeByName(info)
2191
+ if (registered) {
2192
+ return typeFromTypeInfo(registered)
2193
+ }
2194
+ return StructType.createTypeFromFieldInfo(info)
2195
+ }
2196
+ switch (info.kind) {
2197
+ case $.TypeKind.Array:
2198
+ return new ArrayType(
2199
+ typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2200
+ info.length,
2201
+ )
2202
+ case $.TypeKind.Channel:
2203
+ return new ChannelType(
2204
+ typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2205
+ chanDirFromTypeInfo(info.direction),
2206
+ )
2207
+ case $.TypeKind.Function:
2208
+ return functionTypeFromInfo(info)
2209
+ case $.TypeKind.Interface:
2210
+ return interfaceTypeFromInfo(info)
2211
+ case $.TypeKind.Map:
2212
+ return new MapType(
2213
+ typeFromTypeInfo(info.keyType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2214
+ typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2215
+ )
2216
+ case $.TypeKind.Pointer:
2217
+ return new PointerType(
2218
+ typeFromTypeInfo(info.elemType ?? { kind: $.TypeKind.Basic, name: 'unknown' }),
2219
+ )
2220
+ default:
2221
+ return StructType.createTypeFromFieldInfo(info)
2222
+ }
2223
+ }
2224
+
2225
+ function functionTypeFromInfo(info: $.FunctionTypeInfo): Type {
2226
+ if (info.name) {
2227
+ return new FunctionType(info.name)
2228
+ }
2229
+ const params = info.params ?? []
2230
+ const paramTypes = params.map((param, index) => {
2231
+ const typeName = functionSignatureTypeName(param)
2232
+ if (!info.isVariadic || index !== params.length - 1) {
2233
+ return typeName
2234
+ }
2235
+ if (typeName.startsWith('[]')) {
2236
+ return '...' + typeName.slice(2)
2237
+ }
2238
+ return '...' + typeName
2239
+ })
2240
+ const resultTypes = (info.results ?? []).map(functionSignatureTypeName)
2241
+ let signature = `func(${paramTypes.join(', ')})`
2242
+ if (resultTypes.length === 1) {
2243
+ signature += ` ${resultTypes[0]}`
2244
+ }
2245
+ if (resultTypes.length > 1) {
2246
+ signature += ` (${resultTypes.join(', ')})`
2247
+ }
2248
+ return new FunctionType(signature)
2249
+ }
2250
+
2251
+ function functionSignatureTypeName(info: $.TypeInfo | string): string {
2252
+ return typeFromTypeInfo(info).String()
2253
+ }
2254
+
2255
+ function interfaceTypeFromInfo(info: $.InterfaceTypeInfo): Type {
2256
+ if (info.methods.length === 0) {
2257
+ return new InterfaceType('interface{}', info.name)
2258
+ }
2259
+ return new InterfaceType(
2260
+ `interface { ${info.methods.map((method) => method.name + '()').join('; ')} }`,
2261
+ info.name,
2262
+ )
2263
+ }
2264
+
2265
+ function chanDirFromTypeInfo(direction?: 'send' | 'receive' | 'both'): ChanDir {
2266
+ switch (direction) {
2267
+ case 'send':
2268
+ return SendDir
2269
+ case 'receive':
2270
+ return RecvDir
2271
+ default:
2272
+ return BothDir
2273
+ }
2274
+ }
2275
+
2187
2276
  /**
2188
2277
  * getInterfaceTypeByName looks up a registered interface type by name
2189
2278
  * and returns a Type for it. Returns an interface{} type if not found.