Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions gs/fmt/fmt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,46 @@ $.registerInterfaceType('fmt.Formatter', null, [
['verb', $.basicType('int32')],
]),
])
$.registerInterfaceType('fmt.ScanState', null, [
$.methodSignature(
'Read',
[['buf', $.sliceType($.basicType('uint8'))]],
[$.basicType('int'), 'error'],
),
$.methodSignature(
'ReadRune',
[],
[$.basicType('int32'), $.basicType('int'), 'error'],
),
$.methodSignature('SkipSpace'),
$.methodSignature(
'Token',
[
['skipSpace', $.basicType('bool')],
[
'f',
{
kind: $.TypeKind.Function,
params: [$.basicType('int32')],
results: [$.basicType('bool')],
},
],
],
[$.sliceType($.basicType('uint8')), 'error'],
),
$.methodSignature('UnreadRune', [], ['error']),
$.methodSignature('Width', [], [$.basicType('int'), $.basicType('bool')]),
])
$.registerInterfaceType('fmt.Scanner', null, [
$.methodSignature(
'Scan',
[
['state', 'fmt.ScanState'],
['verb', $.basicType('int32')],
],
['error'],
),
])

// basicValue returns the primitive inside a boxed basic interface value, or
// value itself when it is not boxed.
Expand Down
18 changes: 18 additions & 0 deletions gs/sort/sort.gs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ export interface Interface {
Swap(i: number, j: number): void | Promise<void>
}

// Interface is registered with the runtime type system, so reflection sees
// an interface type with its methods.
$.registerInterfaceType('sort.Interface', null, [
$.methodSignature('Len', [], [$.basicType('int')]),
$.methodSignature(
'Less',
[
['i', $.basicType('int')],
['j', $.basicType('int')],
],
[$.basicType('bool')],
),
$.methodSignature('Swap', [
['i', $.basicType('int')],
['j', $.basicType('int')],
]),
])

