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
@@ -1,38 +1,49 @@
1
- import { describe, it, expect } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
+ import { resetHostRuntimeForTests } from '@goscript/builtin/hostio.js'
2
3
  import * as fmt from './fmt.js'
3
4
 
4
- // Helper to capture stdout via internal stdout.write
5
- // We will monkey-patch global process.stdout.write if available
5
+ const originalDeno = (globalThis as any).Deno
6
+ const originalProcess = (globalThis as any).process
7
+
8
+ afterEach(() => {
9
+ if (originalDeno === undefined) {
10
+ delete (globalThis as any).Deno
11
+ } else {
12
+ ;(globalThis as any).Deno = originalDeno
13
+ }
14
+
15
+ if (originalProcess === undefined) {
16
+ delete (globalThis as any).process
17
+ } else {
18
+ ;(globalThis as any).process = originalProcess
19
+ }
20
+
21
+ resetHostRuntimeForTests()
22
+ })
23
+
24
+ // Helper to capture stdout via the hostio text output path.
6
25
  function captureStdout(run: () => void): string {
7
26
  let buf = ''
8
- const hasProcess =
9
- typeof process !== 'undefined' &&
10
- (process as any).stdout &&
11
- typeof (process as any).stdout.write === 'function'
12
-
13
- if (hasProcess) {
14
- const orig = (process as any).stdout.write
15
- ;(process as any).stdout.write = (chunk: any) => {
16
- buf += typeof chunk === 'string' ? chunk : String(chunk)
17
- return true
18
- }
19
- try {
20
- run()
21
- } finally {
22
- ;(process as any).stdout.write = orig
23
- }
24
- } else {
25
- // Fallback: spy on console.log for environments without process
26
- const origLog = console.log
27
- ;(console as any).log = (msg: any) => {
28
- buf += String(msg) + '\n'
29
- }
30
- try {
31
- run()
32
- } finally {
33
- console.log = origLog
34
- }
27
+ delete (globalThis as any).Deno
28
+ ;(globalThis as any).process = {
29
+ getBuiltinModule: vi.fn(() => ({
30
+ readSync: vi.fn(),
31
+ writeSync: vi.fn(
32
+ (
33
+ _fd: number,
34
+ chunk: Uint8Array,
35
+ _offset?: number,
36
+ length?: number,
37
+ _position?: number | null,
38
+ ) => {
39
+ buf += new TextDecoder().decode(chunk.subarray(0, length ?? chunk.length))
40
+ return length ?? chunk.length
41
+ },
42
+ ),
43
+ })),
35
44
  }
45
+ resetHostRuntimeForTests()
46
+ run()
36
47
 
37
48
  return buf
38
49
  }
package/gs/fmt/fmt.ts CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  import * as $ from '@goscript/builtin/index.js'
5
5
  import * as errors from '@goscript/errors/index.js'
6
+ import { writeHostStdoutText } from '@goscript/builtin/hostio.js'
6
7
 
7
8
  // Basic interfaces
8
9
  export interface Stringer {
@@ -259,28 +260,7 @@ function parseFormat(format: string, args: any[]): string {
259
260
  // Global stdout simulation for Print functions
260
261
  let stdout = {
261
262
  write: (data: string) => {
262
- // Use process.stdout.write if available (Node.js), otherwise fallback to console.log
263
- // but we need to avoid adding extra newlines that console.log adds
264
- if (
265
- typeof process !== 'undefined' &&
266
- process.stdout &&
267
- process.stdout.write
268
- ) {
269
- process.stdout.write(data)
270
- } else {
271
- // In browser environments, we need to use console.log but handle newlines carefully
272
- // If the data already ends with \n, we should strip it to avoid double newlines
273
- if (data.endsWith('\n')) {
274
- console.log(data.slice(0, -1))
275
- } else {
276
- // Use console.log without adding newline by using a custom method
277
- if (console.log) {
278
- // For data without newlines, we can just print it directly
279
- // This is a bit of a hack but works for most cases
280
- console.log(data)
281
- }
282
- }
283
- }
263
+ writeHostStdoutText(data)
284
264
  },
285
265
  }
286
266
 
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { CompareEqualVT } from './index.js'
4
+
5
+ class TestValue {
6
+ constructor(private readonly value: string) {}
7
+
8
+ EqualVT(other: TestValue): boolean {
9
+ return this.value == other.value
10
+ }
11
+ }
12
+
13
+ describe('protobuf-go-lite EqualVT helpers', () => {
14
+ it('accepts compiler-emitted runtime type arguments', () => {
15
+ const equal = CompareEqualVT<TestValue>({
16
+ T: { zero: () => null },
17
+ })
18
+
19
+ expect(equal(new TestValue('a'), new TestValue('a'))).toBe(true)
20
+ expect(equal(new TestValue('a'), new TestValue('b'))).toBe(false)
21
+ expect(equal(null, null)).toBe(true)
22
+ })
23
+ })
@@ -9,6 +9,8 @@ export function IsEqualVT<T extends EqualVT<T>>(t1: T | null, t2: T | null): boo
9
9
  return t1.EqualVT(t2)
10
10
  }
11
11
 
12
- export function CompareEqualVT<T extends EqualVT<T>>(): (t1: T | null, t2: T | null) => boolean {
12
+ export function CompareEqualVT<T extends EqualVT<T>>(
13
+ _typeArgs?: unknown,
14
+ ): (t1: T | null, t2: T | null) => boolean {
13
15
  return (t1, t2) => IsEqualVT(t1, t2)
14
16
  }
@@ -1,5 +1,7 @@
1
1
  {
2
- "dependencies": [],
2
+ "dependencies": [
3
+ "github.com/aperturerobotics/wasivm/wazero/kernel/runtime"
4
+ ],
3
5
  "asyncMethods": {
4
6
  "Runtime.Compile": true,
5
7
  "Runtime.Close": true,
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import * as $ from '@goscript/builtin/index.js'
4
+ import * as token from '@goscript/go/token/index.js'
5
+
6
+ import {
7
+ ErrorList_Add,
8
+ ErrorList_Error,
9
+ ErrorList_Len,
10
+ ErrorList_RemoveMultiples,
11
+ type ErrorList,
12
+ } from './index.js'
13
+
14
+ describe('go/scanner override', () => {
15
+ it('adds and formats scanner errors', () => {
16
+ const list: $.VarRef<ErrorList> = $.varRef(null)
17
+
18
+ ErrorList_Add(
19
+ list,
20
+ $.markAsStructValue(
21
+ new token.Position({
22
+ Filename: 'test.go',
23
+ Line: 1,
24
+ Column: 1,
25
+ }),
26
+ ),
27
+ 'test error',
28
+ )
29
+
30
+ expect(ErrorList_Len(list.value)).toBe(1)
31
+ expect(ErrorList_Error(list.value)).toBe('test.go:1:1: test error')
32
+ })
33
+
34
+ it('removes repeated line errors', () => {
35
+ const list: $.VarRef<ErrorList> = $.varRef(null)
36
+ const pos = $.markAsStructValue(
37
+ new token.Position({
38
+ Filename: 'test.go',
39
+ Line: 1,
40
+ Column: 1,
41
+ }),
42
+ )
43
+
44
+ ErrorList_Add(list, pos, 'first')
45
+ ErrorList_Add(list, pos, 'second')
46
+ ErrorList_RemoveMultiples(list)
47
+
48
+ expect(ErrorList_Len(list.value)).toBe(1)
49
+ })
50
+ })
@@ -0,0 +1,157 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as token from '@goscript/go/token/index.js'
3
+
4
+ export class Error {
5
+ public get Pos(): token.Position {
6
+ return this._fields.Pos.value
7
+ }
8
+
9
+ public set Pos(value: token.Position) {
10
+ this._fields.Pos.value = value
11
+ }
12
+
13
+ public get Msg(): string {
14
+ return this._fields.Msg.value
15
+ }
16
+
17
+ public set Msg(value: string) {
18
+ this._fields.Msg.value = value
19
+ }
20
+
21
+ public _fields: {
22
+ Pos: $.VarRef<token.Position>
23
+ Msg: $.VarRef<string>
24
+ }
25
+
26
+ constructor(init?: Partial<{ Pos: token.Position; Msg: string }>) {
27
+ this._fields = {
28
+ Pos: $.varRef(init?.Pos ?? new token.Position()),
29
+ Msg: $.varRef(init?.Msg ?? ''),
30
+ }
31
+ }
32
+
33
+ public clone(): Error {
34
+ return $.markAsStructValue(
35
+ new Error({
36
+ Pos: this.Pos.clone(),
37
+ Msg: this.Msg,
38
+ }),
39
+ )
40
+ }
41
+
42
+ public Error(): string {
43
+ return Error_Error(this)
44
+ }
45
+
46
+ static __typeInfo = $.registerStructType(
47
+ 'go/scanner.Error',
48
+ new Error(),
49
+ [
50
+ {
51
+ name: 'Error',
52
+ args: [],
53
+ returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }],
54
+ },
55
+ ],
56
+ Error,
57
+ {
58
+ Pos: { type: 'go/token.Position' },
59
+ Msg: { kind: $.TypeKind.Basic, name: 'string' },
60
+ },
61
+ )
62
+ }
63
+
64
+ export type ErrorList = $.Slice<Error | null>
65
+
66
+ export const ScanComments = 1
67
+
68
+ export function Error_Error(err: Error): string {
69
+ if (!err.Pos.IsValid()) {
70
+ return err.Msg
71
+ }
72
+ return `${err.Pos.String()}: ${err.Msg}`
73
+ }
74
+
75
+ export function ErrorList_Add(
76
+ list: $.VarRef<ErrorList>,
77
+ pos: token.Position,
78
+ msg: string,
79
+ ): void {
80
+ list.value = $.append(
81
+ list.value,
82
+ $.markAsStructValue(new Error({ Pos: pos, Msg: msg })),
83
+ )
84
+ }
85
+
86
+ export function ErrorList_Len(list: ErrorList): number {
87
+ return $.len(list)
88
+ }
89
+
90
+ export function ErrorList_Less(list: ErrorList, i: number, j: number): boolean {
91
+ const left = list![i]!
92
+ const right = list![j]!
93
+ if (left.Pos.Filename !== right.Pos.Filename) {
94
+ return left.Pos.Filename < right.Pos.Filename
95
+ }
96
+ if (left.Pos.Line !== right.Pos.Line) {
97
+ return left.Pos.Line < right.Pos.Line
98
+ }
99
+ if (left.Pos.Column !== right.Pos.Column) {
100
+ return left.Pos.Column < right.Pos.Column
101
+ }
102
+ return left.Msg < right.Msg
103
+ }
104
+
105
+ export function ErrorList_Swap(list: ErrorList, i: number, j: number): void {
106
+ const first = list![i]
107
+ list![i] = list![j]
108
+ list![j] = first
109
+ }
110
+
111
+ export function ErrorList_Sort(list: ErrorList): void {
112
+ list?.sort((left, right) => {
113
+ if (left === null || right === null) {
114
+ if (left === right) {
115
+ return 0
116
+ }
117
+ if (left === null) {
118
+ return -1
119
+ }
120
+ return 1
121
+ }
122
+ if (ErrorList_Less([left, right], 0, 1)) {
123
+ return -1
124
+ }
125
+ if (ErrorList_Less([right, left], 0, 1)) {
126
+ return 1
127
+ }
128
+ return 0
129
+ })
130
+ }
131
+
132
+ export function ErrorList_RemoveMultiples(list: $.VarRef<ErrorList>): void {
133
+ ErrorList_Sort(list.value)
134
+ const seen = new Set<string>()
135
+ list.value = $.asArray(list.value).filter((err) => {
136
+ if (err === null) {
137
+ return false
138
+ }
139
+ const key = `${err.Pos.Filename}:${err.Pos.Line}`
140
+ if (seen.has(key)) {
141
+ return false
142
+ }
143
+ seen.add(key)
144
+ return true
145
+ })
146
+ }
147
+
148
+ export function ErrorList_Error(list: ErrorList): string {
149
+ const errors = $.asArray(list).filter((err) => err !== null)
150
+ if (errors.length === 0) {
151
+ return 'no errors'
152
+ }
153
+ if (errors.length === 1) {
154
+ return errors[0]!.Error()
155
+ }
156
+ return `${errors[0]!.Error()} (and ${errors.length - 1} more errors)`
157
+ }
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import * as $ from '@goscript/builtin/index.js'
4
+
5
+ import { Position, Position_IsValid, Position_String } from './index.js'
6
+
7
+ describe('go/token override', () => {
8
+ it('models Position values', () => {
9
+ const pos = $.markAsStructValue(
10
+ new Position({
11
+ Filename: 'test.go',
12
+ Line: 3,
13
+ Column: 9,
14
+ }),
15
+ )
16
+
17
+ expect(Position_IsValid(pos)).toBe(true)
18
+ expect(Position_String(pos)).toBe('test.go:3:9')
19
+ expect(pos.clone().String()).toBe('test.go:3:9')
20
+ })
21
+ })
@@ -0,0 +1,120 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+
3
+ export type Pos = number
4
+
5
+ export const NoPos: Pos = 0
6
+
7
+ export class Position {
8
+ public get Filename(): string {
9
+ return this._fields.Filename.value
10
+ }
11
+
12
+ public set Filename(value: string) {
13
+ this._fields.Filename.value = value
14
+ }
15
+
16
+ public get Offset(): number {
17
+ return this._fields.Offset.value
18
+ }
19
+
20
+ public set Offset(value: number) {
21
+ this._fields.Offset.value = value
22
+ }
23
+
24
+ public get Line(): number {
25
+ return this._fields.Line.value
26
+ }
27
+
28
+ public set Line(value: number) {
29
+ this._fields.Line.value = value
30
+ }
31
+
32
+ public get Column(): number {
33
+ return this._fields.Column.value
34
+ }
35
+
36
+ public set Column(value: number) {
37
+ this._fields.Column.value = value
38
+ }
39
+
40
+ public _fields: {
41
+ Filename: $.VarRef<string>
42
+ Offset: $.VarRef<number>
43
+ Line: $.VarRef<number>
44
+ Column: $.VarRef<number>
45
+ }
46
+
47
+ constructor(
48
+ init?: Partial<{
49
+ Filename: string
50
+ Offset: number
51
+ Line: number
52
+ Column: number
53
+ }>,
54
+ ) {
55
+ this._fields = {
56
+ Filename: $.varRef(init?.Filename ?? ''),
57
+ Offset: $.varRef(init?.Offset ?? 0),
58
+ Line: $.varRef(init?.Line ?? 0),
59
+ Column: $.varRef(init?.Column ?? 0),
60
+ }
61
+ }
62
+
63
+ public clone(): Position {
64
+ return $.markAsStructValue(
65
+ new Position({
66
+ Filename: this.Filename,
67
+ Offset: this.Offset,
68
+ Line: this.Line,
69
+ Column: this.Column,
70
+ }),
71
+ )
72
+ }
73
+
74
+ public IsValid(): boolean {
75
+ return Position_IsValid(this)
76
+ }
77
+
78
+ public String(): string {
79
+ return Position_String(this)
80
+ }
81
+
82
+ static __typeInfo = $.registerStructType(
83
+ 'go/token.Position',
84
+ new Position(),
85
+ [
86
+ {
87
+ name: 'IsValid',
88
+ args: [],
89
+ returns: [{ type: { kind: $.TypeKind.Basic, name: 'bool' } }],
90
+ },
91
+ {
92
+ name: 'String',
93
+ args: [],
94
+ returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }],
95
+ },
96
+ ],
97
+ Position,
98
+ {
99
+ Filename: { kind: $.TypeKind.Basic, name: 'string' },
100
+ Offset: { kind: $.TypeKind.Basic, name: 'int' },
101
+ Line: { kind: $.TypeKind.Basic, name: 'int' },
102
+ Column: { kind: $.TypeKind.Basic, name: 'int' },
103
+ },
104
+ )
105
+ }
106
+
107
+ export function Position_IsValid(pos: Position): boolean {
108
+ return pos.Line > 0
109
+ }
110
+
111
+ export function Position_String(pos: Position): string {
112
+ if (!Position_IsValid(pos)) {
113
+ return '-'
114
+ }
115
+ const filename = pos.Filename === '' ? '<input>' : pos.Filename
116
+ if (pos.Column > 0) {
117
+ return `${filename}:${pos.Line}:${pos.Column}`
118
+ }
119
+ return `${filename}:${pos.Line}`
120
+ }
@@ -4,6 +4,7 @@ import * as io from '@goscript/io/index.js'
4
4
 
5
5
  import { NewFile, Stderr, Stdin, Stdout } from './file_unix_js.gs.js'
6
6
  import { ErrClosed } from './error.gs.js'
7
+ import { createHostFile, resetHostRuntimeForTests } from './types_js.gs.js'
7
8
 
8
9
  const originalDeno = (globalThis as any).Deno
9
10
  const originalProcess = (globalThis as any).process
@@ -20,6 +21,8 @@ afterEach(() => {
20
21
  } else {
21
22
  ;(globalThis as any).process = originalProcess
22
23
  }
24
+
25
+ resetHostRuntimeForTests()
23
26
  })
