goscript 0.0.76 → 0.0.78

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 (89) hide show
  1. package/compiler/analysis.go +100 -33
  2. package/compiler/analysis_test.go +2 -7
  3. package/compiler/code-writer.go +2 -2
  4. package/compiler/compiler.go +4 -4
  5. package/compiler/composite-lit.go +4 -6
  6. package/compiler/constraint.go +2 -4
  7. package/compiler/decl.go +34 -0
  8. package/compiler/expr-call-async.go +4 -0
  9. package/compiler/expr-call-helpers.go +98 -8
  10. package/compiler/expr-call-make.go +4 -4
  11. package/compiler/expr-call.go +3 -0
  12. package/compiler/expr-type.go +42 -0
  13. package/compiler/gs_dependencies_test.go +3 -14
  14. package/compiler/index.ts +20 -5
  15. package/compiler/protobuf.go +21 -21
  16. package/compiler/spec-struct.go +195 -30
  17. package/compiler/spec.go +32 -3
  18. package/compiler/stmt-assign.go +2 -2
  19. package/compiler/type-info.go +20 -3
  20. package/compiler/type-utils.go +2 -4
  21. package/compiler/type.go +3 -4
  22. package/dist/compiler/index.js +13 -4
  23. package/dist/compiler/index.js.map +1 -1
  24. package/dist/gs/builtin/slice.js +2 -3
  25. package/dist/gs/builtin/slice.js.map +1 -1
  26. package/dist/gs/builtin/type.d.ts +1 -0
  27. package/dist/gs/builtin/type.js +8 -14
  28. package/dist/gs/builtin/type.js.map +1 -1
  29. package/dist/gs/bytes/buffer.gs.d.ts +1 -0
  30. package/dist/gs/bytes/buffer.gs.js +20 -0
  31. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  32. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +5 -0
  33. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +10 -0
  34. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -0
  35. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.d.ts +50 -0
  36. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js +221 -0
  37. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -0
  38. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.d.ts +1 -0
  39. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.js +2 -0
  40. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.js.map +1 -0
  41. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.d.ts +1 -0
  42. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.js +2 -0
  43. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.js.map +1 -0
  44. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.d.ts +56 -0
  45. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.js +17 -0
  46. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.js.map +1 -0
  47. package/dist/gs/io/fs/format.js +2 -6
  48. package/dist/gs/io/fs/format.js.map +1 -1
  49. package/dist/gs/io/fs/glob.js +18 -23
  50. package/dist/gs/io/fs/glob.js.map +1 -1
  51. package/dist/gs/path/match.js +9 -22
  52. package/dist/gs/path/match.js.map +1 -1
  53. package/dist/gs/reflect/index.d.ts +1 -1
  54. package/dist/gs/reflect/index.js +1 -1
  55. package/dist/gs/reflect/index.js.map +1 -1
  56. package/dist/gs/reflect/type.d.ts +1 -0
  57. package/dist/gs/reflect/type.js +52 -23
  58. package/dist/gs/reflect/type.js.map +1 -1
  59. package/dist/gs/strings/iter.js +1 -1
  60. package/dist/gs/strings/iter.js.map +1 -1
  61. package/dist/gs/strings/reader.js +1 -1
  62. package/dist/gs/strings/reader.js.map +1 -1
  63. package/dist/gs/strings/replace.js +9 -20
  64. package/dist/gs/strings/replace.js.map +1 -1
  65. package/dist/gs/time/time.js +2 -2
  66. package/dist/gs/time/time.js.map +1 -1
  67. package/go.mod +1 -1
  68. package/go.sum +2 -2
  69. package/gs/builtin/slice.ts +2 -2
  70. package/gs/builtin/type.ts +14 -14
  71. package/gs/bytes/buffer.gs.ts +21 -1
  72. package/gs/fmt/fmt.test.ts +1 -1
  73. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +14 -0
  74. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +238 -0
  75. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.ts +1 -0
  76. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +12 -0
  77. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.ts +1 -0
  78. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/meta.json +8 -0
  79. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.ts +94 -0
  80. package/gs/io/fs/format.ts +2 -5
  81. package/gs/io/fs/glob.ts +18 -21
  82. package/gs/path/match.ts +9 -22
  83. package/gs/reflect/index.ts +1 -0
  84. package/gs/reflect/type.ts +62 -25
  85. package/gs/strings/iter.ts +1 -1
  86. package/gs/strings/reader.ts +1 -1
  87. package/gs/strings/replace.ts +13 -18
  88. package/gs/time/time.ts +2 -2
  89. package/package.json +18 -15