// Helper type for slice metadata
interface SliceMetadata<T> {
backing: T[]
Expand Down
9 changes: 9 additions & 0 deletions gs/sync/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import {
comparableEqual,
methodSignature,
pointerValue,
registerInterfaceType,
runtimePanic,
} from '@goscript/builtin/index.js'

Expand All @@ -15,6 +17,13 @@ export interface Locker {
Unlock(): void
}

// Locker is registered with the runtime type system, so reflection sees an
// interface type with its methods.
registerInterfaceType('sync.Locker', null, [
methodSignature('Lock'),
methodSignature('Unlock'),
])

// Mutex is a mutual exclusion lock.
export class Mutex implements Locker {
private _locked: boolean = false
Expand Down
4 changes: 4 additions & 0 deletions tests/tests/reflect_typefor/expected.log
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ index kind: float32
type: []int elem kind: int len: 0
map type: map[string]main.MyStruct
pointer type: *main.MyStruct
fmt.ScanState: fmt.ScanState interface 6
fmt.Scanner: fmt.Scanner interface 1
interface: sort.Interface interface 3
interface: sync.Locker interface 2
reflect_typefor test finished
11 changes: 11 additions & 0 deletions tests/tests/reflect_typefor/reflect_typefor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"io"
"reflect"
"sort"
"sync"
"time"
)

Expand Down Expand Up @@ -74,6 +76,15 @@ func main() {

genericComposites()

// The fmt scanning interfaces are interface types.
scanState := reflect.TypeFor[fmt.ScanState]()
println("fmt.ScanState:", scanState.String(), scanState.Kind().String(), scanState.NumMethod())
scanner := reflect.TypeFor[fmt.Scanner]()
println("fmt.Scanner:", scanner.String(), scanner.Kind().String(), scanner.NumMethod())
for _, t := range []reflect.Type{reflect.TypeFor[sort.Interface](), reflect.TypeFor[sync.Locker]()} {
println("interface:", t.String(), t.Kind().String(), t.NumMethod())
}

println("reflect_typefor test finished")
}

Expand Down
52 changes: 43 additions & 9 deletions tests/tests/reflect_typefor/reflect_typefor.gs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import * as $ from "@goscript/builtin/index.js"
import * as fmt from "@goscript/fmt/index.js"
import * as io from "@goscript/io/index.js"
import * as reflect from "@goscript/reflect/index.js"
import * as sort from "@goscript/sort/index.js"
import * as sync from "@goscript/sync/index.js"
import * as time from "@goscript/time/index.js"
import * as __goscript_other from "./other.gs.ts"
import "@goscript/fmt/index.js"
import "@goscript/io/index.js"
import "@goscript/sort/index.js"
import "@goscript/sync/index.js"

export type MyInterface = {
SomeMethod(): void
Expand Down Expand Up @@ -152,6 +156,16 @@ export async function main(): globalThis.Promise<void> {

await genericComposites()

// The fmt scanning interfaces are interface types.
let scanState = reflect.TypeFor(__goscriptStatic15())
await $.println("fmt.ScanState:", (__goscriptAwait = (scanState !== null && (scanState as any).__isVarRef !== true && ((scanState as any).__goValue === undefined || (scanState as any).__goType?.charCodeAt(0) !== 42) ? (scanState as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanState)).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), reflect.Kind_String((__goscriptAwait = (scanState !== null && (scanState as any).__isVarRef !== true && ((scanState as any).__goValue === undefined || (scanState as any).__goType?.charCodeAt(0) !== 42) ? (scanState as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanState)).Kind(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)), (__goscriptAwait = (scanState !== null && (scanState as any).__isVarRef !== true && ((scanState as any).__goValue === undefined || (scanState as any).__goType?.charCodeAt(0) !== 42) ? (scanState as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanState)).NumMethod(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait))
let scanner = reflect.TypeFor(__goscriptStatic16())
await $.println("fmt.Scanner:", (__goscriptAwait = (scanner !== null && (scanner as any).__isVarRef !== true && ((scanner as any).__goValue === undefined || (scanner as any).__goType?.charCodeAt(0) !== 42) ? (scanner as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanner)).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), reflect.Kind_String((__goscriptAwait = (scanner !== null && (scanner as any).__isVarRef !== true && ((scanner as any).__goValue === undefined || (scanner as any).__goType?.charCodeAt(0) !== 42) ? (scanner as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanner)).Kind(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)), (__goscriptAwait = (scanner !== null && (scanner as any).__isVarRef !== true && ((scanner as any).__goValue === undefined || (scanner as any).__goType?.charCodeAt(0) !== 42) ? (scanner as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(scanner)).NumMethod(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait))
for (let __goscriptRangeTarget0 = $.arrayToSlice<reflect.Type | null>([reflect.TypeFor(__goscriptStatic17()), reflect.TypeFor(__goscriptStatic18())]), __goscriptRangeWindow0 = $.sliceRange(__goscriptRangeTarget0), __rangeIndex = 0; __rangeIndex < __goscriptRangeWindow0.length; __rangeIndex++) {
let t = (__goscriptRangeWindow0.backing[__goscriptRangeWindow0.offset + __rangeIndex] as reflect.Type | null)
await $.println("interface:", (__goscriptAwait = (t !== null && (t as any).__isVarRef !== true && ((t as any).__goValue === undefined || (t as any).__goType?.charCodeAt(0) !== 42) ? (t as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(t)).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), reflect.Kind_String((__goscriptAwait = (t !== null && (t as any).__isVarRef !== true && ((t as any).__goValue === undefined || (t as any).__goType?.charCodeAt(0) !== 42) ? (t as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(t)).Kind(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)), (__goscriptAwait = (t !== null && (t as any).__isVarRef !== true && ((t as any).__goValue === undefined || (t as any).__goType?.charCodeAt(0) !== 42) ? (t as Exclude<reflect.Type, null>) : $.pointerValue<Exclude<reflect.Type, null>>(t)).NumMethod(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait))
}

await $.println("reflect_typefor test finished")
}

Expand All @@ -172,11 +186,11 @@ export async function describePointer(__typeArgs: $.GenericTypeArgs | undefined,
}

export async function genericComposites(): globalThis.Promise<void> {
await describe(__goscriptStatic15(), $.arrayToSlice<MyStruct>([new MyStruct(true, "a", 1)]))
await describe(__goscriptStatic16(), $.typedSliceOf(Float32Array, [1, 2, 3]) as $.Slice<number>)
await describe(__goscriptStatic17(), $.arrayToSlice<number>([]))
await describeMap(__goscriptStatic18(), $.makeMap<string, MyStruct>([]))
await describePointer(__goscriptStatic15(), new MyStruct())
await describe(__goscriptStatic19(), $.arrayToSlice<MyStruct>([new MyStruct(true, "a", 1)]))
await describe(__goscriptStatic20(), $.typedSliceOf(Float32Array, [1, 2, 3]) as $.Slice<number>)
await describe(__goscriptStatic21(), $.arrayToSlice<number>([]))
await describeMap(__goscriptStatic22(), $.makeMap<string, MyStruct>([]))
await describePointer(__goscriptStatic19(), new MyStruct())
}

var __goscriptStatic0$value: any
Expand Down Expand Up @@ -256,22 +270,42 @@ function __goscriptStatic14(): any {

var __goscriptStatic15$value: any
function __goscriptStatic15(): any {
return __goscriptStatic15$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: "main.MyStruct", zero: () => new MyStruct(true) }})
return __goscriptStatic15$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: "fmt.ScanState", zero: () => null, methods: {Read: (receiver: any, ...args: any[]) => receiver.Read(...$.stripGenericTypeArgs(args)), ReadRune: (receiver: any) => receiver.ReadRune(), SkipSpace: (receiver: any) => receiver.SkipSpace(), Token: (receiver: any, ...args: any[]) => receiver.Token(...$.stripGenericTypeArgs(args)), UnreadRune: (receiver: any) => receiver.UnreadRune(), Width: (receiver: any) => receiver.Width()} }})
}

var __goscriptStatic16$value: any
function __goscriptStatic16(): any {
return __goscriptStatic16$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: /* @__PURE__ */ $.basicType("float32"), zero: () => 0 }})
return __goscriptStatic16$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: "fmt.Scanner", zero: () => null, methods: {Scan: (receiver: any, ...args: any[]) => receiver.Scan(...$.stripGenericTypeArgs(args))} }})
}

