goscript 0.0.38 → 0.0.40

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 (180) hide show
  1. package/compiler/analysis.go +15 -6
  2. package/compiler/compiler.go +184 -34
  3. package/compiler/expr-call.go +19 -9
  4. package/compiler/field.go +17 -3
  5. package/compiler/gs_dependencies_test.go +80 -0
  6. package/compiler/lit.go +12 -6
  7. package/compiler/output.go +10 -4
  8. package/compiler/spec.go +15 -2
  9. package/compiler/type-assert.go +111 -21
  10. package/compiler/type.go +37 -8
  11. package/dist/gs/builtin/builtin.d.ts +55 -0
  12. package/dist/gs/builtin/builtin.js +213 -0
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/slice.js +13 -0
  15. package/dist/gs/builtin/slice.js.map +1 -1
  16. package/dist/gs/bytes/buffer.gs.d.ts +56 -0
  17. package/dist/gs/bytes/buffer.gs.js +611 -0
  18. package/dist/gs/bytes/buffer.gs.js.map +1 -0
  19. package/dist/gs/bytes/bytes.gs.d.ts +78 -0
  20. package/dist/gs/bytes/bytes.gs.js +1107 -0
  21. package/dist/gs/bytes/bytes.gs.js.map +1 -0
  22. package/dist/gs/bytes/index.d.ts +4 -0
  23. package/dist/gs/bytes/index.js +5 -0
  24. package/dist/gs/bytes/index.js.map +1 -0
  25. package/dist/gs/bytes/iter.gs.d.ts +9 -0
  26. package/dist/gs/bytes/iter.gs.js +143 -0
  27. package/dist/gs/bytes/iter.gs.js.map +1 -0
  28. package/dist/gs/bytes/reader.gs.d.ts +34 -0
  29. package/dist/gs/bytes/reader.gs.js +198 -0
  30. package/dist/gs/bytes/reader.gs.js.map +1 -0
  31. package/dist/gs/fmt/fmt.d.ts +49 -0
  32. package/dist/gs/fmt/fmt.js +322 -0
  33. package/dist/gs/fmt/fmt.js.map +1 -0
  34. package/dist/gs/fmt/index.d.ts +1 -0
  35. package/dist/gs/fmt/index.js +2 -0
  36. package/dist/gs/fmt/index.js.map +1 -0
  37. package/dist/gs/internal/bytealg/index.d.ts +14 -2
  38. package/dist/gs/internal/bytealg/index.js +114 -8
  39. package/dist/gs/internal/bytealg/index.js.map +1 -1
  40. package/dist/gs/path/filepath/index.d.ts +3 -0
  41. package/dist/gs/path/filepath/index.js +3 -0
  42. package/dist/gs/path/filepath/index.js.map +1 -0
  43. package/dist/gs/path/filepath/match.d.ts +3 -0
  44. package/dist/gs/path/filepath/match.js +212 -0
  45. package/dist/gs/path/filepath/match.js.map +1 -0
  46. package/dist/gs/path/filepath/path.d.ts +25 -0
  47. package/dist/gs/path/filepath/path.js +265 -0
  48. package/dist/gs/path/filepath/path.js.map +1 -0
  49. package/dist/gs/reflect/deepequal.d.ts +2 -1
  50. package/dist/gs/reflect/deepequal.js +5 -53
  51. package/dist/gs/reflect/deepequal.js.map +1 -1
  52. package/dist/gs/reflect/map.d.ts +14 -8
  53. package/dist/gs/reflect/map.js +15 -11
  54. package/dist/gs/reflect/map.js.map +1 -1
  55. package/dist/gs/reflect/type.d.ts +17 -9
  56. package/dist/gs/reflect/type.js +1 -1
  57. package/dist/gs/reflect/type.js.map +1 -1
  58. package/dist/gs/reflect/value.js +15 -6
  59. package/dist/gs/reflect/value.js.map +1 -1
  60. package/dist/gs/reflect/visiblefields.js +18 -12
  61. package/dist/gs/reflect/visiblefields.js.map +1 -1
  62. package/dist/gs/sort/index.d.ts +4 -0
  63. package/dist/gs/sort/index.js +4 -0
  64. package/dist/gs/sort/index.js.map +1 -0
  65. package/dist/gs/sort/search.gs.d.ts +6 -0
  66. package/dist/gs/sort/search.gs.js +125 -0
  67. package/dist/gs/sort/search.gs.js.map +1 -0
  68. package/dist/gs/sort/slice.gs.d.ts +4 -0
  69. package/dist/gs/sort/slice.gs.js +49 -0
  70. package/dist/gs/sort/slice.gs.js.map +1 -0
  71. package/dist/gs/sort/sort.gs.d.ts +37 -0
  72. package/dist/gs/sort/sort.gs.js +203 -0
  73. package/dist/gs/sort/sort.gs.js.map +1 -0
  74. package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
  75. package/dist/gs/unicode/utf8/utf8.js +4 -2
  76. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  77. package/gs/builtin/builtin.ts +236 -0
  78. package/gs/builtin/slice.ts +17 -1
  79. package/gs/bytes/buffer.gs.ts +614 -0
  80. package/gs/bytes/bytes.gs.ts +1288 -0
  81. package/gs/bytes/godoc.txt +69 -0
  82. package/gs/bytes/index.ts +69 -0
  83. package/gs/bytes/iter.gs.ts +149 -0
  84. package/gs/bytes/metadata.go +12 -0
  85. package/gs/bytes/reader.gs.ts +230 -0
  86. package/gs/fmt/fmt.ts +407 -0
  87. package/gs/fmt/godoc.txt +382 -0
  88. package/gs/fmt/index.ts +31 -0
  89. package/gs/fmt/metadata.go +7 -0
  90. package/gs/internal/bytealg/index.ts +125 -10
  91. package/gs/internal/metadata.go +7 -0
  92. package/gs/io/metadata.go +11 -0
  93. package/gs/maps/metadata.go +8 -0
  94. package/gs/math/metadata.go +7 -0
  95. package/gs/os/metadata.go +17 -0
  96. package/gs/path/filepath/godoc.txt +35 -0
  97. package/gs/path/filepath/index.ts +27 -0
  98. package/gs/path/filepath/match.test.ts +274 -0
  99. package/gs/path/filepath/match.ts +249 -0
  100. package/gs/path/filepath/path.test.ts +246 -0
  101. package/gs/path/filepath/path.ts +328 -0
  102. package/gs/path/metadata.go +8 -0
  103. package/gs/reflect/deepequal.test.ts +41 -0
  104. package/gs/reflect/deepequal.ts +19 -4
  105. package/gs/reflect/map.test.ts +30 -0
  106. package/gs/reflect/map.ts +22 -18
  107. package/gs/reflect/metadata.go +7 -0
  108. package/gs/reflect/type.ts +19 -15
  109. package/gs/reflect/value.ts +21 -7
  110. package/gs/reflect/visiblefields.ts +17 -13
  111. package/gs/sort/godoc.txt +27 -0
  112. package/gs/sort/index.ts +24 -0
  113. package/gs/sort/search.gs.ts +128 -0
  114. package/gs/sort/slice.gs.ts +59 -0
  115. package/gs/sort/sort.gs.ts +227 -0
  116. package/gs/strconv/metadata.go +7 -0
  117. package/gs/strings/metadata.go +11 -0
  118. package/gs/sync/metadata.go +7 -0
  119. package/gs/unicode/utf8/utf8.ts +8 -5
  120. package/package.json +1 -1
  121. package/dist/gs/internal/testlog/index.d.ts +0 -1
  122. package/dist/gs/internal/testlog/index.js +0 -5
  123. package/dist/gs/internal/testlog/index.js.map +0 -1
  124. package/dist/gs/maps/iter.gs.d.ts +0 -7
  125. package/dist/gs/maps/iter.gs.js +0 -65
  126. package/dist/gs/maps/iter.gs.js.map +0 -1
  127. package/dist/gs/maps/maps.gs.d.ts +0 -7
  128. package/dist/gs/maps/maps.gs.js +0 -79
  129. package/dist/gs/maps/maps.gs.js.map +0 -1
  130. package/dist/gs/reflect/abi.d.ts +0 -59
  131. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  132. package/dist/gs/reflect/abi.gs.js +0 -79
  133. package/dist/gs/reflect/abi.gs.js.map +0 -1
  134. package/dist/gs/reflect/abi.js +0 -79
  135. package/dist/gs/reflect/abi.js.map +0 -1
  136. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  137. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  138. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  139. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  140. package/dist/gs/reflect/badlinkname.js +0 -72
  141. package/dist/gs/reflect/badlinkname.js.map +0 -1
  142. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  143. package/dist/gs/reflect/deepequal.gs.js +0 -308
  144. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  145. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  146. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  147. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  148. package/dist/gs/reflect/index.gs.d.ts +0 -1
  149. package/dist/gs/reflect/index.gs.js +0 -3
  150. package/dist/gs/reflect/index.gs.js.map +0 -1
  151. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  152. package/dist/gs/reflect/iter.gs.js +0 -24
  153. package/dist/gs/reflect/iter.gs.js.map +0 -1
  154. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  155. package/dist/gs/reflect/makefunc.gs.js +0 -288
  156. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  157. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  158. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  159. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  160. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  161. package/dist/gs/reflect/reflect.gs.js +0 -437
  162. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  163. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  164. package/dist/gs/reflect/swapper.gs.js +0 -32
  165. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  166. package/dist/gs/reflect/type.gs.d.ts +0 -4
  167. package/dist/gs/reflect/type.gs.js +0 -21
  168. package/dist/gs/reflect/type.gs.js.map +0 -1
  169. package/dist/gs/reflect/value.gs.d.ts +0 -4
  170. package/dist/gs/reflect/value.gs.js +0 -12
  171. package/dist/gs/reflect/value.gs.js.map +0 -1
  172. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  173. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  174. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  175. package/dist/gs/stringslite/index.d.ts +0 -1
  176. package/dist/gs/stringslite/index.js +0 -2
  177. package/dist/gs/stringslite/index.js.map +0 -1
  178. package/dist/gs/stringslite/strings.d.ts +0 -11
  179. package/dist/gs/stringslite/strings.js +0 -67
  180. package/dist/gs/stringslite/strings.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { MapIter } from './map.js'
