goscript 0.0.26 → 0.0.29
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/README.md +4 -4
- package/cmd/goscript/cmd_compile.go +0 -3
- package/cmd/goscript/deps.go +11 -0
- package/compiler/analysis.go +298 -55
- package/compiler/assignment.go +2 -2
- package/compiler/builtin_test.go +1 -1
- package/compiler/compiler.go +200 -68
- package/compiler/compiler_test.go +17 -24
- package/compiler/composite-lit.go +32 -8
- package/compiler/decl.go +6 -6
- package/compiler/expr-call.go +170 -15
- package/compiler/expr-selector.go +100 -0
- package/compiler/expr.go +1 -1
- package/compiler/protobuf.go +557 -0
- package/compiler/spec-struct.go +4 -0
- package/compiler/spec-value.go +89 -10
- package/compiler/spec.go +254 -1
- package/compiler/stmt-assign.go +35 -0
- package/compiler/type-assert.go +87 -0
- package/compiler/type.go +4 -1
- package/dist/gs/builtin/builtin.d.ts +20 -1
- package/dist/gs/builtin/builtin.js +95 -4
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +21 -2
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/errors/errors.d.ts +5 -6
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/internal/oserror/errors.d.ts +6 -0
- package/dist/gs/internal/oserror/errors.js +7 -0
- package/dist/gs/internal/oserror/errors.js.map +1 -0
- package/dist/gs/internal/oserror/index.d.ts +1 -0
- package/dist/gs/internal/oserror/index.js +2 -0
- package/dist/gs/internal/oserror/index.js.map +1 -0
- package/dist/gs/io/fs/format.d.ts +3 -0
- package/dist/gs/io/fs/format.js +56 -0
- package/dist/gs/io/fs/format.js.map +1 -0
- package/dist/gs/io/fs/fs.d.ts +79 -0
- package/dist/gs/io/fs/fs.js +200 -0
- package/dist/gs/io/fs/fs.js.map +1 -0
- package/dist/gs/io/fs/glob.d.ts +10 -0
- package/dist/gs/io/fs/glob.js +141 -0
- package/dist/gs/io/fs/glob.js.map +1 -0
- package/dist/gs/io/fs/index.d.ts +8 -0
- package/dist/gs/io/fs/index.js +9 -0
- package/dist/gs/io/fs/index.js.map +1 -0
- package/dist/gs/io/fs/readdir.d.ts +7 -0
- package/dist/gs/io/fs/readdir.js +152 -0
- package/dist/gs/io/fs/readdir.js.map +1 -0
- package/dist/gs/io/fs/readfile.d.ts +6 -0
- package/dist/gs/io/fs/readfile.js +118 -0
- package/dist/gs/io/fs/readfile.js.map +1 -0
- package/dist/gs/io/fs/stat.d.ts +6 -0
- package/dist/gs/io/fs/stat.js +87 -0
- package/dist/gs/io/fs/stat.js.map +1 -0
- package/dist/gs/io/fs/sub.d.ts +6 -0
- package/dist/gs/io/fs/sub.js +172 -0
- package/dist/gs/io/fs/sub.js.map +1 -0
- package/dist/gs/io/fs/walk.d.ts +7 -0
- package/dist/gs/io/fs/walk.js +76 -0
- package/dist/gs/io/fs/walk.js.map +1 -0
- package/dist/gs/io/index.d.ts +1 -0
- package/dist/gs/io/index.js +2 -0
- package/dist/gs/io/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +107 -0
- package/dist/gs/io/io.js +385 -0
- package/dist/gs/io/io.js.map +1 -0
- package/dist/gs/path/index.d.ts +2 -0
- package/dist/gs/path/index.js +3 -0
- package/dist/gs/path/index.js.map +1 -0
- package/dist/gs/path/match.d.ts +6 -0
- package/dist/gs/path/match.js +281 -0
- package/dist/gs/path/match.js.map +1 -0
- package/dist/gs/path/path.d.ts +7 -0
- package/dist/gs/path/path.js +256 -0
- package/dist/gs/path/path.js.map +1 -0
- package/dist/gs/strings/builder.d.ts +18 -0
- package/dist/gs/strings/builder.js +205 -0
- package/dist/gs/strings/builder.js.map +1 -0
- package/dist/gs/strings/clone.d.ts +1 -0
- package/dist/gs/strings/clone.js +16 -0
- package/dist/gs/strings/clone.js.map +1 -0
- package/dist/gs/strings/compare.d.ts +1 -0
- package/dist/gs/strings/compare.js +14 -0
- package/dist/gs/strings/compare.js.map +1 -0
- package/dist/gs/strings/index.d.ts +2 -0
- package/dist/gs/strings/index.js +3 -0
- package/dist/gs/strings/index.js.map +1 -0
- package/dist/gs/strings/iter.d.ts +8 -0
- package/dist/gs/strings/iter.js +160 -0
- package/dist/gs/strings/iter.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +34 -0
- package/dist/gs/strings/reader.js +418 -0
- package/dist/gs/strings/reader.js.map +1 -0
- package/dist/gs/strings/replace.d.ts +106 -0
- package/dist/gs/strings/replace.js +1136 -0
- package/dist/gs/strings/replace.js.map +1 -0
- package/dist/gs/strings/search.d.ts +24 -0
- package/dist/gs/strings/search.js +169 -0
- package/dist/gs/strings/search.js.map +1 -0
- package/dist/gs/strings/strings.d.ts +47 -0
- package/dist/gs/strings/strings.js +418 -0
- package/dist/gs/strings/strings.js.map +1 -0
- package/dist/gs/stringslite/index.d.ts +1 -0
- package/dist/gs/stringslite/index.js +2 -0
- package/dist/gs/stringslite/index.js.map +1 -0
- package/dist/gs/stringslite/strings.d.ts +11 -0
- package/dist/gs/stringslite/strings.js +67 -0
- package/dist/gs/stringslite/strings.js.map +1 -0
- package/dist/gs/sync/index.d.ts +1 -0
- package/dist/gs/sync/index.js +2 -0
- package/dist/gs/sync/index.js.map +1 -0
- package/dist/gs/sync/sync.d.ts +79 -0
- package/dist/gs/sync/sync.js +392 -0
- package/dist/gs/sync/sync.js.map +1 -0
- package/dist/gs/time/time.d.ts +11 -2
- package/dist/gs/time/time.js +337 -12
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/index.d.ts +1 -0
- package/dist/gs/unicode/index.js +2 -0
- package/dist/gs/unicode/index.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +105 -0
- package/dist/gs/unicode/unicode.js +332 -0
- package/dist/gs/unicode/unicode.js.map +1 -0
- package/dist/gs/unicode/utf8/index.d.ts +1 -0
- package/dist/gs/unicode/utf8/index.js +3 -0
- package/dist/gs/unicode/utf8/index.js.map +1 -0
- package/dist/gs/unicode/utf8/utf8.d.ts +20 -0
- package/dist/gs/unicode/utf8/utf8.js +196 -0
- package/dist/gs/unicode/utf8/utf8.js.map +1 -0
- package/dist/gs/unsafe/index.d.ts +1 -0
- package/dist/gs/unsafe/index.js +2 -0
- package/dist/gs/unsafe/index.js.map +1 -0
- package/dist/gs/unsafe/unsafe.d.ts +11 -0
- package/dist/gs/unsafe/unsafe.js +44 -0
- package/dist/gs/unsafe/unsafe.js.map +1 -0
- package/go.mod +2 -1
- package/go.sum +6 -2
- package/gs/README.md +6 -0
- package/gs/builtin/builtin.ts +171 -0
- package/gs/builtin/channel.ts +683 -0
- package/gs/builtin/defer.ts +58 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/io.ts +22 -0
- package/gs/builtin/map.ts +50 -0
- package/gs/builtin/slice.ts +1030 -0
- package/gs/builtin/type.ts +1106 -0
- package/gs/builtin/varRef.ts +25 -0
- package/gs/cmp/godoc.txt +8 -0
- package/gs/cmp/index.ts +29 -0
- package/gs/context/context.ts +401 -0
- package/gs/context/godoc.txt +69 -0
- package/gs/context/index.ts +1 -0
- package/gs/errors/errors.ts +223 -0
- package/gs/errors/godoc.txt +63 -0
- package/gs/errors/index.ts +1 -0
- package/gs/internal/goarch/godoc.txt +39 -0
- package/gs/internal/goarch/index.ts +18 -0
- package/gs/internal/oserror/errors.ts +14 -0
- package/gs/internal/oserror/index.ts +1 -0
- package/gs/io/fs/format.ts +65 -0
- package/gs/io/fs/fs.ts +359 -0
- package/gs/io/fs/glob.ts +167 -0
- package/gs/io/fs/godoc.txt +35 -0
- package/gs/io/fs/index.ts +8 -0
- package/gs/io/fs/readdir.ts +126 -0
- package/gs/io/fs/readfile.ts +77 -0
- package/gs/io/fs/stat.ts +38 -0
- package/gs/io/fs/sub.ts +208 -0
- package/gs/io/fs/walk.ts +89 -0
- package/gs/io/godoc.txt +61 -0
- package/gs/io/index.ts +1 -0
- package/gs/io/io.go +75 -0
- package/gs/io/io.ts +546 -0
- package/gs/iter/godoc.txt +203 -0
- package/gs/iter/index.ts +1 -0
- package/gs/iter/iter.ts +117 -0
- package/gs/math/bits/index.ts +356 -0
- package/gs/math/godoc.txt +76 -0
- package/gs/path/index.ts +2 -0
- package/gs/path/match.ts +307 -0
- package/gs/path/path.ts +301 -0
- package/gs/runtime/godoc.txt +331 -0
- package/gs/runtime/index.ts +1 -0
- package/gs/runtime/runtime.ts +178 -0
- package/gs/slices/godoc.txt +44 -0
- package/gs/slices/index.ts +1 -0
- package/gs/slices/slices.ts +22 -0
- package/gs/strings/builder.test.ts +121 -0
- package/gs/strings/builder.ts +223 -0
- package/gs/strings/clone.test.ts +43 -0
- package/gs/strings/clone.ts +17 -0
- package/gs/strings/compare.test.ts +84 -0
- package/gs/strings/compare.ts +13 -0
- package/gs/strings/godoc.txt +66 -0
- package/gs/strings/index.ts +2 -0
- package/gs/strings/iter.test.ts +343 -0
- package/gs/strings/iter.ts +171 -0
- package/gs/strings/reader.test.ts +242 -0
- package/gs/strings/reader.ts +451 -0
- package/gs/strings/replace.test.ts +181 -0
- package/gs/strings/replace.ts +1310 -0
- package/gs/strings/search.test.ts +214 -0
- package/gs/strings/search.ts +213 -0
- package/gs/strings/strings.test.ts +477 -0
- package/gs/strings/strings.ts +510 -0
- package/gs/stringslite/godoc.txt +17 -0
- package/gs/stringslite/index.ts +1 -0
- package/gs/stringslite/strings.ts +82 -0
- package/gs/sync/godoc.txt +21 -0
- package/gs/sync/index.ts +1 -0
- package/gs/sync/sync.go +64 -0
- package/gs/sync/sync.ts +449 -0
- package/gs/time/godoc.txt +116 -0
- package/gs/time/index.ts +1 -0
- package/gs/time/time.ts +585 -0
- package/gs/unicode/godoc.txt +52 -0
- package/gs/unicode/index.ts +1 -0
- package/gs/unicode/unicode.go +38 -0
- package/gs/unicode/unicode.ts +418 -0
- package/gs/unicode/utf8/godoc.txt +22 -0
- package/gs/unicode/utf8/index.ts +2 -0
- package/gs/unicode/utf8/utf8.ts +227 -0
- package/gs/unsafe/godoc.txt +19 -0
- package/gs/unsafe/index.ts +1 -0
- package/gs/unsafe/unsafe.test.ts +68 -0
- package/gs/unsafe/unsafe.ts +77 -0
- package/package.json +4 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import * as $ from '@goscript/builtin/builtin.js'
|
|
3
|
+
import { Builder } from './builder.js'
|
|
4
|
+
|
|
5
|
+
describe('strings/Builder', () => {
|
|
6
|
+
describe('Builder', () => {
|
|
7
|
+
it('should create empty builder', () => {
|
|
8
|
+
const b = new Builder()
|
|
9
|
+
expect(b.String()).toBe('')
|
|
10
|
+
expect(b.Len()).toBe(0)
|
|
11
|
+
expect(b.Cap()).toBe(0)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should write string', () => {
|
|
15
|
+
const b = new Builder()
|
|
16
|
+
const [n, err] = b.WriteString('hello')
|
|
17
|
+
expect(n).toBe(5)
|
|
18
|
+
expect(err).toBeNull()
|
|
19
|
+
expect(b.String()).toBe('hello')
|
|
20
|
+
expect(b.Len()).toBe(5)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should write bytes', () => {
|
|
24
|
+
const b = new Builder()
|
|
25
|
+
const bytes = new TextEncoder().encode('world')
|
|
26
|
+
const [n, err] = b.Write(bytes)
|
|
27
|
+
expect(n).toBe(bytes.length)
|
|
28
|
+
expect(err).toBeNull()
|
|
29
|
+
expect(b.String()).toBe('world')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should write byte', () => {
|
|
33
|
+
const b = new Builder()
|
|
34
|
+
const err = b.WriteByte(65) // 'A'
|
|
35
|
+
expect(err).toBeNull()
|
|
36
|
+
expect(b.String()).toBe('A')
|
|
37
|
+
expect(b.Len()).toBe(1)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should write rune', () => {
|
|
41
|
+
const b = new Builder()
|
|
42
|
+
const [n, err] = b.WriteRune(0x1f44d) // 👍
|
|
43
|
+
expect(err).toBeNull()
|
|
44
|
+
expect(n).toBeGreaterThan(0)
|
|
45
|
+
expect(b.String()).toBe('👍')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should grow capacity', () => {
|
|
49
|
+
const b = new Builder()
|
|
50
|
+
b.Grow(100)
|
|
51
|
+
// Should not throw - capacity is grown
|
|
52
|
+
expect(b.Cap()).toBeGreaterThanOrEqual(0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should throw on negative grow', () => {
|
|
56
|
+
const b = new Builder()
|
|
57
|
+
expect(() => b.Grow(-1)).toThrow()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should reset builder', () => {
|
|
61
|
+
const b = new Builder()
|
|
62
|
+
b.WriteString('hello')
|
|
63
|
+
expect(b.Len()).toBe(5)
|
|
64
|
+
|
|
65
|
+
b.Reset()
|
|
66
|
+
expect(b.String()).toBe('')
|
|
67
|
+
expect(b.Len()).toBe(0)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should clone builder', () => {
|
|
71
|
+
const b = new Builder()
|
|
72
|
+
b.WriteString('hello')
|
|
73
|
+
|
|
74
|
+
const cloned = b.clone()
|
|
75
|
+
expect(cloned.String()).toBe('hello')
|
|
76
|
+
expect(cloned.Len()).toBe(5)
|
|
77
|
+
|
|
78
|
+
// Modify original
|
|
79
|
+
b.WriteString(' world')
|
|
80
|
+
expect(b.String()).toBe('hello world')
|
|
81
|
+
expect(cloned.String()).toBe('hello') // Should not change
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should handle multiple writes', () => {
|
|
85
|
+
const b = new Builder()
|
|
86
|
+
b.WriteString('hello')
|
|
87
|
+
b.WriteString(' ')
|
|
88
|
+
b.WriteString('world')
|
|
89
|
+
expect(b.String()).toBe('hello world')
|
|
90
|
+
expect(b.Len()).toBe(11)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should handle empty writes', () => {
|
|
94
|
+
const b = new Builder()
|
|
95
|
+
const [n, err] = b.WriteString('')
|
|
96
|
+
expect(n).toBe(0)
|
|
97
|
+
expect(err).toBeNull()
|
|
98
|
+
expect(b.String()).toBe('')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should handle unicode correctly', () => {
|
|
102
|
+
const b = new Builder()
|
|
103
|
+
b.WriteString('Hello 世界')
|
|
104
|
+
expect(b.String()).toBe('Hello 世界')
|
|
105
|
+
|
|
106
|
+
// Write individual runes
|
|
107
|
+
const b2 = new Builder()
|
|
108
|
+
b2.WriteRune(0x4e16) // 世
|
|
109
|
+
b2.WriteRune(0x754c) // 界
|
|
110
|
+
expect(b2.String()).toBe('世界')
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('should maintain proper length with unicode', () => {
|
|
114
|
+
const b = new Builder()
|
|
115
|
+
const text = 'Hello 🌟'
|
|
116
|
+
b.WriteString(text)
|
|
117
|
+
expect(b.String()).toBe(text)
|
|
118
|
+
expect(b.Len()).toBe(text.length)
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
})
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/builtin.js'
|
|
2
|
+
|
|
3
|
+
export class Builder {
|
|
4
|
+
private _content: string = ''
|
|
5
|
+
private _addr: Builder | null = null
|
|
6
|
+
|
|
7
|
+
constructor(init?: Partial<{}>) {
|
|
8
|
+
// Simple constructor - no complex initialization needed
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public clone(): Builder {
|
|
12
|
+
const cloned = new Builder()
|
|
13
|
+
cloned._content = this._content
|
|
14
|
+
cloned._addr = this._addr
|
|
15
|
+
return cloned
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private copyCheck(): void {
|
|
19
|
+
if (this._addr == null) {
|
|
20
|
+
this._addr = this
|
|
21
|
+
} else if (this._addr !== this) {
|
|
22
|
+
$.panic('strings: illegal use of non-zero Builder copied by value')
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// String returns the accumulated string.
|
|
27
|
+
public String(): string {
|
|
28
|
+
return this._content
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
|
|
32
|
+
public Len(): number {
|
|
33
|
+
return this._content.length
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Cap returns the capacity of the builder's underlying byte slice. It is the
|
|
37
|
+
// total space allocated for the string being built and includes any bytes
|
|
38
|
+
// already written.
|
|
39
|
+
public Cap(): number {
|
|
40
|
+
// For simplicity, return the current length since JavaScript strings are dynamic
|
|
41
|
+
return this._content.length
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Reset resets the Builder to be empty.
|
|
45
|
+
public Reset(): void {
|
|
46
|
+
this._addr = null
|
|
47
|
+
this._content = ''
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Grow grows b's capacity, if necessary, to guarantee space for
|
|
51
|
+
// another n bytes. After Grow(n), at least n bytes can be written to b
|
|
52
|
+
// without another allocation. If n is negative, Grow panics.
|
|
53
|
+
public Grow(n: number): void {
|
|
54
|
+
this.copyCheck()
|
|
55
|
+
if (n < 0) {
|
|
56
|
+
$.panic('strings.Builder.Grow: negative count')
|
|
57
|
+
}
|
|
58
|
+
// JavaScript strings are dynamic, so no need to pre-allocate
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Write appends the contents of p to b's buffer.
|
|
62
|
+
// Write always returns len(p), nil.
|
|
63
|
+
public Write(p: Uint8Array): [number, $.GoError] {
|
|
64
|
+
this.copyCheck()
|
|
65
|
+
// Convert byte array to string
|
|
66
|
+
const str = new TextDecoder('utf-8').decode(p)
|
|
67
|
+
this._content += str
|
|
68
|
+
return [p.length, null]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// WriteByte appends the byte c to b's buffer.
|
|
72
|
+
// The returned error is always nil.
|
|
73
|
+
public WriteByte(c: number): $.GoError {
|
|
74
|
+
this.copyCheck()
|
|
75
|
+
this._content += String.fromCharCode(c)
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
|
|
80
|
+
// It returns the length of r and a nil error.
|
|
81
|
+
public WriteRune(r: number): [number, $.GoError] {
|
|
82
|
+
this.copyCheck()
|
|
83
|
+
const str = String.fromCodePoint(r)
|
|
84
|
+
this._content += str
|
|
85
|
+
// Return the byte length of the UTF-8 encoding
|
|
86
|
+
const byteLength = new TextEncoder().encode(str).length
|
|
87
|
+
return [byteLength, null]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// WriteString appends the contents of s to b's buffer.
|
|
91
|
+
// It returns the length of s and a nil error.
|
|
92
|
+
public WriteString(s: string): [number, $.GoError] {
|
|
93
|
+
this.copyCheck()
|
|
94
|
+
this._content += s
|
|
95
|
+
return [s.length, null]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Register this type with the runtime type system
|
|
99
|
+
static __typeInfo = $.registerStructType(
|
|
100
|
+
'Builder',
|
|
101
|
+
new Builder(),
|
|
102
|
+
[
|
|
103
|
+
{
|
|
104
|
+
name: 'String',
|
|
105
|
+
args: [],
|
|
106
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'Len',
|
|
110
|
+
args: [],
|
|
111
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'number' } }],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'Cap',
|
|
115
|
+
args: [],
|
|
116
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'number' } }],
|
|
117
|
+
},
|
|
118
|
+
{ name: 'Reset', args: [], returns: [] },
|
|
119
|
+
{
|
|
120
|
+
name: 'Grow',
|
|
121
|
+
args: [{ name: 'n', type: { kind: $.TypeKind.Basic, name: 'number' } }],
|
|
122
|
+
returns: [],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Write',
|
|
126
|
+
args: [
|
|
127
|
+
{
|
|
128
|
+
name: 'p',
|
|
129
|
+
type: {
|
|
130
|
+
kind: $.TypeKind.Slice,
|
|
131
|
+
elemType: { kind: $.TypeKind.Basic, name: 'number' },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
returns: [
|
|
136
|
+
{ type: { kind: $.TypeKind.Basic, name: 'number' } },
|
|
137
|
+
{
|
|
138
|
+
type: {
|
|
139
|
+
kind: $.TypeKind.Interface,
|
|
140
|
+
name: 'GoError',
|
|
141
|
+
methods: [
|
|
142
|
+
{
|
|
143
|
+
name: 'Error',
|
|
144
|
+
args: [],
|
|
145
|
+
returns: [
|
|
146
|
+
{ type: { kind: $.TypeKind.Basic, name: 'string' } },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'WriteByte',
|
|
156
|
+
args: [{ name: 'c', type: { kind: $.TypeKind.Basic, name: 'number' } }],
|
|
157
|
+
returns: [
|
|
158
|
+
{
|
|
159
|
+
type: {
|
|
160
|
+
kind: $.TypeKind.Interface,
|
|
161
|
+
name: 'GoError',
|
|
162
|
+
methods: [
|
|
163
|
+
{
|
|
164
|
+
name: 'Error',
|
|
165
|
+
args: [],
|
|
166
|
+
returns: [
|
|
167
|
+
{ type: { kind: $.TypeKind.Basic, name: 'string' } },
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'WriteRune',
|
|
177
|
+
args: [{ name: 'r', type: { kind: $.TypeKind.Basic, name: 'number' } }],
|
|
178
|
+
returns: [
|
|
179
|
+
{ type: { kind: $.TypeKind.Basic, name: 'number' } },
|
|
180
|
+
{
|
|
181
|
+
type: {
|
|
182
|
+
kind: $.TypeKind.Interface,
|
|
183
|
+
name: 'GoError',
|
|
184
|
+
methods: [
|
|
185
|
+
{
|
|
186
|
+
name: 'Error',
|
|
187
|
+
args: [],
|
|
188
|
+
returns: [
|
|
189
|
+
{ type: { kind: $.TypeKind.Basic, name: 'string' } },
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'WriteString',
|
|
199
|
+
args: [{ name: 's', type: { kind: $.TypeKind.Basic, name: 'string' } }],
|
|
200
|
+
returns: [
|
|
201
|
+
{ type: { kind: $.TypeKind.Basic, name: 'number' } },
|
|
202
|
+
{
|
|
203
|
+
type: {
|
|
204
|
+
kind: $.TypeKind.Interface,
|
|
205
|
+
name: 'GoError',
|
|
206
|
+
methods: [
|
|
207
|
+
{
|
|
208
|
+
name: 'Error',
|
|
209
|
+
args: [],
|
|
210
|
+
returns: [
|
|
211
|
+
{ type: { kind: $.TypeKind.Basic, name: 'string' } },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
Builder,
|
|
221
|
+
{},
|
|
222
|
+
)
|
|
223
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { Clone } from './clone.js'
|
|
3
|
+
|
|
4
|
+
describe('strings/clone', () => {
|
|
5
|
+
describe('Clone', () => {
|
|
6
|
+
it('should return a copy of the string', () => {
|
|
7
|
+
expect(Clone('hello')).toBe('hello')
|
|
8
|
+
expect(Clone('world')).toBe('world')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should handle empty string', () => {
|
|
12
|
+
expect(Clone('')).toBe('')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should handle unicode strings', () => {
|
|
16
|
+
expect(Clone('Hello 世界')).toBe('Hello 世界')
|
|
17
|
+
expect(Clone('🌟⭐✨')).toBe('🌟⭐✨')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should handle strings with special characters', () => {
|
|
21
|
+
expect(Clone('Hello\nWorld\t!')).toBe('Hello\nWorld\t!')
|
|
22
|
+
expect(Clone('quotes"and\'stuff')).toBe('quotes"and\'stuff')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should handle long strings', () => {
|
|
26
|
+
const longString = 'a'.repeat(10000)
|
|
27
|
+
expect(Clone(longString)).toBe(longString)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should handle strings with null bytes', () => {
|
|
31
|
+
const stringWithNull = 'hello\0world'
|
|
32
|
+
expect(Clone(stringWithNull)).toBe(stringWithNull)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should create independent copy semantically', () => {
|
|
36
|
+
const original = 'test string'
|
|
37
|
+
const cloned = Clone(original)
|
|
38
|
+
expect(cloned).toBe(original)
|
|
39
|
+
// In JavaScript, strings are immutable, so this is the expected behavior
|
|
40
|
+
// The clone function maintains Go semantics where it guarantees a new allocation
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/builtin.js'
|
|
2
|
+
|
|
3
|
+
// Clone returns a fresh copy of s.
|
|
4
|
+
// It guarantees to make a copy of s into a new allocation,
|
|
5
|
+
// which can be important when retaining only a small substring
|
|
6
|
+
// of a much larger string. Using Clone can help such programs
|
|
7
|
+
// use less memory. Of course, since using Clone makes a copy,
|
|
8
|
+
// overuse of Clone can make programs use more memory.
|
|
9
|
+
// Clone should typically be used only rarely, and only when
|
|
10
|
+
// profiling indicates that it is needed.
|
|
11
|
+
// For strings of length zero the string "" will be returned
|
|
12
|
+
// and no allocation is made.
|
|
13
|
+
export function Clone(s: string): string {
|
|
14
|
+
// In JavaScript, strings are immutable, so we can just return the string
|
|
15
|
+
// But to match Go semantics, we'll create a new string
|
|
16
|
+
return String(s)
|
|
17
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { Compare } from './compare.js'
|
|
3
|
+
|
|
4
|
+
describe('strings/compare', () => {
|
|
5
|
+
describe('Compare', () => {
|
|
6
|
+
it('should return 0 for equal strings', () => {
|
|
7
|
+
expect(Compare('hello', 'hello')).toBe(0)
|
|
8
|
+
expect(Compare('', '')).toBe(0)
|
|
9
|
+
expect(Compare('world', 'world')).toBe(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('should return -1 when first string is lexicographically smaller', () => {
|
|
13
|
+
expect(Compare('a', 'b')).toBe(-1)
|
|
14
|
+
expect(Compare('abc', 'abd')).toBe(-1)
|
|
15
|
+
expect(Compare('hello', 'world')).toBe(-1)
|
|
16
|
+
expect(Compare('', 'a')).toBe(-1)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should return 1 when first string is lexicographically larger', () => {
|
|
20
|
+
expect(Compare('b', 'a')).toBe(1)
|
|
21
|
+
expect(Compare('abd', 'abc')).toBe(1)
|
|
22
|
+
expect(Compare('world', 'hello')).toBe(1)
|
|
23
|
+
expect(Compare('a', '')).toBe(1)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should handle strings of different lengths', () => {
|
|
27
|
+
expect(Compare('abc', 'abcd')).toBe(-1)
|
|
28
|
+
expect(Compare('abcd', 'abc')).toBe(1)
|
|
29
|
+
expect(Compare('ab', 'abc')).toBe(-1)
|
|
30
|
+
expect(Compare('abc', 'ab')).toBe(1)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should handle case sensitivity', () => {
|
|
34
|
+
expect(Compare('a', 'A')).toBe(1) // lowercase > uppercase
|
|
35
|
+
expect(Compare('A', 'a')).toBe(-1)
|
|
36
|
+
expect(Compare('Hello', 'hello')).toBe(-1)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should handle unicode strings', () => {
|
|
40
|
+
expect(Compare('世界', '世界')).toBe(0)
|
|
41
|
+
expect(Compare('世', '界')).toBeLessThan(0)
|
|
42
|
+
expect(Compare('🌟', '⭐')).toBeGreaterThan(0)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should handle special characters', () => {
|
|
46
|
+
expect(Compare('!', '@')).toBe(-1)
|
|
47
|
+
expect(Compare('@', '!')).toBe(1)
|
|
48
|
+
expect(Compare('123', '456')).toBe(-1)
|
|
49
|
+
expect(Compare('9', '10')).toBe(1) // string comparison, not numeric
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should handle strings with spaces', () => {
|
|
53
|
+
expect(Compare(' ', '')).toBe(1)
|
|
54
|
+
expect(Compare('', ' ')).toBe(-1)
|
|
55
|
+
expect(Compare('a b', 'ab')).toBe(-1) // space < 'b'
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should handle mixed content', () => {
|
|
59
|
+
expect(Compare('abc123', 'abc456')).toBe(-1)
|
|
60
|
+
expect(Compare('Hello World', 'Hello world')).toBe(-1) // 'W' < 'w'
|
|
61
|
+
expect(Compare('test\n', 'test\t')).toBe(1) // '\n' > '\t' (10 > 9)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should be consistent with built-in comparison', () => {
|
|
65
|
+
const testCases = [
|
|
66
|
+
['hello', 'world'],
|
|
67
|
+
['abc', 'abc'],
|
|
68
|
+
['a', 'b'],
|
|
69
|
+
['', ''],
|
|
70
|
+
['longer', 'short'],
|
|
71
|
+
['123', '45'],
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
testCases.forEach(([a, b]) => {
|
|
75
|
+
const compareResult = Compare(a, b)
|
|
76
|
+
const builtinResult =
|
|
77
|
+
a < b ? -1
|
|
78
|
+
: a > b ? 1
|
|
79
|
+
: 0
|
|
80
|
+
expect(compareResult).toBe(builtinResult)
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/builtin.js'
|
|
2
|
+
|
|
3
|
+
// Compare returns an integer comparing two strings lexicographically.
|
|
4
|
+
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
|
|
5
|
+
//
|
|
6
|
+
// Compare is included only for symmetry with package bytes.
|
|
7
|
+
// It is usually clearer and always faster to use the built-in
|
|
8
|
+
// string comparison operators ==, <, >, and so on.
|
|
9
|
+
export function Compare(a: string, b: string): number {
|
|
10
|
+
if (a < b) return -1
|
|
11
|
+
if (a > b) return 1
|
|
12
|
+
return 0
|
|
13
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package strings // import "strings"
|
|
2
|
+
|
|
3
|
+
Package strings implements simple functions to manipulate UTF-8 encoded strings.
|
|
4
|
+
|
|
5
|
+
For information about UTF-8 strings in Go, see https://blog.golang.org/strings.
|
|
6
|
+
|
|
7
|
+
func Clone(s string) string
|
|
8
|
+
func Compare(a, b string) int
|
|
9
|
+
func Contains(s, substr string) bool
|
|
10
|
+
func ContainsAny(s, chars string) bool
|
|
11
|
+
func ContainsFunc(s string, f func(rune) bool) bool
|
|
12
|
+
func ContainsRune(s string, r rune) bool
|
|
13
|
+
func Count(s, substr string) int
|
|
14
|
+
func Cut(s, sep string) (before, after string, found bool)
|
|
15
|
+
func CutPrefix(s, prefix string) (after string, found bool)
|
|
16
|
+
func CutSuffix(s, suffix string) (before string, found bool)
|
|
17
|
+
func EqualFold(s, t string) bool
|
|
18
|
+
func Fields(s string) []string
|
|
19
|
+
func FieldsFunc(s string, f func(rune) bool) []string
|
|
20
|
+
func FieldsFuncSeq(s string, f func(rune) bool) iter.Seq[string]
|
|
21
|
+
func FieldsSeq(s string) iter.Seq[string]
|
|
22
|
+
func HasPrefix(s, prefix string) bool
|
|
23
|
+
func HasSuffix(s, suffix string) bool
|
|
24
|
+
func Index(s, substr string) int
|
|
25
|
+
func IndexAny(s, chars string) int
|
|
26
|
+
func IndexByte(s string, c byte) int
|
|
27
|
+
func IndexFunc(s string, f func(rune) bool) int
|
|
28
|
+
func IndexRune(s string, r rune) int
|
|
29
|
+
func Join(elems []string, sep string) string
|
|
30
|
+
func LastIndex(s, substr string) int
|
|
31
|
+
func LastIndexAny(s, chars string) int
|
|
32
|
+
func LastIndexByte(s string, c byte) int
|
|
33
|
+
func LastIndexFunc(s string, f func(rune) bool) int
|
|
34
|
+
func Lines(s string) iter.Seq[string]
|
|
35
|
+
func Map(mapping func(rune) rune, s string) string
|
|
36
|
+
func Repeat(s string, count int) string
|
|
37
|
+
func Replace(s, old, new string, n int) string
|
|
38
|
+
func ReplaceAll(s, old, new string) string
|
|
39
|
+
func Split(s, sep string) []string
|
|
40
|
+
func SplitAfter(s, sep string) []string
|
|
41
|
+
func SplitAfterN(s, sep string, n int) []string
|
|
42
|
+
func SplitAfterSeq(s, sep string) iter.Seq[string]
|
|
43
|
+
func SplitN(s, sep string, n int) []string
|
|
44
|
+
func SplitSeq(s, sep string) iter.Seq[string]
|
|
45
|
+
func Title(s string) string
|
|
46
|
+
func ToLower(s string) string
|
|
47
|
+
func ToLowerSpecial(c unicode.SpecialCase, s string) string
|
|
48
|
+
func ToTitle(s string) string
|
|
49
|
+
func ToTitleSpecial(c unicode.SpecialCase, s string) string
|
|
50
|
+
func ToUpper(s string) string
|
|
51
|
+
func ToUpperSpecial(c unicode.SpecialCase, s string) string
|
|
52
|
+
func ToValidUTF8(s, replacement string) string
|
|
53
|
+
func Trim(s, cutset string) string
|
|
54
|
+
func TrimFunc(s string, f func(rune) bool) string
|
|
55
|
+
func TrimLeft(s, cutset string) string
|
|
56
|
+
func TrimLeftFunc(s string, f func(rune) bool) string
|
|
57
|
+
func TrimPrefix(s, prefix string) string
|
|
58
|
+
func TrimRight(s, cutset string) string
|
|
59
|
+
func TrimRightFunc(s string, f func(rune) bool) string
|
|
60
|
+
func TrimSpace(s string) string
|
|
61
|
+
func TrimSuffix(s, suffix string) string
|
|
62
|
+
type Builder struct{ ... }
|
|
63
|
+
type Reader struct{ ... }
|
|
64
|
+
func NewReader(s string) *Reader
|
|
65
|
+
type Replacer struct{ ... }
|
|
66
|
+
func NewReplacer(oldnew ...string) *Replacer
|