var __goscriptStatic17$value: any
function __goscriptStatic17(): any {
return __goscriptStatic17$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: /* @__PURE__ */ $.basicType("int"), zero: () => 0 }})
return __goscriptStatic17$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: "sort.Interface", zero: () => null, methods: {Len: (receiver: any) => receiver.Len(), Less: (receiver: any, ...args: any[]) => receiver.Less(...$.stripGenericTypeArgs(args)), Swap: (receiver: any, ...args: any[]) => receiver.Swap(...$.stripGenericTypeArgs(args))} }})
}

var __goscriptStatic18$value: any
function __goscriptStatic18(): any {
return __goscriptStatic18$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, K: { type: /* @__PURE__ */ $.basicType("string"), zero: () => "" }, V: { type: "main.MyStruct", zero: () => new MyStruct(true) }})
return __goscriptStatic18$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: "sync.Locker", zero: () => null, methods: {Lock: (receiver: any) => receiver.Lock(), Unlock: (receiver: any) => receiver.Unlock()} }})
}

var __goscriptStatic19$value: any
function __goscriptStatic19(): any {
return __goscriptStatic19$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: "main.MyStruct", zero: () => new MyStruct(true) }})
}

var __goscriptStatic20$value: any
function __goscriptStatic20(): any {
return __goscriptStatic20$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: /* @__PURE__ */ $.basicType("float32"), zero: () => 0 }})
}

var __goscriptStatic21$value: any
function __goscriptStatic21(): any {
return __goscriptStatic21$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, E: { type: /* @__PURE__ */ $.basicType("int"), zero: () => 0 }})
}

var __goscriptStatic22$value: any
function __goscriptStatic22(): any {
return __goscriptStatic22$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, K: { type: /* @__PURE__ */ $.basicType("string"), zero: () => "" }, V: { type: "main.MyStruct", zero: () => new MyStruct(true) }})
}

var __goscriptAwait: any
Expand Down
Loading