3
+
4
+ describe('MapIter', () => {
5
+ it('should iterate over map entries with proper typing', () => {
6
+ const map = new Map<string, number>()
7
+ map.set('one', 1)
8
+ map.set('two', 2)
9
+ map.set('three', 3)
10
+
11
+ const iter = new MapIter<string, number>(map)
12
+
13
+ expect(iter.current?.done === false).toBe(true)
14
+ expect(iter.Key()).toBe('one')
15
+ expect(iter.Value()).toBe(1)
16
+
17
+ expect(iter.Next()).toBe(true)
18
+ expect(iter.current?.done === false).toBe(true)
19
+ expect(typeof iter.Key()).toBe('string')
20
+ expect(typeof iter.Value()).toBe('number')
21
+
22
+ const newMap = new Map<string, number>()
23
+ newMap.set('reset', 100)
24
+ iter.Reset(newMap)
25
+
26
+ expect(iter.current?.done === false).toBe(true)
27
+ expect(iter.Key()).toBe('reset')
28
+ expect(iter.Value()).toBe(100)
29
+ })
30
+ })
package/gs/reflect/map.ts CHANGED
@@ -37,35 +37,39 @@ class MapType implements Type {
37
37
  }
38
38
  }
39
39
 
40
- // Simple map iterator using JavaScript Map
41
- export class MapIter {
42
- private iterator: Iterator<[any, any]>
43
- private currentEntry: IteratorResult<[any, any]> | null = null
44
-
45
- constructor(private map: Map<any, any>) {
40
+ /**
41
+ * MapIter provides an iterator interface for Go maps.
42
+ * It wraps a JavaScript Map iterator and provides methods to iterate over key-value pairs.
43
+ * @template K - The type of keys in the map
44
+ * @template V - The type of values in the map
45
+ */
46
+ export class MapIter<K = unknown, V = unknown> {
47
+ public iterator: Iterator<[K, V]>
48
+ public current: IteratorResult<[K, V]> | null = null
49
+
50
+ constructor(public map: Map<K, V>) {
46
51
  this.iterator = map.entries()
47
52
  this.Next()
48
53
  }
49
54
 
50
55
  public Next(): boolean {
51
- this.currentEntry = this.iterator.next()
52
- return !this.currentEntry.done
56
+ this.current = this.iterator.next()
57
+ return !this.current.done
53
58
  }
54
59
 
55
- public Key(): any {
56
- return this.currentEntry?.value?.[0]
60
+ public Key(): K | null {
61
+ return this.current?.value?.[0] ?? null
57
62
  }
58
63
 
59
- public Value(): any {
60
- return this.currentEntry?.value?.[1]
64
+ public Value(): V | null {
65
+ return this.current?.value?.[1] ?? null
61
66
  }
62
67
 
63
- public Reset(m: any): void {
64
- if (m instanceof Map) {
65
- this.map = m
66
- this.iterator = m.entries()
67
- this.Next()
68
- }
68
+ public Reset(m: Map<K, V>): void {
69
+ this.map = m
70
+ this.iterator = m.entries()
71
+ this.current = null
72
+ this.Next()
69
73
  }
70
74
  }
71
75
 
@@ -0,0 +1,7 @@
1
+ package reflect
2
+
3
+ // GsDependencies lists the import paths that this gs/ package requires
4
+ // These dependencies will be automatically copied when this package is included
5
+ var GsDependencies = []string{
6
+ "iter",
7
+ }
@@ -1,4 +1,5 @@
1
- import { ReflectValue, ChanDir } from './types.js'
1
+ import { ReflectValue, ChanDir, StructField } from './types.js'
2
+ import { MapIter } from './map.js'
2
3
 
3
4
  // rtype is the common implementation of most values
4
5
  export class rtype {
@@ -181,7 +182,7 @@ export interface Type {
181
182
  PkgPath?(): string
182
183
 
183
184
  // Field returns a struct type's i'th field.
184
- Field?(i: number): any
185
+ Field?(i: number): StructField | null
185
186
 
186
187
  // common returns the common type implementation.
187
188
  common?(): rtype
@@ -351,15 +352,15 @@ export class Value {
351
352
  }
352
353
 
353
354
  // Additional methods needed by various parts of the codebase
354
- public UnsafePointer(): any {
355
+ public UnsafePointer(): unknown {
355
356
  return this._value
356
357
  }
357
358
 
358
- public pointer(): any {
359
+ public pointer(): unknown {
359
360
  return this._value
360
361
  }
361
362
 
362
- public get ptr(): any {
363
+ public get ptr(): unknown {
363
364
  return this._value
364
365
  }
365
366
 
@@ -383,7 +384,7 @@ export class Value {
383
384
  return 0
384
385
  }
385
386
 
386
- public MapRange(): any {
387
+ public MapRange(): MapIter<unknown, unknown> | null {
387
388
  // Placeholder for map iteration
388
389
  return null
389
390
  }
@@ -393,9 +394,9 @@ export class Value {
393
394
  return new Value(null, new BasicType(Invalid, 'invalid'))
394
395
  }
395
396
 
396
- public Complex(): any {
397
+ public Complex(): number | { real: number; imag: number } | null {
397
398
  // Placeholder for complex number support
398
- return this._value
399
+ return this._value as number | { real: number; imag: number } | null
399
400
  }
400
401
 
401
402
  // Send sends a value to a channel
@@ -459,7 +460,7 @@ export class BasicType implements Type {
459
460
  return ''
460
461
  }
461
462
 
462
- public Field?(_i: number): any {
463
+ public Field?(_i: number): StructField | null {
463
464
  return null
464
465
  }
465
466
 
@@ -532,7 +533,7 @@ class ArrayType implements Type {
532
533
  return ''
533
534
  }
534
535
 
535
- public Field?(_i: number): any {
536
+ public Field?(_i: number): StructField | null {
536
537
  return null
537
538
  }
538
539
 
@@ -569,7 +570,7 @@ class PointerType implements Type {
569
570
  return ''
570
571
  }
571
572
 
572
- public Field?(_i: number): any {
573
+ public Field?(_i: number): StructField | null {
573
574
  return null
574
575
  }
575
576
 
@@ -606,7 +607,7 @@ class FunctionType implements Type {
606
607
  return ''
607
608
  }
608
609
 
609
- public Field?(_i: number): any {
610
+ public Field?(_i: number): StructField | null {
610
611
  return null
611
612
  }
612
613
 
@@ -650,7 +651,7 @@ class MapType implements Type {
650
651
  return ''
651
652
  }
652
653
 
653
- public Field?(_i: number): any {
654
+ public Field?(_i: number): StructField | null {
654
655
  return null
655
656
  }
656
657
 
@@ -780,7 +781,7 @@ function getTypeOf(value: ReflectValue): Type {
780
781
  if (funcWithMeta.__typeInfo) {
781
782
  const typeInfo = funcWithMeta.__typeInfo
782
783
  if (
783
- typeInfo.kind === 'function' &&
784
+ (typeInfo.kind === 'function' || typeInfo.kind === 'Function') &&
784
785
  typeInfo.params &&
785
786
  typeInfo.results
786
787
  ) {
@@ -1003,7 +1004,10 @@ export function canRangeFunc2(t: Type): boolean {
1003
1004
  return kind === 21 // map
1004
1005
  }
1005
1006
 
1006
- export function funcLayout(_t: Type, _rcvr: Type | null): any {
1007
+ export function funcLayout(
1008
+ _t: Type,
1009
+ _rcvr: Type | null,
1010
+ ): { Type: Type | null; InCount: number; OutCount: number } {
1007
1011
  return {
1008
1012
  Type: null,
1009
1013
  InCount: 0,
@@ -28,6 +28,11 @@ import {
28
28
  import { ReflectValue, SelectCase, SelectRecv, SelectDefault } from './types.js'
29
29
  import * as $ from '@goscript/builtin/builtin.js'
30
30
 
31
+ interface ChannelObject {
32
+ _sendQueue?: unknown[]
33
+ send?: (value: unknown) => void
34
+ }
35
+
31
36
  // Re-export ValueOf from type.ts for compatibility
32
37
  export { ValueOf } from './type'
33
38
 
@@ -205,11 +210,19 @@ export function MakeChan(typ: Type, buffer: number): Value {
205
210
  export function Select(cases: $.Slice<SelectCase>): [number, Value, boolean] {
206
211
  // Extract the backing array from the GoScript slice
207
212
  let selectCases: SelectCase[] = []
208
- if (cases && typeof cases === 'object' && '__meta__' in cases) {
209
- // This is a GoScript slice, extract the backing array
210
- const meta = (cases as { __meta__?: { backing?: SelectCase[] } }).__meta__
211
- if (meta && meta.backing) {
212
- selectCases = meta.backing
213
+
214
+ if (cases && typeof cases === 'object') {
215
+ if ('__meta__' in cases) {
216
+ // This is a GoScript SliceProxy, extract the backing array
217
+ const meta = (cases as { __meta__?: { backing?: SelectCase[], offset?: number, length?: number } }).__meta__
218
+ if (meta && meta.backing) {
219
+ const offset = meta.offset ?? 0
220
+ const length = meta.length ?? meta.backing.length
221
+ selectCases = meta.backing.slice(offset, offset + length)
222
+ }
223
+ } else if (globalThis.Array.isArray(cases)) {
224
+ // This is a plain array (optimized case where offset=0 and length=capacity)
225
+ selectCases = cases as SelectCase[]
213
226
  }
214
227
  }
215
228
 
@@ -218,7 +231,8 @@ export function Select(cases: $.Slice<SelectCase>): [number, Value, boolean] {
218
231
  const selectCase = selectCases[i]
219
232
  if (selectCase.Dir.valueOf() === SelectRecv.valueOf() && selectCase.Chan) {
220
233
  const channelValue = selectCase.Chan
221
- const channelObj = (channelValue as unknown as { value: any }).value
234
+ const channelObj = (channelValue as unknown as { value: unknown })
235
+ .value as ChannelObject
222
236
 
223
237
  // Check if there are queued values to receive
224
238
  if (
@@ -226,7 +240,7 @@ export function Select(cases: $.Slice<SelectCase>): [number, Value, boolean] {
226
240
  channelObj._sendQueue &&
227
241
  channelObj._sendQueue.length > 0
228
242
  ) {
229
- const receivedValue = channelObj._sendQueue.shift() // Remove from queue
243
+ const receivedValue = channelObj._sendQueue.shift() as ReflectValue // Remove from queue
230
244
  const elemType = channelValue.Type().Elem()
231
245
  if (elemType) {
232
246
  const recvVal = new Value(receivedValue, elemType)
@@ -1,5 +1,5 @@
1
1
  import * as $ from '@goscript/builtin/builtin.js'
2
- import { Type } from './type.js'
2
+ import { Type, Ptr, Struct } from './type.js'
3
3
  import { StructField } from './types.js'
4
4
 
5
5
  // VisibleFields returns all the visible fields in t, which must be a
@@ -127,20 +127,24 @@ class visibleFieldsWalker {
127
127
  }
128
128
  $.mapSet(w.visiting, t, true)
129
129
  for (let i = 0; i < t!.NumField!(); i++) {
130
- let f = t!.Field!(i).clone()
131
- f.Index = $.append(null, w.index) as number[]
132
- if (f.Anonymous) {
133
- if (f.Type!.Kind().valueOf() == 22) {
134
- const elemType = f.Type!.Elem!()
135
- if (elemType) {
136
- f.Type = elemType
130
+ if (!t!.Field) continue
131
+ const field = t!.Field(i)
132
+ if (field) {
133
+ const f = field.clone()
134
+ f.Index = $.append(null, w.index) as number[]
135
+ if (f.Anonymous) {
136
+ if (f.Type && f.Type.Kind().valueOf() === Ptr.valueOf()) {
137
+ const elemType = f.Type.Elem!()
138
+ if (elemType) {
139
+ f.Type = elemType
140
+ }
137
141
  }
142
+ if (f.Type && f.Type.Kind().valueOf() === Struct.valueOf()) {
143
+ w.walk(f.Type)
144
+ }
145
+ } else {
146
+ w.fields = $.append(w.fields, f)
138
147
  }
139
- if (f.Type!.Kind().valueOf() == 25) {
140
- w.walk(f.Type)
141
- }
142
- } else {
143
- w.fields = $.append(w.fields, f)
144
148
  }
145
149
  }
146
150
  $.deleteMapEntry(w.visiting, t)
@@ -0,0 +1,27 @@
1
+ package sort // import "sort"
2
+
3
+ Package sort provides primitives for sorting slices and user-defined
4
+ collections.
5
+
6
+ func Find(n int, cmp func(int) int) (i int, found bool)
7
+ func Float64s(x []float64)
8
+ func Float64sAreSorted(x []float64) bool
9
+ func Ints(x []int)
10
+ func IntsAreSorted(x []int) bool
11
+ func IsSorted(data Interface) bool
12
+ func Search(n int, f func(int) bool) int
13
+ func SearchFloat64s(a []float64, x float64) int
14
+ func SearchInts(a []int, x int) int
15
+ func SearchStrings(a []string, x string) int
16
+ func Slice(x any, less func(i, j int) bool)
17
+ func SliceIsSorted(x any, less func(i, j int) bool) bool
18
+ func SliceStable(x any, less func(i, j int) bool)
19
+ func Sort(data Interface)
20
+ func Stable(data Interface)
21
+ func Strings(x []string)
22
+ func StringsAreSorted(x []string) bool
23
+ type Float64Slice []float64
24
+ type IntSlice []int
25
+ type Interface interface{ ... }
26
+ func Reverse(data Interface) Interface
27
+ type StringSlice []string
@@ -0,0 +1,24 @@
1
+ export {
2
+ Find,
3
+ Search,
4
+ SearchFloat64s,
5
+ SearchInts,
6
+ SearchStrings,
7
+ } from './search.gs'
8
+ export { Slice, SliceIsSorted, SliceStable } from './slice.gs'
9
+ export {
10
+ Float64Slice,
11
+ Float64s,
12
+ Float64sAreSorted,
13
+ IntSlice,
14
+ Ints,
15
+ IntsAreSorted,
16
+ IsSorted,
17
+ Reverse,
18
+ Sort,
19
+ Stable,
20
+ StringSlice,
21
+ Strings,
22
+ StringsAreSorted,
23
+ } from './sort.gs'
24
+ export type { Interface } from './sort.gs'
@@ -0,0 +1,128 @@
1
+ import * as $ from "@goscript/builtin/builtin.js";
2
+
3
+ // Search uses binary search to find and return the smallest index i
4
+ // in [0, n) at which f(i) is true, assuming that on the range [0, n),
5
+ // f(i) == true implies f(i+1) == true. That is, Search requires that
6
+ // f is false for some (possibly empty) prefix of the input range [0, n)
7
+ // and then true for the (possibly empty) remainder; Search returns
8
+ // the first true index. If there is no such index, Search returns n.
9
+ // (Note that the "not found" return value is not -1 as in, for instance,
10
+ // strings.Index.)
11
+ // Search calls f(i) only for i in the range [0, n).
12
+ //
13
+ // A common use of Search is to find the index i for a value x in
14
+ // a sorted, indexable data structure such as an array or slice.
15
+ // In this case, the argument f, typically a closure, captures the value
16
+ // to be searched for, and how the data structure is indexed and
17
+ // ordered.
18
+ //
19
+ // For instance, given a slice data sorted in ascending order,
20
+ // the call Search(len(data), func(i int) bool { return data[i] >= 23 })
21
+ // returns the smallest index i such that data[i] >= 23. If the caller
22
+ // wants to find whether 23 is in the slice, it must test data[i] == 23
23
+ // separately.
24
+ //
25
+ // Searching data sorted in descending order would use the <=
26
+ // operator instead of the >= operator.
27
+ //
28
+ // To complete the example above, the following code tries to find the value
29
+ // x in an integer slice data sorted in ascending order:
30
+ //
31
+ // x := 23
32
+ // i := sort.Search(len(data), func(i int) bool { return data[i] >= x })
33
+ // if i < len(data) && data[i] == x {
34
+ // // x is present at data[i]
35
+ // } else {
36
+ // // x is not present in data,
37
+ // // but i is the index where it would be inserted.
38
+ // }
39
+ //
40
+ // As a more whimsical example, this program guesses your number:
41
+ //
42
+ // func GuessingGame() {
43
+ // var s string
44
+ // fmt.Printf("Pick an integer from 0 to 100.\n")
45
+ // answer := sort.Search(100, func(i int) bool {
46
+ // fmt.Printf("Is your number <= %d? ", i)
47
+ // fmt.Scanf("%s", &s)
48
+ // return s != "" && s[0] == 'y'
49
+ // })
50
+ // fmt.Printf("Your number is %d.\n", answer)
51
+ // }
52
+ export function Search(n: number, f: (i: number) => boolean): number {
53
+ let left = 0
54
+ let right = n
55
+ while (left < right) {
56
+ const mid = Math.floor((left + right) / 2)
57
+ if (f(mid)) {
58
+ right = mid
59
+ } else {
60
+ left = mid + 1
61
+ }
62
+ }
63
+ return left
64
+ }
65
+
66
+ // Find uses binary search to find and return the smallest index i in [0, n)
67
+ // at which cmp(i) <= 0. If there is no such index i, Find returns i = n.
68
+ // The found result is true if i < n and cmp(i) == 0.
69
+ // Find calls cmp(i) only for i in the range [0, n).
70
+ //
71
+ // To permit binary search, Find requires that cmp(i) > 0 for a leading
72
+ // prefix of the range, cmp(i) == 0 in the middle, and cmp(i) < 0 for
73
+ // the final suffix of the range. (Each subrange could be empty.)
74
+ // The usual way to establish this condition is to interpret cmp(i)
75
+ // as a comparison of a desired target value t against entry i in an
76
+ // underlying indexed data structure x, returning <0, 0, and >0
77
+ // when t < x[i], t == x[i], and t > x[i], respectively.
78
+ //
79
+ // For example, to look for a particular string in a sorted, random-access
80
+ // list of strings:
81
+ //
82
+ // i, found := sort.Find(x.Len(), func(i int) int {
83
+ // return strings.Compare(target, x.At(i))
84
+ // })
85
+ // if found {
86
+ // fmt.Printf("found %s at entry %d\n", target, i)
87
+ // } else {
88
+ // fmt.Printf("%s not found, would insert at %d", target, i)
89
+ // }
90
+ export function Find(n: number, cmp: (i: number) => number): [number, boolean] {
91
+ let left = 0
92
+ let right = n
93
+ while (left < right) {
94
+ const mid = Math.floor((left + right) / 2)
95
+ if (cmp(mid) <= 0) {
96
+ right = mid
97
+ } else {
98
+ left = mid + 1
99
+ }
100
+ }
101
+ const found = left < n && cmp(left) === 0
102
+ return [left, found]
103
+ }
104
+
105
+ // SearchInts searches for x in a sorted slice of ints and returns the index
106
+ // as specified by Search. The return value is the index to insert x if x is
107
+ // not present (it could be len(a)).
108
+ // The slice must be sorted in ascending order.
109
+ export function SearchInts(a: $.Slice<number>, x: number): number {
110
+ return Search($.len(a), (i: number) => ($.index(a, i) as number) >= x)
111
+ }
112
+
113
+ // SearchFloat64s searches for x in a sorted slice of float64s and returns the index
114
+ // as specified by Search. The return value is the index to insert x if x is not
115
+ // present (it could be len(a)).
116
+ // The slice must be sorted in ascending order.
117
+ export function SearchFloat64s(a: $.Slice<number>, x: number): number {
118
+ return Search($.len(a), (i: number) => ($.index(a, i) as number) >= x)
119
+ }
120
+
121
+ // SearchStrings searches for x in a sorted slice of strings and returns the index
122
+ // as specified by Search. The return value is the index to insert x if x is not
123
+ // present (it could be len(a)).
124
+ // The slice must be sorted in ascending order.
125
+ export function SearchStrings(a: $.Slice<string>, x: string): number {
126
+ return Search($.len(a), (i: number) => ($.index(a, i) as string) >= x)
127
+ }
128
+
@@ -0,0 +1,59 @@
1
+ import * as $ from "../builtin/builtin.js";
2
+
3
+ // Helper type for slice metadata
4
+ interface SliceMetadata<T> {
5
+ backing: T[]
6
+ offset: number
7
+ length: number
8
+ capacity: number
9
+ }
10
+
11
+ // Helper function to swap elements in a slice
12
+ function swapInSlice<T>(slice: $.Slice<T>, i: number, j: number): void {
13
+ if (!slice) return
14
+
15
+ const temp = $.index(slice, i)
16
+ if (Array.isArray(slice)) {
17
+ const val_j = $.index(slice, j)
18
+ const val_i = temp
19
+ slice[i] = val_j as T
20
+ slice[j] = val_i as T
21
+ } else if (typeof slice === 'object' && '__meta__' in slice) {
22
+ const meta = (slice as any).__meta__ as SliceMetadata<T>
23
+ const backing = meta.backing
24
+ backing[meta.offset + i] = $.index(slice, j) as T
25
+ backing[meta.offset + j] = temp as T
26
+ }
27
+ }
28
+
29
+ // Slice sorts the slice x given the provided less function
30
+ export function Slice(x: $.Slice<any>, less: (i: number, j: number) => boolean): void {
31
+ if (!x) return
32
+
33
+ // Simple insertion sort using the provided less function
34
+ const n = $.len(x)
35
+ for (let i = 1; i < n; i++) {
36
+ for (let j = i; j > 0 && less(j, j - 1); j--) {
37
+ swapInSlice(x, j, j - 1)
38
+ }
39
+ }
40
+ }
41
+
42
+ // SliceIsSorted reports whether the slice x is sorted according to the provided less function
43
+ export function SliceIsSorted(x: $.Slice<any>, less: (i: number, j: number) => boolean): boolean {
44
+ if (!x) return true
45
+
46
+ const n = $.len(x)
47
+ for (let i = n - 1; i > 0; i--) {
48
+ if (less(i, i - 1)) {
49
+ return false
50
+ }
51
+ }
52
+ return true
53
+ }
54
+
55
+ // SliceStable sorts the slice x while keeping the original order of equal elements
56
+ export function SliceStable(x: $.Slice<any>, less: (i: number, j: number) => boolean): void {
57
+ // For simplicity, use the same sort - can be improved later
58
+ Slice(x, less)
59
+ }