@@ -0,0 +1,238 @@
1
+ // Package browser_runtime implements VmRuntime backed by the browser
2
+ // WebAssembly API. Pure TypeScript -- no syscall/js indirection.
3
+
4
+ import type * as vmruntime from '../runtime.js'
5
+
6
+ // Runtime implements VmRuntime using the browser WebAssembly API.
7
+ export class Runtime implements vmruntime.VmRuntime {
8
+ constructor() {}
9
+
10
+ // Compile calls WebAssembly.compile and returns a Module.
11
+ async Compile(
12
+ _ctx: any,
13
+ wasm: Uint8Array | number[],
14
+ ): Promise<Module> {
15
+ const bytes = wasm instanceof Uint8Array ? wasm : new Uint8Array(wasm)
16
+ const compiled = await WebAssembly.compile(bytes.buffer as ArrayBuffer)
17
+ return new Module(compiled)
18
+ }
19
+
20
+ // Close is a no-op for the browser runtime.
21
+ async Close(_ctx: any): Promise<null> {
22
+ return null
23
+ }
24
+ }
25
+
26
+ // New creates a new browser-backed VmRuntime.
27
+ export function New(): Runtime {
28
+ return new Runtime()
29
+ }
30
+
31
+ // Module wraps a WebAssembly.Module.
32
+ export class Module implements vmruntime.VmModule {
33
+ constructor(private readonly wasmModule: WebAssembly.Module) {}
34
+
35
+ // Instantiate creates an instance with host functions wired as imports.
36
+ async Instantiate(
37
+ ctx: any,
38
+ config: vmruntime.VmModuleConfig,
39
+ ): Promise<Instance> {
40
+ const imports = this.buildImports(ctx, config.HostFunctions)
41
+ const wasmInst = await WebAssembly.instantiate(this.wasmModule, imports)
42
+ const inst = new Instance(wasmInst)
43
+ // Patch the captured instance reference in host function closures.
44
+ if ((imports as any).__instRef) {
45
+ ;(imports as any).__instRef.current = inst
46
+ }
47
+ return inst
48
+ }
49
+
50
+ // Close is a no-op.
51
+ async Close(_ctx: any): Promise<null> {
52
+ return null
53
+ }
54
+
55
+ // buildImports constructs the WebAssembly imports object.
56
+ private buildImports(
57
+ ctx: any,
58
+ hostFns: Map<string, vmruntime.HostFunction> | null,
59
+ ): WebAssembly.Imports {
60
+ const imports: Record<string, Record<string, WebAssembly.ImportValue>> = {}
61
+ if (!hostFns) return imports
62
+
63
+ // Shared mutable ref -- patched after instantiation.
64
+ const instRef: { current: Instance | null } = { current: null }
65
+
66
+ hostFns.forEach((fn, key) => {
67
+ let modName = 'env'
68
+ let funcName = key
69
+ const dot = key.indexOf('.')
70
+ if (dot !== -1) {
71
+ modName = key.substring(0, dot)
72
+ funcName = key.substring(dot + 1)
73
+ }
74
+ if (!imports[modName]) imports[modName] = {}
75
+
76
+ imports[modName][funcName] = (...args: number[]) => {
77
+ const stack = new BigInt64Array(args.length)
78
+ for (let i = 0; i < args.length; i++) {
79
+ stack[i] = BigInt(args[i])
80
+ }
81
+ const u64Stack: number[] = args.map((a) => a >>> 0)
82
+ const err = fn(ctx, instRef.current, u64Stack)
83
+ if (err) throw err
84
+ // WASM i32 return: first stack element.
85
+ if (u64Stack.length > 0) return u64Stack[0]
86
+ }
87
+ })
88
+
89
+ // Stash the ref so Instantiate can patch it.
90
+ ;(imports as any).__instRef = instRef
91
+ return imports
92
+ }
93
+ }
94
+
95
+ // Instance wraps a WebAssembly.Instance.
96
+ export class Instance implements vmruntime.VmInstance {
97
+ private readonly exports: WebAssembly.Exports
98
+
99
+ constructor(private readonly wasmInstance: WebAssembly.Instance) {
100
+ this.exports = wasmInstance.exports
101
+ }
102
+
103
+ // Call invokes an exported function by name.
104
+ async Call(
105
+ _ctx: any,
106
+ name: string,
107
+ ...args: number[]
108
+ ): Promise<number[] | null> {
109
+ const fn = this.exports[name]
110
+ if (typeof fn !== 'function') return null
111
+ const result = (fn as (...args: number[]) => unknown)(...args)
112
+ if (result === undefined) return null
113
+ return [result as number]
114
+ }
115
+
116
+ // Memory returns the instance's linear memory.
117
+ Memory(): BrowserMemory | null {
118
+ const mem = this.exports.memory
119
+ if (!(mem instanceof WebAssembly.Memory)) return null
120
+ return new BrowserMemory(mem)
121
+ }
122
+
123
+ // ExportedFunction returns a callable reference.
124
+ ExportedFunction(name: string): BrowserFunction | null {
125
+ const fn = this.exports[name]
126
+ if (typeof fn !== 'function') return null
127
+ return new BrowserFunction(fn as (...args: number[]) => unknown)
128
+ }
129
+
130
+ // ExportedGlobal returns a reference to an exported global.
131
+ ExportedGlobal(name: string): BrowserGlobal | null {
132
+ const g = this.exports[name]
133
+ if (!(g instanceof WebAssembly.Global)) return null
134
+ return new BrowserGlobal(g)
135
+ }
136
+
137
+ // Close is a no-op.
138
+ async Close(_ctx: any): Promise<null> {
139
+ return null
140
+ }
141
+ }
142
+
143
+ // BrowserFunction wraps a WebAssembly exported function.
144
+ export class BrowserFunction implements vmruntime.VmFunction {
145
+ constructor(private readonly fn: (...args: number[]) => unknown) {}
146
+
147
+ async Call(_ctx: any, ...args: number[]): Promise<number[] | null> {
148
+ const result = this.fn(...args)
149
+ if (result === undefined) return null
150
+ return [result as number]
151
+ }
152
+ }
153
+
154
+ // BrowserGlobal wraps a WebAssembly.Global.
155
+ export class BrowserGlobal implements vmruntime.VmGlobal {
156
+ constructor(private readonly global: WebAssembly.Global) {}
157
+
158
+ Get(): number {
159
+ return this.global.value as number
160
+ }
161
+
162
+ Set(val: number): void {
163
+ this.global.value = val
164
+ }
165
+ }
166
+
167
+ // BrowserMemory wraps WebAssembly.Memory with typed DataView access.
168
+ export class BrowserMemory implements vmruntime.VmMemory {
169
+ constructor(private readonly mem: WebAssembly.Memory) {}
170
+
171
+ private get buf(): ArrayBuffer {
172
+ return this.mem.buffer
173
+ }
174
+
175
+ Read(offset: number, length: number): [Uint8Array, boolean] {
176
+ if (offset + length > this.buf.byteLength) return [new Uint8Array(0), false]
177
+ return [new Uint8Array(this.buf, offset, length), true]
178
+ }
179
+
180
+ ReadByteAt(offset: number): [number, boolean] {
181
+ if (offset >= this.buf.byteLength) return [0, false]
182
+ return [new Uint8Array(this.buf, offset, 1)[0], true]
183
+ }
184
+
185
+ ReadUint32Le(offset: number): [number, boolean] {
186
+ if (offset + 4 > this.buf.byteLength) return [0, false]
187
+ return [new DataView(this.buf).getUint32(offset, true), true]
188
+ }
189
+
190
+ ReadUint64Le(offset: number): [bigint, boolean] {
191
+ if (offset + 8 > this.buf.byteLength) return [0n, false]
192
+ const dv = new DataView(this.buf)
193
+ const lo = BigInt(dv.getUint32(offset, true))
194
+ const hi = BigInt(dv.getUint32(offset + 4, true))
195
+ return [lo | (hi << 32n), true]
196
+ }
197
+
198
+ Write(offset: number, data: Uint8Array | number[]): boolean {
199
+ const bytes = data instanceof Uint8Array ? data : new Uint8Array(data)
200
+ if (offset + bytes.length > this.buf.byteLength) return false
201
+ new Uint8Array(this.buf, offset, bytes.length).set(bytes)
202
+ return true
203
+ }
204
+
205
+ WriteByteAt(offset: number, val: number): boolean {
206
+ if (offset >= this.buf.byteLength) return false
207
+ new Uint8Array(this.buf, offset, 1)[0] = val
208
+ return true
209
+ }
210
+
211
+ WriteUint32Le(offset: number, val: number): boolean {
212
+ if (offset + 4 > this.buf.byteLength) return false
213
+ new DataView(this.buf).setUint32(offset, val, true)
214
+ return true
215
+ }
216
+
217
+ WriteUint64Le(offset: number, val: bigint | number): boolean {
218
+ if (offset + 8 > this.buf.byteLength) return false
219
+ const v = typeof val === 'bigint' ? val : BigInt(val)
220
+ const dv = new DataView(this.buf)
221
+ dv.setUint32(offset, Number(v & 0xffffffffn), true)
222
+ dv.setUint32(offset + 4, Number((v >> 32n) & 0xffffffffn), true)
223
+ return true
224
+ }
225
+
226
+ Size(): number {
227
+ return this.buf.byteLength
228
+ }
229
+
230
+ Grow(pages: number): [number, boolean] {
231
+ try {
232
+ const prev = this.mem.grow(pages)
233
+ return [prev, true]
234
+ } catch {
235
+ return [0, false]
236
+ }
237
+ }
238
+ }
@@ -0,0 +1 @@
1
+ export * from './browser.js'
@@ -0,0 +1,12 @@
1
+ {
2
+ "dependencies": [],
3
+ "asyncMethods": {
4
+ "Runtime.Compile": true,
5
+ "Runtime.Close": true,
6
+ "Module.Instantiate": true,
7
+ "Module.Close": true,
8
+ "Instance.Call": true,
9
+ "Instance.Close": true,
10
+ "Function.Call": true
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ export * from './runtime.js'
@@ -0,0 +1,8 @@
1
+ {
2
+ "dependencies": [],
3
+ "asyncMethods": {
4
+ "ExitError.Error": false,
5
+ "ExitError.ExitCode": false,
6
+ "NewExitError": false
7
+ }
8
+ }
@@ -0,0 +1,94 @@
1
+ // Package vmruntime defines abstract interfaces for WASM execution engines.
2
+
3
+ // VmRuntime abstracts the WASM execution engine.
4
+ export interface VmRuntime {
5
+ Compile(ctx: any, wasm: Uint8Array | number[]): Promise<VmModule>
6
+ Close(ctx: any): Promise<any>
7
+ }
8
+
9
+ // VmModule represents a compiled WASM module.
10
+ export interface VmModule {
11
+ Instantiate(ctx: any, config: VmModuleConfig): Promise<VmInstance>
12
+ Close(ctx: any): Promise<any>
13
+ }
14
+
15
+ // VmModuleConfig contains configuration for module instantiation.
16
+ export interface VmModuleConfig {
17
+ Name: string
18
+ Args: string[] | null
19
+ Env: string[] | null
20
+ Stdin: any
21
+ Stdout: any
22
+ Stderr: any
23
+ HostFunctions: Map<string, HostFunction> | null
24
+ }
25
+
26
+ // HostFunction is a host-provided function callable from WASM.
27
+ export type HostFunction = (
28
+ ctx: any,
29
+ inst: VmInstance | null,
30
+ stack: number[],
31
+ ) => any
32
+
33
+ // VmInstance represents a running WASM module instance.
34
+ export interface VmInstance {
35
+ Call(ctx: any, name: string, ...args: number[]): Promise<number[] | null>
36
+ Memory(): VmMemory | null
37
+ ExportedFunction(name: string): VmFunction | null
38
+ ExportedGlobal(name: string): VmGlobal | null
39
+ Close(ctx: any): Promise<any>
40
+ }
41
+
42
+ // VmFunction represents an exported WASM function.
43
+ export interface VmFunction {
44
+ Call(ctx: any, ...args: number[]): Promise<number[] | null>
45
+ }
46
+
47
+ // VmGlobal represents an exported WASM global variable.
48
+ export interface VmGlobal {
49
+ Get(): number
50
+ Set(val: number): void
51
+ }
52
+
53
+ // VmMemory abstracts access to WASM linear memory.
54
+ export interface VmMemory {
55
+ Read(offset: number, length: number): [Uint8Array | number[], boolean]
56
+ ReadByteAt(offset: number): [number, boolean]
57
+ ReadUint32Le(offset: number): [number, boolean]
58
+ ReadUint64Le(offset: number): [bigint | number, boolean]
59
+ Write(offset: number, data: Uint8Array | number[]): boolean
60
+ WriteByteAt(offset: number, val: number): boolean
61
+ WriteUint32Le(offset: number, val: number): boolean
62
+ WriteUint64Le(offset: number, val: bigint | number): boolean
63
+ Size(): number
64
+ Grow(pages: number): [number, boolean]
65
+ }
66
+
67
+ // ExitError represents a clean process exit with a status code.
68
+ export class ExitError extends Error {
69
+ public Code: number
70
+
71
+ constructor(code: number) {
72
+ super('exit: ' + code)
73
+ this.Code = code
74
+ }
75
+
76
+ ExitCode(): number {
77
+ return this.Code
78
+ }
79
+ }
80
+
81
+ // NewExitError creates an ExitError with the given code.
82
+ export function NewExitError(code: number): ExitError {
83
+ return new ExitError(code)
84
+ }
85
+
86
+ // Snapshotable is an optional extension for VmInstance.
87
+ export interface Snapshotable {
88
+ Snapshot(): Snapshot
89
+ }
90
+
91
+ // Snapshot represents a captured execution state.
92
+ export interface Snapshot {
93
+ Restore(returnValues: number[]): void
94
+ }
@@ -16,12 +16,9 @@ export function FormatFileInfo(info: FileInfo): string {
16
16
  b.push(' ')
17
17
 
18
18
  let size = info!.Size()
19
- let usize: number = 0
20
- if (size >= 0) {
21
- usize = size as number
22
- } else {
19
+ const usize = size >= 0 ? size : -size
20
+ if (size < 0) {
23
21
  b.push('-')
24
- usize = -size as number
25
22
  }
26
23
 
27
24
  b.push(usize.toString())
package/gs/io/fs/glob.ts CHANGED
@@ -70,7 +70,6 @@ export function globWithLimit(
70
70
  depth: number,
71
71
  ): [$.Slice<string>, $.GoError] {
72
72
  let matches: $.Slice<string> = null
73
- let err: $.GoError = null
74
73
  {
75
74
  // This limit is added to prevent stack exhaustion issues. See
76
75
  // CVE-2022-30630.
@@ -87,15 +86,15 @@ export function globWithLimit(
87
86
 
88
87
  // Check pattern is well-formed.
89
88
  {
90
- let [, err] = path.Match(pattern, '')
91
- if (err != null) {
92
- return [null, err]
89
+ const [, matchErr] = path.Match(pattern, '')
90
+ if (matchErr != null) {
91
+ return [null, matchErr]
93
92
  }
94
93
  }
95
94
  if (!hasMeta(pattern)) {
96
95
  {
97
- ;[, err] = Stat(fsys, pattern)
98
- if (err != null) {
96
+ const [, statErr] = Stat(fsys, pattern)
97
+ if (statErr != null) {
99
98
  return [null, null]
100
99
  }
101
100
  }
@@ -114,21 +113,21 @@ export function globWithLimit(
114
113
  return [null, path.ErrBadPattern]
115
114
  }
116
115
 
117
- let m: $.Slice<string>
118
- ;[m, err] = globWithLimit(fsys, dir, depth + 1)
119
- if (err != null) {
120
- return [null, err]
116
+ const [dirs, dirErr] = globWithLimit(fsys, dir, depth + 1)
117
+ if (dirErr != null) {
118
+ return [null, dirErr]
121
119
  }
122
- for (let _i = 0; _i < $.len(m); _i++) {
123
- const d = m![_i]
120
+ for (let _i = 0; _i < $.len(dirs); _i++) {
121
+ const d = dirs![_i]
124
122
  {
125
- ;[matches, err] = glob(fsys, d, file, matches)
126
- if (err != null) {
127
- return [matches, err]
123
+ const [nextMatches, globErr] = glob(fsys, d, file, matches)
124
+ matches = nextMatches
125
+ if (globErr != null) {
126
+ return [matches, globErr]
128
127
  }
129
128
  }
130
129
  }
131
- return [matches, err]
130
+ return [matches, null]
132
131
  }
133
132
  }
134
133
 
@@ -155,15 +154,13 @@ export function glob(
155
154
  pattern: string,
156
155
  matches: $.Slice<string>,
157
156
  ): [$.Slice<string>, $.GoError] {
158
- let m: $.Slice<string> = null
159
- let e: $.GoError = null
157
+ let m = matches
160
158
  {
161
- m = matches
162
159
  let [infos, err] = ReadDir(fs, dir)
163
160
 
164
161
  // ignore I/O error
165
162
  if (err != null) {
166
- return [m, e]
163
+ return [m, null]
167
164
  }
168
165
 
169
166
  for (let _i = 0; _i < $.len(infos); _i++) {
@@ -179,7 +176,7 @@ export function glob(
179
176
  }
180
177
  }
181
178
  }
182
- return [m, e]
179
+ return [m, null]
183
180
  }
184
181
  }
185
182
 
package/gs/path/match.ts CHANGED
@@ -45,13 +45,7 @@ export function Match(pattern: string, name: string): [boolean, $.GoError] {
45
45
  // Before returning false with no error,
46
46
  // check that the remainder of the pattern is syntactically valid.
47
47
  Pattern: for (; $.len(pattern) > 0; ) {
48
- let star: boolean = false
49
- let chunk: string = ''
50
- let rest: string = ''
51
- let scanResult = scanChunk(pattern)
52
- star = scanResult[0]
53
- chunk = scanResult[1]
54
- rest = scanResult[2]
48
+ const [star, chunk, rest] = scanChunk(pattern)
55
49
  pattern = rest
56
50
 
57
51
  // Trailing * matches rest of string unless it has a /.
@@ -104,13 +98,7 @@ export function Match(pattern: string, name: string): [boolean, $.GoError] {
104
98
  // Before returning false with no error,
105
99
  // check that the remainder of the pattern is syntactically valid.
106
100
  for (; $.len(pattern) > 0; ) {
107
- // let star2: boolean = false
108
- let chunk2: string = ''
109
- let rest2: string = ''
110
- let scanResult2 = scanChunk(pattern)
111
- // star2 = scanResult2[0]
112
- chunk2 = scanResult2[1]
113
- rest2 = scanResult2[2]
101
+ const [, chunk2, rest2] = scanChunk(pattern)
114
102
  pattern = rest2
115
103
  {
116
104
  let [, , err] = matchChunk(chunk2, '')
@@ -135,7 +123,7 @@ export function scanChunk(pattern: string): [boolean, string, string] {
135
123
  star = true
136
124
  }
137
125
  let inrange = false
138
- let i: number = 0
126
+ let i: number
139
127
 
140
128
  // error check handled in matchChunk: bad pattern.
141
129
  Scan: for (i = 0; i < $.len(pattern); i++) {
@@ -174,7 +162,7 @@ export function matchChunk(
174
162
  chunk: string,
175
163
  s: string,
176
164
  ): [string, boolean, $.GoError] {
177
- let err: $.GoError = null
165
+ let err: $.GoError
178
166
  {
179
167
  // failed records whether the match has failed.
180
168
  // After the match fails, the loop continues on processing chunk,
@@ -200,10 +188,9 @@ export function matchChunk(
200
188
  case 91: {
201
189
  let r: number = 0
202
190
  if (!failed) {
203
- let n: number = 0
204
- let decoded = utf8.DecodeRuneInString(s)
191
+ const decoded = utf8.DecodeRuneInString(s)
205
192
  r = decoded[0]
206
- n = decoded[1]
193
+ const n = decoded[1]
207
194
  s = $.sliceString(s, n, undefined)
208
195
  }
209
196
  chunk = $.sliceString(chunk, 1, undefined)
@@ -223,10 +210,10 @@ export function matchChunk(
223
210
  chunk = $.sliceString(chunk, 1, undefined)
224
211
  break
225
212
  }
226
- let lo: number = 0
227
- let hi: number = 0
213
+ let lo: number
214
+ let hi: number
228
215
  {
229
- let escResult = getEsc(chunk)
216
+ const escResult = getEsc(chunk)
230
217
  lo = escResult[0]
231
218
  chunk = escResult[1]
232
219
  err = escResult[2]
@@ -16,6 +16,7 @@ export {
16
16
  SendDir,
17
17
  BothDir,
18
18
  getInterfaceTypeByName,
19
+ getInterfaceLiteralTypeByName,
19
20
  } from './type.js'
20
21
  export type { Type, ChanDir, Kind } from './type.js'
21
22
  export { DeepEqual } from './deepequal.js'
@@ -1492,7 +1492,10 @@ function typeImplementsInterface(
1492
1492
  interfaceType: Type,
1493
1493
  ): boolean {
1494
1494
  // Get the interface name and look it up in the type registry
1495
- const interfaceName = interfaceType.String()
1495
+ const interfaceName =
1496
+ interfaceType instanceof InterfaceType ?
1497
+ interfaceType.registeredName() || interfaceType.String()
1498
+ : interfaceType.String()
1496
1499
  const interfaceTypeInfo = builtinGetTypeByName(interfaceName)
1497
1500
 
1498
1501
  if (!interfaceTypeInfo || !isInterfaceTypeInfo(interfaceTypeInfo)) {
@@ -1797,7 +1800,10 @@ class ChannelType implements Type {
1797
1800
 
1798
1801
  // Interface type implementation
1799
1802
  class InterfaceType implements Type {
1800
- constructor(private _name: string = 'interface{}') {}
1803
+ constructor(
1804
+ private _name: string = 'interface{}',
1805
+ private _registeredName?: string,
1806
+ ) {}
1801
1807
 
1802
1808
  public String(): string {
1803
1809
  return this._name
@@ -1820,10 +1826,30 @@ class InterfaceType implements Type {
1820
1826
  }
1821
1827
 
1822
1828
  public PkgPath?(): string {
1829
+ if (
1830
+ this._name === 'interface{}' ||
1831
+ this._name.startsWith('interface {')
1832
+ ) {
1833
+ return ''
1834
+ }
1835
+ const dotIndex = this._name.lastIndexOf('.')
1836
+ if (dotIndex > 0) {
1837
+ return this._name.substring(0, dotIndex)
1838
+ }
1823
1839
  return ''
1824
1840
  }
1825
1841
 
1826
1842
  public Name(): string {
1843
+ if (
1844
+ this._name === 'interface{}' ||
1845
+ this._name.startsWith('interface {')
1846
+ ) {
1847
+ return this._name
1848
+ }
1849
+ const dotIndex = this._name.lastIndexOf('.')
1850
+ if (dotIndex >= 0) {
1851
+ return this._name.substring(dotIndex + 1)
1852
+ }
1827
1853
  return this._name
1828
1854
  }
1829
1855
 
@@ -1868,6 +1894,10 @@ class InterfaceType implements Type {
1868
1894
  public Bits(): number {
1869
1895
  throw new Error('reflect: call of reflect.Type.Bits on interface Type')
1870
1896
  }
1897
+
1898
+ public registeredName(): string | undefined {
1899
+ return this._registeredName
1900
+ }
1871
1901
  }
1872
1902
 
1873
1903
  function getTypeOf(value: ReflectValue): Type {
@@ -2161,30 +2191,37 @@ export function TypeFor(): Type {
2161
2191
  export function getInterfaceTypeByName(name: string): Type {
2162
2192
  const typeInfo = builtinGetTypeByName(name)
2163
2193
  if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2164
- // InterfaceTypeInfo
2194
+ return new InterfaceType(name, name)
2195
+ }
2196
+ return new InterfaceType('interface{}')
2197
+ }
2198
+
2199
+ export function getInterfaceLiteralTypeByName(name: string): Type {
2200
+ const typeInfo = builtinGetTypeByName(name)
2201
+ if (typeInfo && typeInfo.kind === TypeKind.Interface) {
2165
2202
  const methods = (typeInfo as any).methods || []
2166
- if (methods.length > 0) {
2167
- // Build interface signature with methods
2168
- const methodSigs = methods
2169
- .map((m: any) => {
2170
- const args =
2171
- m.args
2172
- ?.map((a: any) => (typeof a === 'string' ? a : 'any'))
2173
- .join(', ') || ''
2174
- const returns = m.returns?.map((r: any) =>
2175
- typeof r === 'string' ? r : 'any',
2176
- )
2177
- let returnSig = ''
2178
- if (returns && returns.length === 1) {
2179
- returnSig = ` ${returns[0]}`
2180
- } else if (returns && returns.length > 1) {
2181
- returnSig = ` (${returns.join(', ')})`
2182
- }
2183
- return `${m.name}(${args})${returnSig}`
2184
- })
2185
- .join('; ')
2186
- return new InterfaceType(`interface { ${methodSigs} }`)
2187
- }
2203
+ if (methods.length === 0) {
2204
+ return new InterfaceType('interface{}', name)
2205
+ }
2206
+ const methodSigs = methods
2207
+ .map((m: any) => {
2208
+ const args =
2209
+ m.args
2210
+ ?.map((a: any) => (typeof a === 'string' ? a : 'any'))
2211
+ .join(', ') || ''
2212
+ const returns = m.returns?.map((r: any) =>
2213
+ typeof r === 'string' ? r : 'any',
2214
+ )
2215
+ let returnSig = ''
2216
+ if (returns && returns.length === 1) {
2217
+ returnSig = ` ${returns[0]}`
2218
+ } else if (returns && returns.length > 1) {
2219
+ returnSig = ` (${returns.join(', ')})`
2220
+ }
2221
+ return `${m.name}(${args})${returnSig}`
2222
+ })
2223
+ .join('; ')
2224
+ return new InterfaceType(`interface { ${methodSigs} }`, name)
2188
2225
  }
2189
2226
  return new InterfaceType('interface{}')
2190
2227
  }
@@ -25,7 +25,7 @@ const asciiSpace: { [key: number]: boolean } = {
25
25
  export function Lines(s: string): iter.Seq<string> {
26
26
  return (_yield: ((p0: string) => boolean) | null): void => {
27
27
  for (; $.len(s) > 0; ) {
28
- let line: string = ''
28
+ let line: string
29
29
  {
30
30
  let i = IndexByte(s, 10)
31
31
  if (i >= 0) {