24
27
 
25
28
  describe('os stdio', () => {
@@ -45,6 +48,7 @@ describe('os stdio', () => {
45
48
  stdout: { writeSync: stdoutWriteSync },
46
49
  }
47
50
  delete (globalThis as any).process
51
+ resetHostRuntimeForTests()
48
52
 
49
53
  const input = NewFile(0, 'stdin')
50
54
  const output = NewFile(1, 'stdout')
@@ -93,6 +97,7 @@ describe('os stdio', () => {
93
97
  writeSync,
94
98
  })),
95
99
  }
100
+ resetHostRuntimeForTests()
96
101
 
97
102
  const input = NewFile(0, 'stdin')
98
103
  const output = NewFile(1, 'stdout')
@@ -110,6 +115,56 @@ describe('os stdio', () => {
110
115
  expect(writeSync).toHaveBeenCalledTimes(1)
111
116
  })
112
117
 
118
+ it('falls back to process builtin fs when Deno lacks sync stdio', () => {
119
+ const readSync = vi.fn(
120
+ (
121
+ _fd: number,
122
+ buffer: Uint8Array,
123
+ _offset?: number,
124
+ _length?: number,
125
+ _position?: number | null,
126
+ ) => {
127
+ buffer.set([5, 6], 0)
128
+ return 2
129
+ },
130
+ )
131
+ const writeSync = vi.fn(
132
+ (
133
+ _fd: number,
134
+ _buffer: Uint8Array,
135
+ _offset?: number,
136
+ length?: number,
137
+ _position?: number | null,
138
+ ) => length ?? 0,
139
+ )
140
+
141
+ ;(globalThis as any).Deno = {
142
+ stdin: {},
143
+ stdout: {},
144
+ }
145
+ ;(globalThis as any).process = {
146
+ getBuiltinModule: vi.fn(() => ({
147
+ readSync,
148
+ writeSync,
149
+ })),
150
+ }
151
+ resetHostRuntimeForTests()
152
+
153
+ const input = NewFile(0, 'stdin')
154
+ const output = NewFile(1, 'stdout')
155
+ const readBuf = new Uint8Array(2)
156
+
157
+ const [readN, readErr] = input!.Read(readBuf)
158
+ expect(readN).toBe(2)
159
+ expect(readErr).toBeNull()
160
+ expect(Array.from(readBuf)).toEqual([5, 6])
161
+
162
+ const [writeN, writeErr] = output!.Write(new Uint8Array([7, 8, 9]))
163
+ expect(writeN).toBe(3)
164
+ expect(writeErr).toBeNull()
165
+ expect(writeSync).toHaveBeenCalledTimes(1)
166
+ })
167
+
113
168
  it('returns EOF on zero-byte reads and ErrClosed after Close', () => {
114
169
  const stdinReadSync = vi.fn(() => 0)
115
170
 
@@ -117,6 +172,7 @@ describe('os stdio', () => {
117
172
  stdin: { readSync: stdinReadSync },
118
173
  }
119
174
  delete (globalThis as any).process
175
+ resetHostRuntimeForTests()
120
176
 
121
177
  const input = NewFile(0, 'stdin')!
122
178
  const [readN, readErr] = input.Read(new Uint8Array(1))
@@ -128,4 +184,51 @@ describe('os stdio', () => {
128
184
  expect(closedN).toBe(0)
129
185
  expect(closedErr).toBe(ErrClosed)
130
186
  })
187
+
188
+ it('retries short writes until the full buffer is written', () => {
189
+ const writeSync = vi
190
+ .fn<(buffer: Uint8Array) => number>()
191
+ .mockImplementationOnce((_buffer: Uint8Array) => 2)
192
+ .mockImplementationOnce((buffer: Uint8Array) => buffer.length)
193
+
194
+ ;(globalThis as any).Deno = {
195
+ stdout: { writeSync },
196
+ }
197
+ delete (globalThis as any).process
198
+ resetHostRuntimeForTests()
199
+
200
+ const output = NewFile(1, 'stdout')!
201
+ const [writeN, writeErr] = output.Write(new Uint8Array([1, 2, 3, 4, 5]))
202
+ expect(writeN).toBe(5)
203
+ expect(writeErr).toBeNull()
204
+ expect(writeSync).toHaveBeenCalledTimes(2)
205
+ expect(Array.from(writeSync.mock.calls[1][0])).toEqual([3, 4, 5])
206
+ })
207
+
208
+ it('prefers direct handle read and write methods when available', () => {
209
+ const handle = {
210
+ readSync: vi.fn((buffer: Uint8Array) => {
211
+ buffer.set([11, 12, 13], 0)
212
+ return 3
213
+ }),
214
+ writeSync: vi
215
+ .fn<(buffer: Uint8Array) => number>()
216
+ .mockImplementationOnce((_buffer: Uint8Array) => 1)
217
+ .mockImplementationOnce((buffer: Uint8Array) => buffer.length),
218
+ }
219
+
220
+ const file = createHostFile('host-file', 99, handle)
221
+ const readBuf = new Uint8Array(4)
222
+
223
+ const [readN, readErr] = file.Read(readBuf)
224
+ expect(readN).toBe(3)
225
+ expect(readErr).toBeNull()
226
+ expect(Array.from(readBuf.slice(0, 3))).toEqual([11, 12, 13])
227
+
228
+ const [writeN, writeErr] = file.Write(new Uint8Array([21, 22, 23]))
229
+ expect(writeN).toBe(3)
230
+ expect(writeErr).toBeNull()
231
+ expect(handle.writeSync).toHaveBeenCalledTimes(2)
232
+ expect(Array.from(handle.writeSync.mock.calls[1][0])).toEqual([22, 23])
233
+ })
131
234
  })
package/gs/os/meta.json CHANGED
@@ -3,7 +3,6 @@
3
3
  "errors",
4
4
  "internal/byteorder",
5
5
  "internal/goarch",
6
- "internal/poll",
7
6
  "io",
8
7
  "io/fs",
9
8
  "runtime",
@@ -12,4 +11,4 @@
12
11
  "time",
13
12
  "unsafe"
14
13
  ]
15
- }
14
+ }