goscript 0.1.3 → 0.1.4

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 (117) hide show
  1. package/cmd/goscript/cmd_compile.go +28 -8
  2. package/cmd/goscript/cmd_compile_test.go +105 -6
  3. package/compiler/build-flags.go +9 -10
  4. package/compiler/gotest/runner_test.go +127 -0
  5. package/compiler/lowering.go +596 -136
  6. package/compiler/lowering_bench_test.go +350 -0
  7. package/compiler/package-graph.go +61 -4
  8. package/compiler/package-graph_test.go +30 -0
  9. package/compiler/semantic-model-types.go +8 -0
  10. package/compiler/semantic-model.go +447 -22
  11. package/compiler/semantic-model_test.go +138 -0
  12. package/compiler/skeleton_test.go +948 -14
  13. package/compiler/typescript-emitter.go +19 -2
  14. package/dist/gs/builtin/builtin.d.ts +2 -2
  15. package/dist/gs/builtin/builtin.js +20 -0
  16. package/dist/gs/builtin/builtin.js.map +1 -1
  17. package/dist/gs/builtin/slice.js +5 -0
  18. package/dist/gs/builtin/slice.js.map +1 -1
  19. package/dist/gs/builtin/type.d.ts +1 -1
  20. package/dist/gs/builtin/type.js +72 -5
  21. package/dist/gs/builtin/type.js.map +1 -1
  22. package/dist/gs/compress/zlib/index.d.ts +3 -3
  23. package/dist/gs/compress/zlib/index.js +88 -26
  24. package/dist/gs/compress/zlib/index.js.map +1 -1
  25. package/dist/gs/crypto/sha1/index.js +2 -5
  26. package/dist/gs/crypto/sha1/index.js.map +1 -1
  27. package/dist/gs/crypto/sha256/index.js +2 -5
  28. package/dist/gs/crypto/sha256/index.js.map +1 -1
  29. package/dist/gs/crypto/sha512/index.js +2 -5
  30. package/dist/gs/crypto/sha512/index.js.map +1 -1
  31. package/dist/gs/embed/index.d.ts +6 -0
  32. package/dist/gs/embed/index.js +210 -5
  33. package/dist/gs/embed/index.js.map +1 -1
  34. package/dist/gs/fmt/fmt.d.ts +3 -3
  35. package/dist/gs/fmt/fmt.js +29 -16
  36. package/dist/gs/fmt/fmt.js.map +1 -1
  37. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
  38. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  39. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  40. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  41. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  42. package/dist/gs/io/fs/readdir.js +5 -3
  43. package/dist/gs/io/fs/readdir.js.map +1 -1
  44. package/dist/gs/io/io.d.ts +10 -6
  45. package/dist/gs/io/io.js +87 -42
  46. package/dist/gs/io/io.js.map +1 -1
  47. package/dist/gs/math/bits/index.d.ts +26 -5
  48. package/dist/gs/math/bits/index.js +13 -24
  49. package/dist/gs/math/bits/index.js.map +1 -1
  50. package/dist/gs/net/http/index.d.ts +3 -1
  51. package/dist/gs/net/http/index.js +18 -1
  52. package/dist/gs/net/http/index.js.map +1 -1
  53. package/dist/gs/os/types_js.gs.d.ts +6 -2
  54. package/dist/gs/os/types_js.gs.js +169 -8
  55. package/dist/gs/os/types_js.gs.js.map +1 -1
  56. package/dist/gs/reflect/type.d.ts +1 -0
  57. package/dist/gs/reflect/type.js +80 -51
  58. package/dist/gs/reflect/type.js.map +1 -1
  59. package/dist/gs/strings/reader.d.ts +1 -1
  60. package/dist/gs/strings/reader.js +2 -2
  61. package/dist/gs/strings/reader.js.map +1 -1
  62. package/dist/gs/sync/sync.d.ts +2 -1
  63. package/dist/gs/sync/sync.js +37 -16
  64. package/dist/gs/sync/sync.js.map +1 -1
  65. package/dist/gs/syscall/js/index.js +9 -0
  66. package/dist/gs/syscall/js/index.js.map +1 -1
  67. package/dist/gs/testing/testing.js +8 -6
  68. package/dist/gs/testing/testing.js.map +1 -1
  69. package/gs/builtin/builtin.ts +25 -2
  70. package/gs/builtin/runtime-contract.test.ts +45 -0
  71. package/gs/builtin/slice.ts +7 -0
  72. package/gs/builtin/type.ts +85 -5
  73. package/gs/compress/zlib/index.test.ts +97 -0
  74. package/gs/compress/zlib/index.ts +117 -27
  75. package/gs/compress/zlib/meta.json +4 -1
  76. package/gs/crypto/sha1/index.test.ts +19 -2
  77. package/gs/crypto/sha1/index.ts +3 -6
  78. package/gs/crypto/sha256/index.test.ts +14 -2
  79. package/gs/crypto/sha256/index.ts +3 -6
  80. package/gs/crypto/sha512/index.test.ts +17 -2
  81. package/gs/crypto/sha512/index.ts +3 -6
  82. package/gs/embed/index.test.ts +87 -0
  83. package/gs/embed/index.ts +229 -5
  84. package/gs/fmt/fmt.test.ts +41 -3
  85. package/gs/fmt/fmt.ts +40 -17
  86. package/gs/fmt/meta.json +6 -1
  87. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
  88. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
  89. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  90. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  91. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  92. package/gs/io/fs/readdir.test.ts +38 -0
  93. package/gs/io/fs/readdir.ts +7 -3
  94. package/gs/io/io.test.ts +77 -6
  95. package/gs/io/io.ts +114 -52
  96. package/gs/io/meta.json +7 -1
  97. package/gs/math/bits/index.ts +52 -28
  98. package/gs/net/http/index.test.ts +16 -0
  99. package/gs/net/http/index.ts +19 -2
  100. package/gs/os/file_unix_js.test.ts +52 -0
  101. package/gs/os/meta.json +4 -0
  102. package/gs/os/readdir.test.ts +56 -0
  103. package/gs/os/types_js.gs.ts +169 -8
  104. package/gs/reflect/deepequal.test.ts +10 -1
  105. package/gs/reflect/type.ts +91 -56
  106. package/gs/reflect/typefor.test.ts +31 -1
  107. package/gs/strings/meta.json +5 -2
  108. package/gs/strings/reader.test.ts +2 -2
  109. package/gs/strings/reader.ts +2 -2
  110. package/gs/sync/meta.json +1 -0
  111. package/gs/sync/sync.test.ts +41 -1
  112. package/gs/sync/sync.ts +41 -16
  113. package/gs/syscall/js/index.test.ts +18 -0
  114. package/gs/syscall/js/index.ts +12 -0
  115. package/gs/testing/testing.test.ts +32 -3
  116. package/gs/testing/testing.ts +13 -10
  117. package/package.json +1 -1
