goscript 0.0.83 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +27 -7
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +86 -0
- package/dist/gs/builtin/hostio.js +266 -0
- package/dist/gs/builtin/hostio.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/print.d.ts +8 -0
- package/dist/gs/builtin/print.js +111 -0
- package/dist/gs/builtin/print.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +2 -22
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +2 -51
- package/dist/gs/os/types_js.gs.js +67 -105
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +31 -6
- package/gs/builtin/hostio.test.ts +246 -0
- package/gs/builtin/hostio.ts +413 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/print.test.ts +48 -0
- package/gs/builtin/print.ts +154 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/fmt/fmt.test.ts +41 -30
- package/gs/fmt/fmt.ts +2 -22
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +103 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +74 -153
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
package/gs/fmt/fmt.test.ts
CHANGED
|
@@ -1,38 +1,49 @@
|
|
|
1
|
-
import { describe, it,
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { resetHostRuntimeForTests } from '@goscript/builtin/hostio.js'
|
|
2
3
|
import * as fmt from './fmt.js'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
const originalDeno = (globalThis as any).Deno
|
|
6
|
+
const originalProcess = (globalThis as any).process
|
|
7
|
+
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
if (originalDeno === undefined) {
|
|
10
|
+
delete (globalThis as any).Deno
|
|
11
|
+
} else {
|
|
12
|
+
;(globalThis as any).Deno = originalDeno
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (originalProcess === undefined) {
|
|
16
|
+
delete (globalThis as any).process
|
|
17
|
+
} else {
|
|
18
|
+
;(globalThis as any).process = originalProcess
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
resetHostRuntimeForTests()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Helper to capture stdout via the hostio text output path.
|
|
6
25
|
function captureStdout(run: () => void): string {
|
|
7
26
|
let buf = ''
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Fallback: spy on console.log for environments without process
|
|
26
|
-
const origLog = console.log
|
|
27
|
-
;(console as any).log = (msg: any) => {
|
|
28
|
-
buf += String(msg) + '\n'
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
run()
|
|
32
|
-
} finally {
|
|
33
|
-
console.log = origLog
|
|
34
|
-
}
|
|
27
|
+
delete (globalThis as any).Deno
|
|
28
|
+
;(globalThis as any).process = {
|
|
29
|
+
getBuiltinModule: vi.fn(() => ({
|
|
30
|
+
readSync: vi.fn(),
|
|
31
|
+
writeSync: vi.fn(
|
|
32
|
+
(
|
|
33
|
+
_fd: number,
|
|
34
|
+
chunk: Uint8Array,
|
|
35
|
+
_offset?: number,
|
|
36
|
+
length?: number,
|
|
37
|
+
_position?: number | null,
|
|
38
|
+
) => {
|
|
39
|
+
buf += new TextDecoder().decode(chunk.subarray(0, length ?? chunk.length))
|
|
40
|
+
return length ?? chunk.length
|
|
41
|
+
},
|
|
42
|
+
),
|
|
43
|
+
})),
|
|
35
44
|
}
|
|
45
|
+
resetHostRuntimeForTests()
|
|
46
|
+
run()
|
|
36
47
|
|
|
37
48
|
return buf
|
|
38
49
|
}
|
package/gs/fmt/fmt.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import * as $ from '@goscript/builtin/index.js'
|
|
5
5
|
import * as errors from '@goscript/errors/index.js'
|
|
6
|
+
import { writeHostStdoutText } from '@goscript/builtin/hostio.js'
|
|
6
7
|
|
|
7
8
|
// Basic interfaces
|
|
8
9
|
export interface Stringer {
|
|
@@ -259,28 +260,7 @@ function parseFormat(format: string, args: any[]): string {
|
|
|
259
260
|
// Global stdout simulation for Print functions
|
|
260
261
|
let stdout = {
|
|
261
262
|
write: (data: string) => {
|
|
262
|
-
|
|
263
|
-
// but we need to avoid adding extra newlines that console.log adds
|
|
264
|
-
if (
|
|
265
|
-
typeof process !== 'undefined' &&
|
|
266
|
-
process.stdout &&
|
|
267
|
-
process.stdout.write
|
|
268
|
-
) {
|
|
269
|
-
process.stdout.write(data)
|
|
270
|
-
} else {
|
|
271
|
-
// In browser environments, we need to use console.log but handle newlines carefully
|
|
272
|
-
// If the data already ends with \n, we should strip it to avoid double newlines
|
|
273
|
-
if (data.endsWith('\n')) {
|
|
274
|
-
console.log(data.slice(0, -1))
|
|
275
|
-
} else {
|
|
276
|
-
// Use console.log without adding newline by using a custom method
|
|
277
|
-
if (console.log) {
|
|
278
|
-
// For data without newlines, we can just print it directly
|
|
279
|
-
// This is a bit of a hack but works for most cases
|
|
280
|
-
console.log(data)
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
263
|
+
writeHostStdoutText(data)
|
|
284
264
|
},
|
|
285
265
|
}
|
|
286
266
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { CompareEqualVT } from './index.js'
|
|
4
|
+
|
|
5
|
+
class TestValue {
|
|
6
|
+
constructor(private readonly value: string) {}
|
|
7
|
+
|
|
8
|
+
EqualVT(other: TestValue): boolean {
|
|
9
|
+
return this.value == other.value
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('protobuf-go-lite EqualVT helpers', () => {
|
|
14
|
+
it('accepts compiler-emitted runtime type arguments', () => {
|
|
15
|
+
const equal = CompareEqualVT<TestValue>({
|
|
16
|
+
T: { zero: () => null },
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
expect(equal(new TestValue('a'), new TestValue('a'))).toBe(true)
|
|
20
|
+
expect(equal(new TestValue('a'), new TestValue('b'))).toBe(false)
|
|
21
|
+
expect(equal(null, null)).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
})
|
|
@@ -9,6 +9,8 @@ export function IsEqualVT<T extends EqualVT<T>>(t1: T | null, t2: T | null): boo
|
|
|
9
9
|
return t1.EqualVT(t2)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function CompareEqualVT<T extends EqualVT<T>>(
|
|
12
|
+
export function CompareEqualVT<T extends EqualVT<T>>(
|
|
13
|
+
_typeArgs?: unknown,
|
|
14
|
+
): (t1: T | null, t2: T | null) => boolean {
|
|
13
15
|
return (t1, t2) => IsEqualVT(t1, t2)
|
|
14
16
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
4
|
+
import * as token from '@goscript/go/token/index.js'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ErrorList_Add,
|
|
8
|
+
ErrorList_Error,
|
|
9
|
+
ErrorList_Len,
|
|
10
|
+
ErrorList_RemoveMultiples,
|
|
11
|
+
type ErrorList,
|
|
12
|
+
} from './index.js'
|
|
13
|
+
|
|
14
|
+
describe('go/scanner override', () => {
|
|
15
|
+
it('adds and formats scanner errors', () => {
|
|
16
|
+
const list: $.VarRef<ErrorList> = $.varRef(null)
|
|
17
|
+
|
|
18
|
+
ErrorList_Add(
|
|
19
|
+
list,
|
|
20
|
+
$.markAsStructValue(
|
|
21
|
+
new token.Position({
|
|
22
|
+
Filename: 'test.go',
|
|
23
|
+
Line: 1,
|
|
24
|
+
Column: 1,
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
'test error',
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
expect(ErrorList_Len(list.value)).toBe(1)
|
|
31
|
+
expect(ErrorList_Error(list.value)).toBe('test.go:1:1: test error')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('removes repeated line errors', () => {
|
|
35
|
+
const list: $.VarRef<ErrorList> = $.varRef(null)
|
|
36
|
+
const pos = $.markAsStructValue(
|
|
37
|
+
new token.Position({
|
|
38
|
+
Filename: 'test.go',
|
|
39
|
+
Line: 1,
|
|
40
|
+
Column: 1,
|
|
41
|
+
}),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
ErrorList_Add(list, pos, 'first')
|
|
45
|
+
ErrorList_Add(list, pos, 'second')
|
|
46
|
+
ErrorList_RemoveMultiples(list)
|
|
47
|
+
|
|
48
|
+
expect(ErrorList_Len(list.value)).toBe(1)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
2
|
+
import * as token from '@goscript/go/token/index.js'
|
|
3
|
+
|
|
4
|
+
export class Error {
|
|
5
|
+
public get Pos(): token.Position {
|
|
6
|
+
return this._fields.Pos.value
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
public set Pos(value: token.Position) {
|
|
10
|
+
this._fields.Pos.value = value
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public get Msg(): string {
|
|
14
|
+
return this._fields.Msg.value
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public set Msg(value: string) {
|
|
18
|
+
this._fields.Msg.value = value
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public _fields: {
|
|
22
|
+
Pos: $.VarRef<token.Position>
|
|
23
|
+
Msg: $.VarRef<string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(init?: Partial<{ Pos: token.Position; Msg: string }>) {
|
|
27
|
+
this._fields = {
|
|
28
|
+
Pos: $.varRef(init?.Pos ?? new token.Position()),
|
|
29
|
+
Msg: $.varRef(init?.Msg ?? ''),
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public clone(): Error {
|
|
34
|
+
return $.markAsStructValue(
|
|
35
|
+
new Error({
|
|
36
|
+
Pos: this.Pos.clone(),
|
|
37
|
+
Msg: this.Msg,
|
|
38
|
+
}),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public Error(): string {
|
|
43
|
+
return Error_Error(this)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static __typeInfo = $.registerStructType(
|
|
47
|
+
'go/scanner.Error',
|
|
48
|
+
new Error(),
|
|
49
|
+
[
|
|
50
|
+
{
|
|
51
|
+
name: 'Error',
|
|
52
|
+
args: [],
|
|
53
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
Error,
|
|
57
|
+
{
|
|
58
|
+
Pos: { type: 'go/token.Position' },
|
|
59
|
+
Msg: { kind: $.TypeKind.Basic, name: 'string' },
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type ErrorList = $.Slice<Error | null>
|
|
65
|
+
|
|
66
|
+
export const ScanComments = 1
|
|
67
|
+
|
|
68
|
+
export function Error_Error(err: Error): string {
|
|
69
|
+
if (!err.Pos.IsValid()) {
|
|
70
|
+
return err.Msg
|
|
71
|
+
}
|
|
72
|
+
return `${err.Pos.String()}: ${err.Msg}`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function ErrorList_Add(
|
|
76
|
+
list: $.VarRef<ErrorList>,
|
|
77
|
+
pos: token.Position,
|
|
78
|
+
msg: string,
|
|
79
|
+
): void {
|
|
80
|
+
list.value = $.append(
|
|
81
|
+
list.value,
|
|
82
|
+
$.markAsStructValue(new Error({ Pos: pos, Msg: msg })),
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function ErrorList_Len(list: ErrorList): number {
|
|
87
|
+
return $.len(list)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function ErrorList_Less(list: ErrorList, i: number, j: number): boolean {
|
|
91
|
+
const left = list![i]!
|
|
92
|
+
const right = list![j]!
|
|
93
|
+
if (left.Pos.Filename !== right.Pos.Filename) {
|
|
94
|
+
return left.Pos.Filename < right.Pos.Filename
|
|
95
|
+
}
|
|
96
|
+
if (left.Pos.Line !== right.Pos.Line) {
|
|
97
|
+
return left.Pos.Line < right.Pos.Line
|
|
98
|
+
}
|
|
99
|
+
if (left.Pos.Column !== right.Pos.Column) {
|
|
100
|
+
return left.Pos.Column < right.Pos.Column
|
|
101
|
+
}
|
|
102
|
+
return left.Msg < right.Msg
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function ErrorList_Swap(list: ErrorList, i: number, j: number): void {
|
|
106
|
+
const first = list![i]
|
|
107
|
+
list![i] = list![j]
|
|
108
|
+
list![j] = first
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function ErrorList_Sort(list: ErrorList): void {
|
|
112
|
+
list?.sort((left, right) => {
|
|
113
|
+
if (left === null || right === null) {
|
|
114
|
+
if (left === right) {
|
|
115
|
+
return 0
|
|
116
|
+
}
|
|
117
|
+
if (left === null) {
|
|
118
|
+
return -1
|
|
119
|
+
}
|
|
120
|
+
return 1
|
|
121
|
+
}
|
|
122
|
+
if (ErrorList_Less([left, right], 0, 1)) {
|
|
123
|
+
return -1
|
|
124
|
+
}
|
|
125
|
+
if (ErrorList_Less([right, left], 0, 1)) {
|
|
126
|
+
return 1
|
|
127
|
+
}
|
|
128
|
+
return 0
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function ErrorList_RemoveMultiples(list: $.VarRef<ErrorList>): void {
|
|
133
|
+
ErrorList_Sort(list.value)
|
|
134
|
+
const seen = new Set<string>()
|
|
135
|
+
list.value = $.asArray(list.value).filter((err) => {
|
|
136
|
+
if (err === null) {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
const key = `${err.Pos.Filename}:${err.Pos.Line}`
|
|
140
|
+
if (seen.has(key)) {
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
seen.add(key)
|
|
144
|
+
return true
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function ErrorList_Error(list: ErrorList): string {
|
|
149
|
+
const errors = $.asArray(list).filter((err) => err !== null)
|
|
150
|
+
if (errors.length === 0) {
|
|
151
|
+
return 'no errors'
|
|
152
|
+
}
|
|
153
|
+
if (errors.length === 1) {
|
|
154
|
+
return errors[0]!.Error()
|
|
155
|
+
}
|
|
156
|
+
return `${errors[0]!.Error()} (and ${errors.length - 1} more errors)`
|
|
157
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
4
|
+
|
|
5
|
+
import { Position, Position_IsValid, Position_String } from './index.js'
|
|
6
|
+
|
|
7
|
+
describe('go/token override', () => {
|
|
8
|
+
it('models Position values', () => {
|
|
9
|
+
const pos = $.markAsStructValue(
|
|
10
|
+
new Position({
|
|
11
|
+
Filename: 'test.go',
|
|
12
|
+
Line: 3,
|
|
13
|
+
Column: 9,
|
|
14
|
+
}),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
expect(Position_IsValid(pos)).toBe(true)
|
|
18
|
+
expect(Position_String(pos)).toBe('test.go:3:9')
|
|
19
|
+
expect(pos.clone().String()).toBe('test.go:3:9')
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as $ from '@goscript/builtin/index.js'
|
|
2
|
+
|
|
3
|
+
export type Pos = number
|
|
4
|
+
|
|
5
|
+
export const NoPos: Pos = 0
|
|
6
|
+
|
|
7
|
+
export class Position {
|
|
8
|
+
public get Filename(): string {
|
|
9
|
+
return this._fields.Filename.value
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public set Filename(value: string) {
|
|
13
|
+
this._fields.Filename.value = value
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public get Offset(): number {
|
|
17
|
+
return this._fields.Offset.value
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public set Offset(value: number) {
|
|
21
|
+
this._fields.Offset.value = value
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public get Line(): number {
|
|
25
|
+
return this._fields.Line.value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public set Line(value: number) {
|
|
29
|
+
this._fields.Line.value = value
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public get Column(): number {
|
|
33
|
+
return this._fields.Column.value
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public set Column(value: number) {
|
|
37
|
+
this._fields.Column.value = value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public _fields: {
|
|
41
|
+
Filename: $.VarRef<string>
|
|
42
|
+
Offset: $.VarRef<number>
|
|
43
|
+
Line: $.VarRef<number>
|
|
44
|
+
Column: $.VarRef<number>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
init?: Partial<{
|
|
49
|
+
Filename: string
|
|
50
|
+
Offset: number
|
|
51
|
+
Line: number
|
|
52
|
+
Column: number
|
|
53
|
+
}>,
|
|
54
|
+
) {
|
|
55
|
+
this._fields = {
|
|
56
|
+
Filename: $.varRef(init?.Filename ?? ''),
|
|
57
|
+
Offset: $.varRef(init?.Offset ?? 0),
|
|
58
|
+
Line: $.varRef(init?.Line ?? 0),
|
|
59
|
+
Column: $.varRef(init?.Column ?? 0),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public clone(): Position {
|
|
64
|
+
return $.markAsStructValue(
|
|
65
|
+
new Position({
|
|
66
|
+
Filename: this.Filename,
|
|
67
|
+
Offset: this.Offset,
|
|
68
|
+
Line: this.Line,
|
|
69
|
+
Column: this.Column,
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public IsValid(): boolean {
|
|
75
|
+
return Position_IsValid(this)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public String(): string {
|
|
79
|
+
return Position_String(this)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static __typeInfo = $.registerStructType(
|
|
83
|
+
'go/token.Position',
|
|
84
|
+
new Position(),
|
|
85
|
+
[
|
|
86
|
+
{
|
|
87
|
+
name: 'IsValid',
|
|
88
|
+
args: [],
|
|
89
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'bool' } }],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'String',
|
|
93
|
+
args: [],
|
|
94
|
+
returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
Position,
|
|
98
|
+
{
|
|
99
|
+
Filename: { kind: $.TypeKind.Basic, name: 'string' },
|
|
100
|
+
Offset: { kind: $.TypeKind.Basic, name: 'int' },
|
|
101
|
+
Line: { kind: $.TypeKind.Basic, name: 'int' },
|
|
102
|
+
Column: { kind: $.TypeKind.Basic, name: 'int' },
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function Position_IsValid(pos: Position): boolean {
|
|
108
|
+
return pos.Line > 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function Position_String(pos: Position): string {
|
|
112
|
+
if (!Position_IsValid(pos)) {
|
|
113
|
+
return '-'
|
|
114
|
+
}
|
|
115
|
+
const filename = pos.Filename === '' ? '<input>' : pos.Filename
|
|
116
|
+
if (pos.Column > 0) {
|
|
117
|
+
return `${filename}:${pos.Line}:${pos.Column}`
|
|
118
|
+
}
|
|
119
|
+
return `${filename}:${pos.Line}`
|
|
120
|
+
}
|
|
@@ -4,6 +4,7 @@ import * as io from '@goscript/io/index.js'
|
|
|
4
4
|
|
|
5
5
|
import { NewFile, Stderr, Stdin, Stdout } from './file_unix_js.gs.js'
|
|
6
6
|
import { ErrClosed } from './error.gs.js'
|
|
7
|
+
import { createHostFile, resetHostRuntimeForTests } from './types_js.gs.js'
|
|
7
8
|
|
|
8
9
|
const originalDeno = (globalThis as any).Deno
|
|
9
10
|
const originalProcess = (globalThis as any).process
|
|
@@ -20,6 +21,8 @@ afterEach(() => {
|
|
|
20
21
|
} else {
|
|
21
22
|
;(globalThis as any).process = originalProcess
|
|
22
23
|
}
|
|
24
|
+
|
|
25
|
+
resetHostRuntimeForTests()
|
|
23
26
|
})
|
|
24
27
|
|
|
25
28
|
describe('os stdio', () => {
|
|
@@ -45,6 +48,7 @@ describe('os stdio', () => {
|
|
|
45
48
|
stdout: { writeSync: stdoutWriteSync },
|
|
46
49
|
}
|
|
47
50
|
delete (globalThis as any).process
|
|
51
|
+
resetHostRuntimeForTests()
|
|
48
52
|
|
|
49
53
|
const input = NewFile(0, 'stdin')
|
|
50
54
|
const output = NewFile(1, 'stdout')
|
|
@@ -93,6 +97,7 @@ describe('os stdio', () => {
|
|
|
93
97
|
writeSync,
|
|
94
98
|
})),
|
|
95
99
|
}
|
|
100
|
+
resetHostRuntimeForTests()
|
|
96
101
|
|
|
97
102
|
const input = NewFile(0, 'stdin')
|
|
98
103
|
const output = NewFile(1, 'stdout')
|
|
@@ -110,6 +115,56 @@ describe('os stdio', () => {
|
|
|
110
115
|
expect(writeSync).toHaveBeenCalledTimes(1)
|
|
111
116
|
})
|
|
112
117
|
|
|
118
|
+
it('falls back to process builtin fs when Deno lacks sync stdio', () => {
|
|
119
|
+
const readSync = vi.fn(
|
|
120
|
+
(
|
|
121
|
+
_fd: number,
|
|
122
|
+
buffer: Uint8Array,
|
|
123
|
+
_offset?: number,
|
|
124
|
+
_length?: number,
|
|
125
|
+
_position?: number | null,
|
|
126
|
+
) => {
|
|
127
|
+
buffer.set([5, 6], 0)
|
|
128
|
+
return 2
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
const writeSync = vi.fn(
|
|
132
|
+
(
|
|
133
|
+
_fd: number,
|
|
134
|
+
_buffer: Uint8Array,
|
|
135
|
+
_offset?: number,
|
|
136
|
+
length?: number,
|
|
137
|
+
_position?: number | null,
|
|
138
|
+
) => length ?? 0,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
;(globalThis as any).Deno = {
|
|
142
|
+
stdin: {},
|
|
143
|
+
stdout: {},
|
|
144
|
+
}
|
|
145
|
+
;(globalThis as any).process = {
|
|
146
|
+
getBuiltinModule: vi.fn(() => ({
|
|
147
|
+
readSync,
|
|
148
|
+
writeSync,
|
|
149
|
+
})),
|
|
150
|
+
}
|
|
151
|
+
resetHostRuntimeForTests()
|
|
152
|
+
|
|
153
|
+
const input = NewFile(0, 'stdin')
|
|
154
|
+
const output = NewFile(1, 'stdout')
|
|
155
|
+
const readBuf = new Uint8Array(2)
|
|
156
|
+
|
|
157
|
+
const [readN, readErr] = input!.Read(readBuf)
|
|
158
|
+
expect(readN).toBe(2)
|
|
159
|
+
expect(readErr).toBeNull()
|
|
160
|
+
expect(Array.from(readBuf)).toEqual([5, 6])
|
|
161
|
+
|
|
162
|
+
const [writeN, writeErr] = output!.Write(new Uint8Array([7, 8, 9]))
|
|
163
|
+
expect(writeN).toBe(3)
|
|
164
|
+
expect(writeErr).toBeNull()
|
|
165
|
+
expect(writeSync).toHaveBeenCalledTimes(1)
|
|
166
|
+
})
|
|
167
|
+
|
|
113
168
|
it('returns EOF on zero-byte reads and ErrClosed after Close', () => {
|
|
114
169
|
const stdinReadSync = vi.fn(() => 0)
|
|
115
170
|
|
|
@@ -117,6 +172,7 @@ describe('os stdio', () => {
|
|
|
117
172
|
stdin: { readSync: stdinReadSync },
|
|
118
173
|
}
|
|
119
174
|
delete (globalThis as any).process
|
|
175
|
+
resetHostRuntimeForTests()
|
|
120
176
|
|
|
121
177
|
const input = NewFile(0, 'stdin')!
|
|
122
178
|
const [readN, readErr] = input.Read(new Uint8Array(1))
|
|
@@ -128,4 +184,51 @@ describe('os stdio', () => {
|
|
|
128
184
|
expect(closedN).toBe(0)
|
|
129
185
|
expect(closedErr).toBe(ErrClosed)
|
|
130
186
|
})
|
|
187
|
+
|
|
188
|
+
it('retries short writes until the full buffer is written', () => {
|
|
189
|
+
const writeSync = vi
|
|
190
|
+
.fn<(buffer: Uint8Array) => number>()
|
|
191
|
+
.mockImplementationOnce((_buffer: Uint8Array) => 2)
|
|
192
|
+
.mockImplementationOnce((buffer: Uint8Array) => buffer.length)
|
|
193
|
+
|
|
194
|
+
;(globalThis as any).Deno = {
|
|
195
|
+
stdout: { writeSync },
|
|
196
|
+
}
|
|
197
|
+
delete (globalThis as any).process
|
|
198
|
+
resetHostRuntimeForTests()
|
|
199
|
+
|
|
200
|
+
const output = NewFile(1, 'stdout')!
|
|
201
|
+
const [writeN, writeErr] = output.Write(new Uint8Array([1, 2, 3, 4, 5]))
|
|
202
|
+
expect(writeN).toBe(5)
|
|
203
|
+
expect(writeErr).toBeNull()
|
|
204
|
+
expect(writeSync).toHaveBeenCalledTimes(2)
|
|
205
|
+
expect(Array.from(writeSync.mock.calls[1][0])).toEqual([3, 4, 5])
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('prefers direct handle read and write methods when available', () => {
|
|
209
|
+
const handle = {
|
|
210
|
+
readSync: vi.fn((buffer: Uint8Array) => {
|
|
211
|
+
buffer.set([11, 12, 13], 0)
|
|
212
|
+
return 3
|
|
213
|
+
}),
|
|
214
|
+
writeSync: vi
|
|
215
|
+
.fn<(buffer: Uint8Array) => number>()
|
|
216
|
+
.mockImplementationOnce((_buffer: Uint8Array) => 1)
|
|
217
|
+
.mockImplementationOnce((buffer: Uint8Array) => buffer.length),
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const file = createHostFile('host-file', 99, handle)
|
|
221
|
+
const readBuf = new Uint8Array(4)
|
|
222
|
+
|
|
223
|
+
const [readN, readErr] = file.Read(readBuf)
|
|
224
|
+
expect(readN).toBe(3)
|
|
225
|
+
expect(readErr).toBeNull()
|
|
226
|
+
expect(Array.from(readBuf.slice(0, 3))).toEqual([11, 12, 13])
|
|
227
|
+
|
|
228
|
+
const [writeN, writeErr] = file.Write(new Uint8Array([21, 22, 23]))
|
|
229
|
+
expect(writeN).toBe(3)
|
|
230
|
+
expect(writeErr).toBeNull()
|
|
231
|
+
expect(handle.writeSync).toHaveBeenCalledTimes(2)
|
|
232
|
+
expect(Array.from(handle.writeSync.mock.calls[1][0])).toEqual([22, 23])
|
|
233
|
+
})
|
|
131
234
|
})
|