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
255 changes: 248 additions & 7 deletions gs/reflect/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,21 @@ export interface Type {
// NumMethod returns the number of methods in the type's method set
NumMethod(): number

// Methods returns an iterator over the methods of the type's method set.
Methods(): iter.Seq<Method>

// Fields returns an iterator over the fields of a struct type.
// Panics if the type's Kind is not Struct.
Fields(): iter.Seq<StructField>

// Ins returns an iterator over the input types of a function type.
// Panics if the type's Kind is not Func.
Ins(): iter.Seq<Type>

// Outs returns an iterator over the output types of a function type.
// Panics if the type's Kind is not Func.
Outs(): iter.Seq<Type>

// Method returns the i'th method in the type's method set.
Method(i: number): Method

Expand Down Expand Up @@ -549,6 +564,63 @@ export interface Type {
CanSeq2(): boolean
}

// typeMethodsSeq returns an iterator over the methods of the method set of
// t, as Type.Methods does.
function typeMethodsSeq(t: Type): iter.Seq<Method> {
return async (_yield: ((m: Method) => iter.YieldResult) | null) => {
for (let i = 0; i < t.NumMethod(); i++) {
if (!(await _yield!(t.Method(i)))) {
return
}
}
}
}

// typeFieldsSeq returns an iterator over the fields of the struct type t, as
// Type.Fields does.
function typeFieldsSeq(t: Type): iter.Seq<StructField> {
if (t.Kind() !== Struct) {
throw new Error('reflect: Fields of non-struct type ' + t.String())
}
return async (_yield: ((f: StructField) => iter.YieldResult) | null) => {
for (let i = 0; i < t.NumField(); i++) {
if (!(await _yield!(t.Field(i)))) {
return
}
}
}
}

// typeInsSeq returns an iterator over the input types of the function type
// t, as Type.Ins does.
function typeInsSeq(t: Type): iter.Seq<Type> {
if (t.Kind() !== Func) {
throw new Error('reflect: Ins of non-func type ' + t.String())
}
return async (_yield: ((in_: Type) => iter.YieldResult) | null) => {
for (let i = 0; i < t.NumIn(); i++) {
if (!(await _yield!(t.In(i)))) {
return
}
}
}
}

// typeOutsSeq returns an iterator over the output types of the function
// type t, as Type.Outs does.
function typeOutsSeq(t: Type): iter.Seq<Type> {
if (t.Kind() !== Func) {
throw new Error('reflect: Outs of non-func type ' + t.String())
}
return async (_yield: ((out: Type) => iter.YieldResult) | null) => {
for (let i = 0; i < t.NumOut(); i++) {
if (!(await _yield!(t.Out(i)))) {
return
}
}
}
}

// nonChanTypePanic panics for ChanDir on a type that is not a channel.
function nonChanTypePanic(t: Type): never {
throw new Error(`reflect: ChanDir of non-chan type ${t.String()}`)
Expand Down Expand Up @@ -710,6 +782,22 @@ class InvalidTypeClass implements Type {
OverflowFloat(_x: number): boolean {
throw new Error('reflect: OverflowFloat of invalid type')
}
public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

NumMethod(): number {
return 0
}
Expand Down Expand Up @@ -2585,6 +2673,22 @@ export class BasicType implements Type {
)
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -2774,6 +2878,22 @@ class SliceType implements Type {
throw new Error('reflect: call of reflect.Type.OverflowFloat on slice Type')
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -2931,6 +3051,22 @@ class ArrayType implements Type {
throw new Error('reflect: call of reflect.Type.OverflowFloat on array Type')
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -3082,6 +3218,22 @@ class PointerType implements Type {
)
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -3291,6 +3443,22 @@ class FunctionType implements Type {
throw new Error('reflect: call of reflect.Type.OverflowFloat on func Type')
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -3813,6 +3981,22 @@ class MapType implements Type {
throw new Error('reflect: call of reflect.Type.OverflowFloat on map Type')
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -4093,7 +4277,7 @@ export function visibleStructFields(t: Type): StructField[] {
function zeroMethod(): Method {
return new Method({
Type: new BasicType(Invalid, '<invalid>'),
Func: () => undefined,
Func: new Value(),
})
}

Expand All @@ -4102,18 +4286,27 @@ function methodFromSignature(
index: number,
receiver: Type,
): Method {
const iface = receiver.Kind() === Interface
const type = methodTypeFromSignature(signature, receiver, !iface)
return new Method({
Name: signature.name,
Type: methodTypeFromSignature(
signature,
receiver,
receiver.Kind() !== Interface,
),
Func: () => undefined,
Type: type,
Func: iface ? new Value() : methodFuncValue(signature.name, receiver, type),
Index: index,
})
}

// methodFuncValue returns the method name of the type receiver as a function
// of type type, which takes the receiver as its first argument, as
// Method.Func is.
function methodFuncValue(name: string, receiver: Type, type: Type): Value {
const fn = (recv: ReflectValue, ...args: unknown[]): unknown => {
const bound = new Value(recv, receiver).MethodByName(name).currentValue()
return (bound as (...args: unknown[]) => unknown)(...args)
}
return new Value(fn, type)
}

function methodTypeFromSignature(
signature: $.MethodSignature,
receiver: Type,
Expand Down Expand Up @@ -4681,6 +4874,22 @@ class StructType implements Type {
)
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down Expand Up @@ -5015,6 +5224,22 @@ class ChannelType implements Type {
throw new Error('reflect: call of reflect.Type.OverflowFloat on chan Type')
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return 0
}
Expand Down Expand Up @@ -5176,6 +5401,22 @@ class InterfaceType implements Type {
)
}

public Methods(): iter.Seq<Method> {
return typeMethodsSeq(this)
}

public Fields(): iter.Seq<StructField> {
return typeFieldsSeq(this)
}

public Ins(): iter.Seq<Type> {
return typeInsSeq(this)
}

public Outs(): iter.Seq<Type> {
return typeOutsSeq(this)
}

public NumMethod(): number {
return typeMethods(this).length
}
Expand Down
9 changes: 8 additions & 1 deletion gs/reflect/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ export class Method {
public Name = ''
public PkgPath = ''
public Type: Type | null = null
public Func!: ReflectFunc
// Func is the method as a function taking the receiver first; it is the
// zero Value for an interface type.
public Func!: Value
public Index = 0

constructor(init?: Partial<Method>) {
Expand All @@ -168,6 +170,11 @@ export class Method {
}
}

// IsExported reports whether the method is exported.
public IsExported(): boolean {
return this.PkgPath === ''
}

// clone copies the method, as Go copies a Method struct value.
public clone(): Method {
return new Method(this)
Expand Down
8 changes: 8 additions & 0 deletions tests/tests/reflect_value_methods_more/expected.log
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ clear: 0 0 2 4
field: A int
field: B string
method: Sum 3
type field: A int
type field: B string
type method: Sum func(main.pair) int true
func: func(main.pair) int 3
ptr func: func(*main.pair, int) 6
in: string
in: int
out: string
iter: k 7
trysend: true false
tryrecv: 3 true
Expand Down
Loading
Loading