package/gs/io/io.ts CHANGED
@@ -72,67 +72,111 @@ export interface WriteSeeker extends Writer, Seeker {}
72
72
  export interface ReadWriteSeeker extends Reader, Writer, Seeker {}
73
73
 
74
74
  class pipeState {
75
- private chunks: Uint8Array[] = []
76
- private readOffset = 0
77
75
  private readerClosed = false
78
76
  private writerClosed = false
79
77
  private readerErr: $.GoError = null
80
78
  private writerErr: $.GoError = null
81
-
82
- Read(p: $.Bytes): [number, $.GoError] {
83
- if (this.readerClosed) {
84
- return [0, this.readerErr ?? ErrClosedPipe]
85
- }
86
- if ($.len(p) === 0) {
87
- return [0, null]
88
- }
89
- if (this.chunks.length === 0) {
79
+ private pendingReads: Array<{
80
+ data: $.Bytes
81
+ resolve: (result: [number, $.GoError]) => void
82
+ }> = []
83
+ private pendingWrites: Array<{
84
+ data: Uint8Array
85
+ offset: number
86
+ resolve: (result: [number, $.GoError]) => void
87
+ }> = []
88
+
89
+ Read(p: $.Bytes): Promise<[number, $.GoError]> {
90
+ return (async (): Promise<[number, $.GoError]> => {
91
+ if (this.readerClosed) {
92
+ return [0, this.readerErr ?? ErrClosedPipe]
93
+ }
94
+ if ($.len(p) === 0) {
95
+ return [0, null]
96
+ }
97
+ if (this.pendingWrites.length > 0) {
98
+ return this.consumeNextWrite(p)
99
+ }
90
100
  if (this.writerClosed) {
91
101
  return [0, this.writerErr ?? EOF]
92
102
  }
93
- return [0, EOF]
94
- }
95
-
96
- let copied = 0
97
- while (copied < $.len(p) && this.chunks.length > 0) {
98
- const chunk = this.chunks[0]
99
- const available = chunk.length - this.readOffset
100
- const want = Math.min($.len(p) - copied, available)
101
- const target = $.goSlice(p, copied, copied + want)
102
- $.copy(target, chunk.subarray(this.readOffset, this.readOffset + want))
103
- copied += want
104
- this.readOffset += want
105
- if (this.readOffset === chunk.length) {
106
- this.chunks.shift()
107
- this.readOffset = 0
108
- }
109
- }
110
- return [copied, null]
103
+ return await new Promise<[number, $.GoError]>((resolve) => {
104
+ this.pendingReads.push({ data: p, resolve })
105
+ })
106
+ })()
111
107
  }
112
108
 
113
- Write(p: $.Bytes): [number, $.GoError] {
114
- if (this.writerClosed || this.readerClosed) {
115
- return [0, this.readerErr ?? ErrClosedPipe]
116
- }
117
- const data = new Uint8Array($.len(p))
118
- $.copy(data, p)
119
- this.chunks.push(data)
120
- return [$.len(p), null]
109
+ Write(p: $.Bytes): Promise<[number, $.GoError]> {
110
+ return (async (): Promise<[number, $.GoError]> => {
111
+ if (this.writerClosed || this.readerClosed) {
112
+ return [0, this.readerErr ?? ErrClosedPipe]
113
+ }
114
+ if ($.len(p) === 0) {
115
+ return [0, null]
116
+ }
117
+ const data = new Uint8Array($.len(p))
118
+ $.copy(data, p)
119
+ return await new Promise<[number, $.GoError]>((resolve) => {
120
+ this.pendingWrites.push({ data, offset: 0, resolve })
121
+ this.drain()
122
+ })
123
+ })()
121
124
  }
122
125
 
123
126
  CloseReader(err: $.GoError): $.GoError {
124
127
  this.readerClosed = true
125
128
  this.readerErr = err
126
- this.chunks = []
127
- this.readOffset = 0
129
+ this.resolvePendingReads(ErrClosedPipe)
130
+ this.resolvePendingWrites(ErrClosedPipe)
128
131
  return null
129
132
  }
130
133
 
131
134
  CloseWriter(err: $.GoError): $.GoError {
132
135
  this.writerClosed = true
133
136
  this.writerErr = err
137
+ if (this.pendingWrites.length === 0) {
138
+ this.resolvePendingReads(err ?? EOF)
139
+ }
134
140
  return null
135
141
  }
142
+
143
+ private drain(): void {
144
+ while (this.pendingWrites.length > 0 && this.pendingReads.length > 0) {
145
+ if (this.readerClosed) {
146
+ this.resolvePendingWrites(this.readerErr ?? ErrClosedPipe)
147
+ return
148
+ }
149
+ const pending = this.pendingReads.shift()!
150
+ pending.resolve(this.consumeNextWrite(pending.data))
151
+ }
152
+ }
153
+
154
+ private consumeNextWrite(p: $.Bytes): [number, $.GoError] {
155
+ const pending = this.pendingWrites[0]
156
+ const n = Math.min($.len(p), pending.data.length - pending.offset)
157
+ $.copy(p, pending.data.subarray(pending.offset, pending.offset + n))
158
+ pending.offset += n
159
+ if (pending.offset === pending.data.length) {
160
+ this.pendingWrites.shift()
161
+ pending.resolve([pending.data.length, null])
162
+ if (this.writerClosed && this.pendingWrites.length === 0) {
163
+ this.resolvePendingReads(this.writerErr ?? EOF)
164
+ }
165
+ }
166
+ return [n, null]
167
+ }
168
+
169
+ private resolvePendingReads(err: $.GoError): void {
170
+ while (this.pendingReads.length > 0) {
171
+ this.pendingReads.shift()!.resolve([0, err])
172
+ }
173
+ }
174
+
175
+ private resolvePendingWrites(err: $.GoError): void {
176
+ while (this.pendingWrites.length > 0) {
177
+ this.pendingWrites.shift()!.resolve([0, err])
178
+ }
179
+ }
136
180
  }
137
181
 
138
182
  // PipeReader is the read half of a pipe.
@@ -140,7 +184,7 @@ export class PipeReader implements Reader, Closer {
140
184
  constructor(private pipe: pipeState) {}
141
185
 
142
186
  Read(data: $.Bytes): [number, $.GoError] {
143
- return this.pipe.Read(data)
187
+ return this.pipe.Read(data) as any
144
188
  }
145
189
 
146
190
  Close(): $.GoError {
@@ -157,7 +201,7 @@ export class PipeWriter implements Writer, Closer {
157
201
  constructor(private pipe: pipeState) {}
158
202
 
159
203
  Write(data: $.Bytes): [number, $.GoError] {
160
- return this.pipe.Write(data)
204
+ return this.pipe.Write(data) as any
161
205
  }
162
206
 
163
207
  Close(): $.GoError {
@@ -235,15 +279,18 @@ class DiscardWriter implements Writer {
235
279
  export const Discard: Writer | null = new DiscardWriter()
236
280
 
237
281
  // WriteString writes the contents of the string s to w, which accepts a slice of bytes
238
- export function WriteString(w: Writer, s: string): [number, $.GoError] {
282
+ export async function WriteString(
283
+ w: Writer,
284
+ s: string,
285
+ ): Promise<[number, $.GoError]> {
239
286
  // Check if w implements StringWriter interface
240
287
  if ('WriteString' in w && typeof (w as any).WriteString === 'function') {
241
- return (w as StringWriter).WriteString(s)
288
+ return await ((w as StringWriter).WriteString(s) as any)
242
289
  }
243
290
 
244
291
  // Convert string to bytes and write
245
292
  const bytes = new TextEncoder().encode(s)
246
- return w.Write(bytes)
293
+ return await (w.Write(bytes) as any)
247
294
  }
248
295
 
249
296
  // LimitedReader reads from R but limits the amount of data returned to just N bytes
@@ -251,7 +298,10 @@ export class LimitedReader implements Reader {
251
298
  public R: Reader | null
252
299
  public N: number
253
300
 
254
- constructor(r?: Reader | { R?: Reader | null; N?: number } | null, n?: number) {
301
+ constructor(
302
+ r?: Reader | { R?: Reader | null; N?: number } | null,
303
+ n?: number,
304
+ ) {
255
305
  if (r != null && typeof (r as { Read?: unknown }).Read !== 'function') {
256
306
  const init = r as { R?: Reader | null; N?: number }
257
307
  this.R = init.R ?? null
@@ -605,7 +655,15 @@ export async function ReadAll(r: Reader): Promise<[$.Bytes, $.GoError]> {
605
655
  }
606
656
 
607
657
  // NopCloser returns a ReadCloser with a no-op Close method wrapping the provided Reader r
608
- export function NopCloser(r: Reader): ReadCloser {
658
+ export function NopCloser(r: Reader | null): ReadCloser {
659
+ if (r == null) {
660
+ return {
661
+ Read: () => {
662
+ throw new Error('nil Reader')
663
+ },
664
+ Close: () => null,
665
+ }
666
+ }
609
667
  return {
610
668
  Read: r.Read.bind(r),
611
669
  Close: () => null,
@@ -655,22 +713,22 @@ class multiReader implements Reader {
655
713
 
656
714
  // MultiWriter creates a writer that duplicates its writes to all the provided writers
657
715
  export function MultiWriter(...writers: (Writer | null)[]): Writer {
658
- return new multiWriter(writers.slice())
716
+ return new multiWriter(writers.slice()) as any
659
717
  }
660
718
 
661
- class multiWriter implements Writer {
719
+ class multiWriter {
662
720
  private writers: (Writer | null)[]
663
721
 
664
722
  constructor(writers: (Writer | null)[]) {
665
723
  this.writers = writers
666
724
  }
667
725
 
668
- Write(p: $.Bytes): [number, $.GoError] {
726
+ async Write(p: $.Bytes): Promise<[number, $.GoError]> {
669
727
  for (const w of this.writers) {
670
728
  if (w == null) {
671
729
  throw new Error('io.MultiWriter: nil writer')
672
730
  }
673
- const [n, err] = w.Write(p)
731
+ const [n, err] = await w.Write(p)
674
732
  if (err !== null) {
675
733
  return [n, err]
676
734
  }
@@ -697,15 +755,19 @@ class teeReader implements Reader {
697
755
  }
698
756
 
699
757
  Read(p: $.Bytes): [number, $.GoError] {
758
+ return this.read(p) as any
759
+ }
760
+
761
+ private async read(p: $.Bytes): Promise<[number, $.GoError]> {
700
762
  if (this.r == null) {
701
763
  throw new Error('io.TeeReader: nil reader')
702
764
  }
703
- const [n, err] = this.r.Read(p)
765
+ const [n, err] = await this.r.Read(p)
704
766
  if (n > 0) {
705
767
  if (this.w == null) {
706
768
  throw new Error('io.TeeReader: nil writer')
707
769
  }
708
- const [nw, ew] = this.w.Write($.goSlice(p, 0, n))
770
+ const [nw, ew] = await this.w.Write($.goSlice(p, 0, n))
709
771
  if (ew !== null) {
710
772
  return [n, ew]
711
773
  }
package/gs/io/meta.json CHANGED
@@ -12,6 +12,12 @@
12
12
  "CopyN": true,
13
13
  "ReadAtLeast": true,
14
14
  "ReadFull": true,
15
- "ReadAll": true
15
+ "ReadAll": true,
16
+ "WriteString": true
17
+ },
18
+ "asyncMethods": {
19
+ "PipeReader.Read": true,
20
+ "PipeWriter.Write": true,
21
+ "TeeReader.Read": true
16
22
  }
17
23
  }
@@ -2,7 +2,7 @@
2
2
  // This replaces the auto-generated version that has TypeScript syntax errors
3
3
 
4
4
  // UintSize is the size of a uint in bits
5
- export const UintSize = 32 // Assuming 32-bit for JavaScript numbers
5
+ export const UintSize = 64
6
6
 
7
7
  type Word64 = number | bigint
8
8
 
@@ -23,8 +23,8 @@ function word64Result(value: bigint, useBigInt: boolean): Word64 {
23
23
  }
24
24
 
25
25
  // --- Leading zeros ---
26
- export function LeadingZeros(x: number): number {
27
- return Math.clz32(x >>> 0)
26
+ export function LeadingZeros(x: Word64): number {
27
+ return LeadingZeros64(x)
28
28
  }
29
29
 
30
30
  export function LeadingZeros8(x: number): number {
@@ -53,9 +53,8 @@ export function LeadingZeros64(x: Word64): number {
53
53
  }
54
54
 
55
55
  // --- Trailing zeros ---
56
- export function TrailingZeros(x: number): number {
57
- if (x === 0) return UintSize
58
- return TrailingZeros32(x)
56
+ export function TrailingZeros(x: Word64): number {
57
+ return TrailingZeros64(x)
59
58
  }
60
59
 
61
60
  export function TrailingZeros8(x: number): number {
@@ -90,8 +89,8 @@ export function TrailingZeros64(x: Word64): number {
90
89
  }
91
90
 
92
91
  // --- Ones count ---
93
- export function OnesCount(x: number): number {
94
- return OnesCount32(x)
92
+ export function OnesCount(x: Word64): number {
93
+ return OnesCount64(x)
95
94
  }
96
95
 
97
96
  export function OnesCount8(x: number): number {
@@ -124,8 +123,11 @@ export function OnesCount64(x: Word64): number {
124
123
  }
125
124
 
126
125
  // --- Rotate left ---
127
- export function RotateLeft(x: number, k: number): number {
128
- return RotateLeft32(x, k)
126
+ export function RotateLeft(x: number, k: number): number
127
+ export function RotateLeft(x: bigint, k: number): bigint
128
+ export function RotateLeft(x: Word64, k: number): number
129
+ export function RotateLeft(x: Word64, k: number): Word64 {
130
+ return RotateLeft64(x, k)
129
131
  }
130
132
 
131
133
  export function RotateLeft8(x: number, k: number): number {
@@ -151,6 +153,7 @@ export function RotateLeft32(x: number, k: number): number {
151
153
 
152
154
  export function RotateLeft64(x: number, k: number): number
153
155
  export function RotateLeft64(x: bigint, k: number): bigint
156
+ export function RotateLeft64(x: Word64, k: number): number
154
157
  export function RotateLeft64(x: Word64, k: number): Word64 {
155
158
  const n = 64
156
159
  k = k % n
@@ -163,8 +166,11 @@ export function RotateLeft64(x: Word64, k: number): Word64 {
163
166
  }
164
167
 
165
168
  // --- Reverse ---
166
- export function Reverse(x: number): number {
167
- return Reverse32(x)
169
+ export function Reverse(x: number): number
170
+ export function Reverse(x: bigint): bigint
171
+ export function Reverse(x: Word64): number
172
+ export function Reverse(x: Word64): Word64 {
173
+ return Reverse64(x)
168
174
  }
169
175
 
170
176
  export function Reverse8(x: number): number {
@@ -196,6 +202,7 @@ export function Reverse32(x: number): number {
196
202
 
197
203
  export function Reverse64(x: number): number
198
204
  export function Reverse64(x: bigint): bigint
205
+ export function Reverse64(x: Word64): number
199
206
  export function Reverse64(x: Word64): Word64 {
200
207
  // Implement 64-bit reverse using similar bit manipulation
201
208
  const useBigInt = useBigIntResult(x)
@@ -226,8 +233,11 @@ export function Reverse64(x: Word64): Word64 {
226
233
  }
227
234
 
228
235
  // --- ReverseBytes ---
229
- export function ReverseBytes(x: number): number {
230
- return ReverseBytes32(x)
236
+ export function ReverseBytes(x: number): number
237
+ export function ReverseBytes(x: bigint): bigint
238
+ export function ReverseBytes(x: Word64): number
239
+ export function ReverseBytes(x: Word64): Word64 {
240
+ return ReverseBytes64(x)
231
241
  }
232
242
 
233
243
  export function ReverseBytes16(x: number): number {
@@ -247,6 +257,7 @@ export function ReverseBytes32(x: number): number {
247
257
 
248
258
  export function ReverseBytes64(x: number): number
249
259
  export function ReverseBytes64(x: bigint): bigint
260
+ export function ReverseBytes64(x: Word64): number
250
261
  export function ReverseBytes64(x: Word64): Word64 {
251
262
  const useBigInt = useBigIntResult(x)
252
263
  const word = toUint64(x)
@@ -266,8 +277,8 @@ export function ReverseBytes64(x: Word64): Word64 {
266
277
  }
267
278
 
268
279
  // --- Len ---
269
- export function Len(x: number): number {
270
- return Len32(x)
280
+ export function Len(x: Word64): number {
281
+ return Len64(x)
271
282
  }
272
283
 
273
284
  export function Len8(x: number): number {
@@ -287,8 +298,11 @@ export function Len64(x: Word64): number {
287
298
  }
288
299
 
289
300
  // --- Multiplication functions ---
290
- export function Mul(x: number, y: number): [number, number] {
291
- return Mul32(x, y)
301
+ export function Mul(x: number, y: number): [number, number]
302
+ export function Mul(x: bigint, y: bigint): [bigint, bigint]
303
+ export function Mul(x: Word64, y: Word64): [number, number]
304
+ export function Mul(x: Word64, y: Word64): [Word64, Word64] {
305
+ return Mul64(x, y)
292
306
  }
293
307
 
294
308
  export function Mul32(x: number, y: number): [number, number] {
@@ -301,6 +315,7 @@ export function Mul32(x: number, y: number): [number, number] {
301
315
 
302
316
  export function Mul64(x: number, y: number): [number, number]
303
317
  export function Mul64(x: bigint, y: bigint): [bigint, bigint]
318
+ export function Mul64(x: Word64, y: Word64): [number, number]
304
319
  export function Mul64(x: Word64, y: Word64): [Word64, Word64] {
305
320
  const useBigInt = useBigIntResult(x, y)
306
321
  x = toUint64(x)
@@ -309,15 +324,15 @@ export function Mul64(x: Word64, y: Word64): [Word64, Word64] {
309
324
  const lo = product & uint64Mask
310
325
  const hi = product >> 64n
311
326
 
312
- return [
313
- word64Result(hi & uint64Mask, useBigInt),
314
- word64Result(lo, useBigInt),
315
- ]
327
+ return [word64Result(hi & uint64Mask, useBigInt), word64Result(lo, useBigInt)]
316
328
  }
317
329
 
318
330
  // --- Division functions ---
319
- export function Div(hi: number, lo: number, y: number): [number, number] {
320
- return Div32(hi, lo, y)
331
+ export function Div(hi: number, lo: number, y: number): [number, number]
332
+ export function Div(hi: bigint, lo: bigint, y: bigint): [bigint, bigint]
333
+ export function Div(hi: Word64, lo: Word64, y: Word64): [number, number]
334
+ export function Div(hi: Word64, lo: Word64, y: Word64): [Word64, Word64] {
335
+ return Div64(hi, lo, y)
321
336
  }
322
337
 
323
338
  export function Div32(hi: number, lo: number, y: number): [number, number] {
@@ -337,6 +352,7 @@ export function Div32(hi: number, lo: number, y: number): [number, number] {
337
352
 
338
353
  export function Div64(hi: number, lo: number, y: number): [number, number]
339
354
  export function Div64(hi: bigint, lo: bigint, y: bigint): [bigint, bigint]
355
+ export function Div64(hi: Word64, lo: Word64, y: Word64): [number, number]
340
356
  export function Div64(hi: Word64, lo: Word64, y: Word64): [Word64, Word64] {
341
357
  const useBigInt = useBigIntResult(hi, lo, y)
342
358
  hi = toUint64(hi)
@@ -356,8 +372,11 @@ export function Div64(hi: Word64, lo: Word64, y: Word64): [Word64, Word64] {
356
372
  }
357
373
 
358
374
  // --- Add and Sub with carry ---
359
- export function Add(x: number, y: number, carry: number): [number, number] {
360
- return Add32(x, y, carry)
375
+ export function Add(x: number, y: number, carry: number): [number, number]
376
+ export function Add(x: bigint, y: bigint, carry: bigint): [bigint, bigint]
377
+ export function Add(x: Word64, y: Word64, carry: Word64): [number, number]
378
+ export function Add(x: Word64, y: Word64, carry: Word64): [Word64, Word64] {
379
+ return Add64(x, y, carry)
361
380
  }
362
381
 
363
382
  export function Add32(x: number, y: number, carry: number): [number, number] {
@@ -369,6 +388,7 @@ export function Add32(x: number, y: number, carry: number): [number, number] {
369
388
 
370
389
  export function Add64(x: number, y: number, carry: number): [number, number]
371
390
  export function Add64(x: bigint, y: bigint, carry: bigint): [bigint, bigint]
391
+ export function Add64(x: Word64, y: Word64, carry: Word64): [number, number]
372
392
  export function Add64(x: Word64, y: Word64, carry: Word64): [Word64, Word64] {
373
393
  const useBigInt = useBigIntResult(x, y, carry)
374
394
  const sum = toUint64(x) + toUint64(y) + toUint64(carry)
@@ -377,8 +397,11 @@ export function Add64(x: Word64, y: Word64, carry: Word64): [Word64, Word64] {
377
397
  return [word64Result(result, useBigInt), word64Result(carryOut, useBigInt)]
378
398
  }
379
399
 
380
- export function Sub(x: number, y: number, borrow: number): [number, number] {
381
- return Sub32(x, y, borrow)
400
+ export function Sub(x: number, y: number, borrow: number): [number, number]
401
+ export function Sub(x: bigint, y: bigint, borrow: bigint): [bigint, bigint]
402
+ export function Sub(x: Word64, y: Word64, borrow: Word64): [number, number]
403
+ export function Sub(x: Word64, y: Word64, borrow: Word64): [Word64, Word64] {
404
+ return Sub64(x, y, borrow)
382
405
  }
383
406
 
384
407
  export function Sub32(x: number, y: number, borrow: number): [number, number] {
@@ -390,6 +413,7 @@ export function Sub32(x: number, y: number, borrow: number): [number, number] {
390
413
 
391
414
  export function Sub64(x: number, y: number, borrow: number): [number, number]
392
415
  export function Sub64(x: bigint, y: bigint, borrow: bigint): [bigint, bigint]
416
+ export function Sub64(x: Word64, y: Word64, borrow: Word64): [number, number]
393
417
  export function Sub64(x: Word64, y: Word64, borrow: Word64): [Word64, Word64] {
394
418
  const useBigInt = useBigIntResult(x, y, borrow)
395
419
  const diff = toUint64(x) - toUint64(y) - toUint64(borrow)
@@ -72,6 +72,22 @@ describe('net/http override', () => {
72
72
  expect(err?.Error()).toBe('net/http: Client.Do is not implemented in GoScript')
73
73
  })
74
74
 
75
+ it('wraps request body readers and keeps response metadata', () => {
76
+ const reader = {
77
+ Read: (p: Uint8Array) => [p.length, null] as [number, null],
78
+ }
79
+
80
+ const [req, reqErr] = NewRequest(MethodPost, 'https://example.invalid/upload', reader)
81
+
82
+ expect(reqErr).toBeNull()
83
+ expect(req!.Body).not.toBeNull()
84
+ expect(req!.Body!.Close()).toBeNull()
85
+
86
+ const resp = new Response({ StatusCode: StatusCreated, ContentLength: -1, Request: varRef(req!) })
87
+ expect(resp.ContentLength).toBe(-1)
88
+ expect((resp.Request as any).value).toBe(req)
89
+ })
90
+
75
91
  it('exports the default transport surface', async () => {
76
92
  const [req] = NewRequest(MethodPost, 'https://example.invalid', null)
77
93
 
@@ -259,7 +259,7 @@ export interface ResponseWriter {
259
259
  export class Request {
260
260
  public Method: string
261
261
  public URL: any
262
- public Body: io.Reader | null
262
+ public Body: io.ReadCloser | null
263
263
  public Header: Header
264
264
  public ContentLength: number
265
265
  public RequestURI: string
@@ -313,12 +313,16 @@ export class Response {
313
313
  public StatusCode: number
314
314
  public Body: io.ReadCloser | null
315
315
  public Header: Header
316
+ public ContentLength: number
317
+ public Request: Request | $.VarRef<Request> | null
316
318
 
317
319
  constructor(init?: Partial<Response>) {
318
320
  this.Status = init?.Status ?? ''
319
321
  this.StatusCode = init?.StatusCode ?? 0
320
322
  this.Body = init?.Body ?? null
321
323
  this.Header = init?.Header ?? new Header()
324
+ this.ContentLength = init?.ContentLength ?? 0
325
+ this.Request = init?.Request ?? null
322
326
  if (this.Status === '' && this.StatusCode !== 0) {
323
327
  const text = StatusText(this.StatusCode)
324
328
  this.Status = text === '' ? String(this.StatusCode) : `${this.StatusCode} ${text}`
@@ -331,6 +335,8 @@ export class Response {
331
335
  Header: this.Header,
332
336
  Status: this.Status,
333
337
  StatusCode: this.StatusCode,
338
+ ContentLength: this.ContentLength,
339
+ Request: this.Request,
334
340
  })
335
341
  }
336
342
  }
@@ -573,9 +579,20 @@ export function NewRequestWithContext(
573
579
  method = MethodGet
574
580
  }
575
581
  const parsedURL = parseRequestURL(url)
576
- return [new Request({ Method: method, URL: parsedURL, Body: body, RequestURI: parsedURL.Path, ctx: _ctx }), null]
582
+ return [new Request({ Method: method, URL: parsedURL, Body: readCloserForBody(body), RequestURI: parsedURL.Path, ctx: _ctx }), null]
577
583
  }
578
584
 
579
585
  export function Get(_url: string): [Response | null, $.GoError] {
580
586
  return [null, errors.New('net/http: Get is not implemented in GoScript')]
581
587
  }
588
+
589
+ function readCloserForBody(body: io.Reader | null): io.ReadCloser | null {
590
+ if (body == null) {
591
+ return null
592
+ }
593
+ const closer = body as io.Reader & Partial<io.Closer>
594
+ if (typeof closer.Close === 'function') {
595
+ return closer as io.ReadCloser
596
+ }
597
+ return io.NopCloser(body)
598
+ }
@@ -286,4 +286,56 @@ describe('os stdio', () => {
286
286
  expect(readSync).toHaveBeenCalledTimes(1)
287
287
  expect(writeSync).toHaveBeenCalledTimes(1)
288
288
  })
289
+
290
+ it('copies from File without recursing through io.Copy', async () => {
291
+ const readSync = vi
292
+ .fn<(buffer: Uint8Array) => number>()
293
+ .mockImplementationOnce((buffer) => {
294
+ buffer.set([65, 66, 67], 0)
295
+ return 3
296
+ })
297
+ .mockImplementationOnce(() => 0)
298
+
299
+ const file = createHostFile('descriptor-file', 7, { readSync })
300
+ const chunks: number[] = []
301
+ const writer = {
302
+ Write(p: Uint8Array): [number, null] {
303
+ chunks.push(...Array.from(p))
304
+ return [p.length, null]
305
+ },
306
+ }
307
+
308
+ const [n, err] = await io.Copy(writer, file)
309
+
310
+ expect(err).toBeNull()
311
+ expect(n).toBe(3)
312
+ expect(Buffer.from(chunks).toString('utf8')).toBe('ABC')
313
+ })
314
+
315
+ it('copies into File without recursing through io.Copy', async () => {
316
+ const writes: number[] = []
317
+ const writeSync = vi.fn((buffer: Uint8Array) => {
318
+ writes.push(...Array.from(buffer))
319
+ return buffer.length
320
+ })
321
+
322
+ let sent = false
323
+ const reader = {
324
+ Read(p: Uint8Array): [number, typeof io.EOF | null] {
325
+ if (sent) {
326
+ return [0, io.EOF]
327
+ }
328
+ sent = true
329
+ p.set([88, 89, 90], 0)
330
+ return [3, null]
331
+ },
332
+ }
333
+ const file = createHostFile('descriptor-file', 7, { writeSync })
334
+
335
+ const [n, err] = await io.Copy(file, reader)
336
+
337
+ expect(err).toBeNull()
338
+ expect(n).toBe(3)
339
+ expect(Buffer.from(writes).toString('utf8')).toBe('XYZ')
340
+ })
289
341
  })
package/gs/os/meta.json CHANGED
@@ -1,4 +1,8 @@
1
1
  {
2
+ "asyncMethods": {
3
+ "File.ReadFrom": true,
4
+ "File.WriteTo": true
5
+ },
2
6
  "dependencies": [
3
7
  "errors",
4
8
  "internal/byteorder",