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.
- package/compiler/analysis.go +15 -6
- package/compiler/compiler.go +184 -34
- package/compiler/expr-call.go +19 -9
- package/compiler/field.go +17 -3
- package/compiler/gs_dependencies_test.go +80 -0
- package/compiler/lit.go +12 -6
- package/compiler/output.go +10 -4
- package/compiler/spec.go +15 -2
- package/compiler/type-assert.go +111 -21
- package/compiler/type.go +37 -8
- package/dist/gs/builtin/builtin.d.ts +55 -0
- package/dist/gs/builtin/builtin.js +213 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/slice.js +13 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.d.ts +56 -0
- package/dist/gs/bytes/buffer.gs.js +611 -0
- package/dist/gs/bytes/buffer.gs.js.map +1 -0
- package/dist/gs/bytes/bytes.gs.d.ts +78 -0
- package/dist/gs/bytes/bytes.gs.js +1107 -0
- package/dist/gs/bytes/bytes.gs.js.map +1 -0
- package/dist/gs/bytes/index.d.ts +4 -0
- package/dist/gs/bytes/index.js +5 -0
- package/dist/gs/bytes/index.js.map +1 -0
- package/dist/gs/bytes/iter.gs.d.ts +9 -0
- package/dist/gs/bytes/iter.gs.js +143 -0
- package/dist/gs/bytes/iter.gs.js.map +1 -0
- package/dist/gs/bytes/reader.gs.d.ts +34 -0
- package/dist/gs/bytes/reader.gs.js +198 -0
- package/dist/gs/bytes/reader.gs.js.map +1 -0
- package/dist/gs/fmt/fmt.d.ts +49 -0
- package/dist/gs/fmt/fmt.js +322 -0
- package/dist/gs/fmt/fmt.js.map +1 -0
- package/dist/gs/fmt/index.d.ts +1 -0
- package/dist/gs/fmt/index.js +2 -0
- package/dist/gs/fmt/index.js.map +1 -0
- package/dist/gs/internal/bytealg/index.d.ts +14 -2
- package/dist/gs/internal/bytealg/index.js +114 -8
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/path/filepath/index.d.ts +3 -0
- package/dist/gs/path/filepath/index.js +3 -0
- package/dist/gs/path/filepath/index.js.map +1 -0
- package/dist/gs/path/filepath/match.d.ts +3 -0
- package/dist/gs/path/filepath/match.js +212 -0
- package/dist/gs/path/filepath/match.js.map +1 -0
- package/dist/gs/path/filepath/path.d.ts +25 -0
- package/dist/gs/path/filepath/path.js +265 -0
- package/dist/gs/path/filepath/path.js.map +1 -0
- package/dist/gs/reflect/deepequal.d.ts +2 -1
- package/dist/gs/reflect/deepequal.js +5 -53
- package/dist/gs/reflect/deepequal.js.map +1 -1
- package/dist/gs/reflect/map.d.ts +14 -8
- package/dist/gs/reflect/map.js +15 -11
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +17 -9
- package/dist/gs/reflect/type.js +1 -1
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/value.js +15 -6
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js +18 -12
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/sort/index.d.ts +4 -0
- package/dist/gs/sort/index.js +4 -0
- package/dist/gs/sort/index.js.map +1 -0
- package/dist/gs/sort/search.gs.d.ts +6 -0
- package/dist/gs/sort/search.gs.js +125 -0
- package/dist/gs/sort/search.gs.js.map +1 -0
- package/dist/gs/sort/slice.gs.d.ts +4 -0
- package/dist/gs/sort/slice.gs.js +49 -0
- package/dist/gs/sort/slice.gs.js.map +1 -0
- package/dist/gs/sort/sort.gs.d.ts +37 -0
- package/dist/gs/sort/sort.gs.js +203 -0
- package/dist/gs/sort/sort.gs.js.map +1 -0
- package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
- package/dist/gs/unicode/utf8/utf8.js +4 -2
- package/dist/gs/unicode/utf8/utf8.js.map +1 -1
- package/gs/builtin/builtin.ts +236 -0
- package/gs/builtin/slice.ts +17 -1
- package/gs/bytes/buffer.gs.ts +614 -0
- package/gs/bytes/bytes.gs.ts +1288 -0
- package/gs/bytes/godoc.txt +69 -0
- package/gs/bytes/index.ts +69 -0
- package/gs/bytes/iter.gs.ts +149 -0
- package/gs/bytes/metadata.go +12 -0
- package/gs/bytes/reader.gs.ts +230 -0
- package/gs/fmt/fmt.ts +407 -0
- package/gs/fmt/godoc.txt +382 -0
- package/gs/fmt/index.ts +31 -0
- package/gs/fmt/metadata.go +7 -0
- package/gs/internal/bytealg/index.ts +125 -10
- package/gs/internal/metadata.go +7 -0
- package/gs/io/metadata.go +11 -0
- package/gs/maps/metadata.go +8 -0
- package/gs/math/metadata.go +7 -0
- package/gs/os/metadata.go +17 -0
- package/gs/path/filepath/godoc.txt +35 -0
- package/gs/path/filepath/index.ts +27 -0
- package/gs/path/filepath/match.test.ts +274 -0
- package/gs/path/filepath/match.ts +249 -0
- package/gs/path/filepath/path.test.ts +246 -0
- package/gs/path/filepath/path.ts +328 -0
- package/gs/path/metadata.go +8 -0
- package/gs/reflect/deepequal.test.ts +41 -0
- package/gs/reflect/deepequal.ts +19 -4
- package/gs/reflect/map.test.ts +30 -0
- package/gs/reflect/map.ts +22 -18
- package/gs/reflect/metadata.go +7 -0
- package/gs/reflect/type.ts +19 -15
- package/gs/reflect/value.ts +21 -7
- package/gs/reflect/visiblefields.ts +17 -13
- package/gs/sort/godoc.txt +27 -0
- package/gs/sort/index.ts +24 -0
- package/gs/sort/search.gs.ts +128 -0
- package/gs/sort/slice.gs.ts +59 -0
- package/gs/sort/sort.gs.ts +227 -0
- package/gs/strconv/metadata.go +7 -0
- package/gs/strings/metadata.go +11 -0
- package/gs/sync/metadata.go +7 -0
- package/gs/unicode/utf8/utf8.ts +8 -5
- package/package.json +1 -1
- package/dist/gs/internal/testlog/index.d.ts +0 -1
- package/dist/gs/internal/testlog/index.js +0 -5
- package/dist/gs/internal/testlog/index.js.map +0 -1
- package/dist/gs/maps/iter.gs.d.ts +0 -7
- package/dist/gs/maps/iter.gs.js +0 -65
- package/dist/gs/maps/iter.gs.js.map +0 -1
- package/dist/gs/maps/maps.gs.d.ts +0 -7
- package/dist/gs/maps/maps.gs.js +0 -79
- package/dist/gs/maps/maps.gs.js.map +0 -1
- package/dist/gs/reflect/abi.d.ts +0 -59
- package/dist/gs/reflect/abi.gs.d.ts +0 -59
- package/dist/gs/reflect/abi.gs.js +0 -79
- package/dist/gs/reflect/abi.gs.js.map +0 -1
- package/dist/gs/reflect/abi.js +0 -79
- package/dist/gs/reflect/abi.js.map +0 -1
- package/dist/gs/reflect/badlinkname.d.ts +0 -52
- package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
- package/dist/gs/reflect/badlinkname.gs.js +0 -72
- package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
- package/dist/gs/reflect/badlinkname.js +0 -72
- package/dist/gs/reflect/badlinkname.js.map +0 -1
- package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
- package/dist/gs/reflect/deepequal.gs.js +0 -308
- package/dist/gs/reflect/deepequal.gs.js.map +0 -1
- package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
- package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
- package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
- package/dist/gs/reflect/index.gs.d.ts +0 -1
- package/dist/gs/reflect/index.gs.js +0 -3
- package/dist/gs/reflect/index.gs.js.map +0 -1
- package/dist/gs/reflect/iter.gs.d.ts +0 -3
- package/dist/gs/reflect/iter.gs.js +0 -24
- package/dist/gs/reflect/iter.gs.js.map +0 -1
- package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
- package/dist/gs/reflect/makefunc.gs.js +0 -288
- package/dist/gs/reflect/makefunc.gs.js.map +0 -1
- package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
- package/dist/gs/reflect/map_swiss.gs.js +0 -70
- package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
- package/dist/gs/reflect/reflect.gs.d.ts +0 -132
- package/dist/gs/reflect/reflect.gs.js +0 -437
- package/dist/gs/reflect/reflect.gs.js.map +0 -1
- package/dist/gs/reflect/swapper.gs.d.ts +0 -1
- package/dist/gs/reflect/swapper.gs.js +0 -32
- package/dist/gs/reflect/swapper.gs.js.map +0 -1
- package/dist/gs/reflect/type.gs.d.ts +0 -4
- package/dist/gs/reflect/type.gs.js +0 -21
- package/dist/gs/reflect/type.gs.js.map +0 -1
- package/dist/gs/reflect/value.gs.d.ts +0 -4
- package/dist/gs/reflect/value.gs.js +0 -12
- package/dist/gs/reflect/value.gs.js.map +0 -1
- package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
- package/dist/gs/reflect/visiblefields.gs.js +0 -123
- package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
- package/dist/gs/stringslite/index.d.ts +0 -1
- package/dist/gs/stringslite/index.js +0 -2
- package/dist/gs/stringslite/index.js.map +0 -1
- package/dist/gs/stringslite/strings.d.ts +0 -11
- package/dist/gs/stringslite/strings.js +0 -67
- 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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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.
|
|
52
|
-
return !this.
|
|
56
|
+
this.current = this.iterator.next()
|
|
57
|
+
return !this.current.done
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
public Key():
|
|
56
|
-
return this.
|
|
60
|
+
public Key(): K | null {
|
|
61
|
+
return this.current?.value?.[0] ?? null
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
public Value():
|
|
60
|
-
return this.
|
|
64
|
+
public Value(): V | null {
|
|
65
|
+
return this.current?.value?.[1] ?? null
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
public Reset(m:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
package/gs/reflect/type.ts
CHANGED
|
@@ -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):
|
|
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():
|
|
355
|
+
public UnsafePointer(): unknown {
|
|
355
356
|
return this._value
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
public pointer():
|
|
359
|
+
public pointer(): unknown {
|
|
359
360
|
return this._value
|
|
360
361
|
}
|
|
361
362
|
|
|
362
|
-
public get ptr():
|
|
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():
|
|
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():
|
|
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):
|
|
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):
|
|
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):
|
|
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):
|
|
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):
|
|
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(
|
|
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,
|
package/gs/reflect/value.ts
CHANGED
|
@@ -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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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:
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
package/gs/sort/index.ts
ADDED
|
@@ -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
|
+
}
|