From 20fa1aadb77473cd6c4410ae1f811d6ebc53afe3 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 25 Oct 2026 10:52:22 +0100 Subject: [PATCH 1/3] feat(reflect): add the Type iterators of Go 1.26 Go 1.26 added Type.Fields, Type.Methods, Type.Ins and Type.Outs, which return iterators. Code that ranges over them, such as a Go interpreter that walks the methods of a type, failed with a TypeError. They are now methods of every reflect type. Signed-off-by: Randall C. O'Reilly --- gs/reflect/type.ts | 232 ++++++++++++++++++ .../reflect_value_methods_more/expected.log | 6 + .../reflect_value_methods_more.go | 21 +- .../reflect_value_methods_more.gs.ts | 48 ++++ 4 files changed, 306 insertions(+), 1 deletion(-) diff --git a/gs/reflect/type.ts b/gs/reflect/type.ts index ed71e4079..75271c4f1 100644 --- a/gs/reflect/type.ts +++ b/gs/reflect/type.ts @@ -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 + + // Fields returns an iterator over the fields of a struct type. + // Panics if the type's Kind is not Struct. + Fields(): iter.Seq + + // Ins returns an iterator over the input types of a function type. + // Panics if the type's Kind is not Func. + Ins(): iter.Seq + + // Outs returns an iterator over the output types of a function type. + // Panics if the type's Kind is not Func. + Outs(): iter.Seq + // Method returns the i'th method in the type's method set. Method(i: number): Method @@ -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 { + 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 { + 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 { + 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 { + 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()}`) @@ -710,6 +782,22 @@ class InvalidTypeClass implements Type { OverflowFloat(_x: number): boolean { throw new Error('reflect: OverflowFloat of invalid type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + NumMethod(): number { return 0 } @@ -2585,6 +2673,22 @@ export class BasicType implements Type { ) } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -2774,6 +2878,22 @@ class SliceType implements Type { throw new Error('reflect: call of reflect.Type.OverflowFloat on slice Type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -2931,6 +3051,22 @@ class ArrayType implements Type { throw new Error('reflect: call of reflect.Type.OverflowFloat on array Type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -3082,6 +3218,22 @@ class PointerType implements Type { ) } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -3291,6 +3443,22 @@ class FunctionType implements Type { throw new Error('reflect: call of reflect.Type.OverflowFloat on func Type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -3813,6 +3981,22 @@ class MapType implements Type { throw new Error('reflect: call of reflect.Type.OverflowFloat on map Type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -4681,6 +4865,22 @@ class StructType implements Type { ) } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } @@ -5015,6 +5215,22 @@ class ChannelType implements Type { throw new Error('reflect: call of reflect.Type.OverflowFloat on chan Type') } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return 0 } @@ -5176,6 +5392,22 @@ class InterfaceType implements Type { ) } + public Methods(): iter.Seq { + return typeMethodsSeq(this) + } + + public Fields(): iter.Seq { + return typeFieldsSeq(this) + } + + public Ins(): iter.Seq { + return typeInsSeq(this) + } + + public Outs(): iter.Seq { + return typeOutsSeq(this) + } + public NumMethod(): number { return typeMethods(this).length } diff --git a/tests/tests/reflect_value_methods_more/expected.log b/tests/tests/reflect_value_methods_more/expected.log index 5bab00f7c..b68d274a1 100644 --- a/tests/tests/reflect_value_methods_more/expected.log +++ b/tests/tests/reflect_value_methods_more/expected.log @@ -5,6 +5,12 @@ 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 +in: string +in: int +out: string iter: k 7 trysend: true false tryrecv: 3 true diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go index 606c5b341..1e16ae8a7 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go @@ -1,6 +1,9 @@ package main -import "reflect" +import ( + "reflect" + "strings" +) type pair struct { A int @@ -38,6 +41,22 @@ func main() { println("method:", meth.Name, v.Call(nil)[0].Int()) } + // The Type iterators yield fields, methods, and function inputs and outputs. + pt := reflect.TypeOf(p) + for sf := range pt.Fields() { + println("type field:", sf.Name, sf.Type.String()) + } + for meth := range pt.Methods() { + println("type method:", meth.Name, meth.Type.String()) + } + ft := reflect.TypeOf(strings.Repeat) + for in := range ft.Ins() { + println("in:", in.String()) + } + for out := range ft.Outs() { + println("out:", out.String()) + } + // SetIterKey and SetIterValue copy the current map entry. k, e := reflect.New(reflect.TypeFor[string]()).Elem(), reflect.New(reflect.TypeFor[int]()).Elem() it := reflect.ValueOf(map[string]int{"k": 7}).MapRange() diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts index 2c129d1c3..599aeb304 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts @@ -3,7 +3,9 @@ import * as $ from "@goscript/builtin/index.js" import * as reflect from "@goscript/reflect/index.js" +import * as strings from "@goscript/strings/index.js" import type * as iter from "@goscript/iter/index.js" +import "@goscript/strings/index.js" export class pair { public declare A: number @@ -86,6 +88,50 @@ export async function main(): globalThis.Promise { return } + // The Type iterators yield fields, methods, and function inputs and outputs. + let pt = reflect.TypeOf($.structInterfaceValue(p, "main.pair", "main.pair")) + let __goscriptRangeReturn2 = false + ;await (async () => { + await ((__goscriptAwait = (pt !== null && (pt as any).__isVarRef !== true && ((pt as any).__goValue === undefined || (pt as any).__goType?.charCodeAt(0) !== 42) ? (pt as Exclude) : $.pointerValue>(pt)).Fields(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (sf) => { + await $.println("type field:", sf.Name, (__goscriptAwait = $.pointerValue>(sf.Type).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)) + return true + }) + })() + if (__goscriptRangeReturn2) { + return + } + let __goscriptRangeReturn3 = false + ;await (async () => { + await ((__goscriptAwait = (pt !== null && (pt as any).__isVarRef !== true && ((pt as any).__goValue === undefined || (pt as any).__goType?.charCodeAt(0) !== 42) ? (pt as Exclude) : $.pointerValue>(pt)).Methods(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (meth) => { + await $.println("type method:", meth.Name, (__goscriptAwait = $.pointerValue>(meth.Type).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)) + return true + }) + })() + if (__goscriptRangeReturn3) { + return + } + let ft = reflect.TypeOf($.interfaceValue($.goFunc(strings.Repeat, "strings.Repeat"), "func(s string, count int) string", ({ kind: $.TypeKind.Function, params: [/* @__PURE__ */ $.basicType("string"), /* @__PURE__ */ $.basicType("int")], results: [/* @__PURE__ */ $.basicType("string")] } as $.FunctionTypeInfo))) + let __goscriptRangeReturn4 = false + ;await (async () => { + await ((__goscriptAwait = (ft !== null && (ft as any).__isVarRef !== true && ((ft as any).__goValue === undefined || (ft as any).__goType?.charCodeAt(0) !== 42) ? (ft as Exclude) : $.pointerValue>(ft)).Ins(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (_in) => { + await $.println("in:", (__goscriptAwait = (_in !== null && (_in as any).__isVarRef !== true && ((_in as any).__goValue === undefined || (_in as any).__goType?.charCodeAt(0) !== 42) ? (_in as Exclude) : $.pointerValue>(_in)).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)) + return true + }) + })() + if (__goscriptRangeReturn4) { + return + } + let __goscriptRangeReturn5 = false + ;await (async () => { + await ((__goscriptAwait = (ft !== null && (ft as any).__isVarRef !== true && ((ft as any).__goValue === undefined || (ft as any).__goType?.charCodeAt(0) !== 42) ? (ft as Exclude) : $.pointerValue>(ft)).Outs(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (out) => { + await $.println("out:", (__goscriptAwait = (out !== null && (out as any).__isVarRef !== true && ((out as any).__goValue === undefined || (out as any).__goType?.charCodeAt(0) !== 42) ? (out as Exclude) : $.pointerValue>(out)).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)) + return true + }) + })() + if (__goscriptRangeReturn5) { + return + } + // SetIterKey and SetIterValue copy the current map entry. let k = $.markAsStructValue($.cloneStructValue($.markAsStructValue($.cloneStructValue(reflect.New($.pointerValueOrNil(reflect.TypeFor(__goscriptStatic0()))!))).Elem())) let e = $.markAsStructValue($.cloneStructValue($.markAsStructValue($.cloneStructValue(reflect.New($.pointerValueOrNil(reflect.TypeFor(__goscriptStatic1()))!))).Elem())) @@ -117,6 +163,8 @@ function __goscriptStatic1(): any { return __goscriptStatic1$value ??= ({[$.genericTypeArgsMarker]: $.genericTypeArgsBrand, T: { type: /* @__PURE__ */ $.basicType("int"), zero: () => 0 }}) } +var __goscriptAwait: any + if ($.isMainScript(import.meta)) { await main() } From f8e5d760b25e3dccf3ea147a770ab7407233c0d5 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 25 Oct 2026 10:56:41 +0100 Subject: [PATCH 2/3] feat(reflect): add Method.IsExported reflect.Method had no IsExported method, so code that filters the methods of a type by it failed with a TypeError. Signed-off-by: Randall C. O'Reilly --- gs/reflect/types.ts | 5 +++++ tests/tests/reflect_value_methods_more/expected.log | 2 +- .../reflect_value_methods_more/reflect_value_methods_more.go | 2 +- .../reflect_value_methods_more.gs.ts | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gs/reflect/types.ts b/gs/reflect/types.ts index ed272bdc5..421f7be5f 100644 --- a/gs/reflect/types.ts +++ b/gs/reflect/types.ts @@ -168,6 +168,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) diff --git a/tests/tests/reflect_value_methods_more/expected.log b/tests/tests/reflect_value_methods_more/expected.log index b68d274a1..d3773dd4d 100644 --- a/tests/tests/reflect_value_methods_more/expected.log +++ b/tests/tests/reflect_value_methods_more/expected.log @@ -7,7 +7,7 @@ field: B string method: Sum 3 type field: A int type field: B string -type method: Sum func(main.pair) int +type method: Sum func(main.pair) int true in: string in: int out: string diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go index 1e16ae8a7..90a716ca1 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go @@ -47,7 +47,7 @@ func main() { println("type field:", sf.Name, sf.Type.String()) } for meth := range pt.Methods() { - println("type method:", meth.Name, meth.Type.String()) + println("type method:", meth.Name, meth.Type.String(), meth.IsExported()) } ft := reflect.TypeOf(strings.Repeat) for in := range ft.Ins() { diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts index 599aeb304..5c22ec1e4 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts @@ -103,7 +103,7 @@ export async function main(): globalThis.Promise { let __goscriptRangeReturn3 = false ;await (async () => { await ((__goscriptAwait = (pt !== null && (pt as any).__isVarRef !== true && ((pt as any).__goValue === undefined || (pt as any).__goType?.charCodeAt(0) !== 42) ? (pt as Exclude) : $.pointerValue>(pt)).Methods(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (meth) => { - await $.println("type method:", meth.Name, (__goscriptAwait = $.pointerValue>(meth.Type).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait)) + await $.println("type method:", meth.Name, (__goscriptAwait = $.pointerValue>(meth.Type).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), $.markAsStructValue($.cloneStructValue(meth)).IsExported()) return true }) })() From 69a2be0cecbffcf3270592e68acaa181efd2b0a3 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 25 Oct 2026 11:12:41 +0100 Subject: [PATCH 3/3] feat(reflect): make Method.Func the method as a function Method.Func was a JavaScript function that returned undefined, while Go code uses it as a reflect.Value: m.Func.Type() and m.Func.Call(args) failed. It is now a func Value of the method type, taking the receiver first, and the zero Value for the methods of an interface type, as in Go. Signed-off-by: Randall C. O'Reilly --- gs/reflect/type.ts | 23 +++++++++++++------ gs/reflect/types.ts | 4 +++- .../reflect_value_methods_more/expected.log | 2 ++ .../reflect_value_methods_more.go | 8 +++++++ .../reflect_value_methods_more.gs.ts | 22 ++++++++++++++---- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/gs/reflect/type.ts b/gs/reflect/type.ts index 75271c4f1..17ce9fc58 100644 --- a/gs/reflect/type.ts +++ b/gs/reflect/type.ts @@ -4277,7 +4277,7 @@ export function visibleStructFields(t: Type): StructField[] { function zeroMethod(): Method { return new Method({ Type: new BasicType(Invalid, ''), - Func: () => undefined, + Func: new Value(), }) } @@ -4286,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, diff --git a/gs/reflect/types.ts b/gs/reflect/types.ts index 421f7be5f..f8ba8bd07 100644 --- a/gs/reflect/types.ts +++ b/gs/reflect/types.ts @@ -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) { diff --git a/tests/tests/reflect_value_methods_more/expected.log b/tests/tests/reflect_value_methods_more/expected.log index d3773dd4d..a7af67bbd 100644 --- a/tests/tests/reflect_value_methods_more/expected.log +++ b/tests/tests/reflect_value_methods_more/expected.log @@ -8,6 +8,8 @@ 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 diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go index 90a716ca1..b62bc345f 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.go @@ -12,6 +12,8 @@ type pair struct { func (p pair) Sum() int { return p.A + len(p.B) } +func (p *pair) Add(n int) { p.A += n } + func main() { // The Can methods report the kinds that their accessors accept. i, u, f, c := reflect.ValueOf(1), reflect.ValueOf(uint8(2)), reflect.ValueOf(1.5), reflect.ValueOf(1i) @@ -49,6 +51,12 @@ func main() { for meth := range pt.Methods() { println("type method:", meth.Name, meth.Type.String(), meth.IsExported()) } + // Method.Func takes the receiver as its first argument. + sum, _ := pt.MethodByName("Sum") + println("func:", sum.Func.Type().String(), sum.Func.Call([]reflect.Value{reflect.ValueOf(p)})[0].Int()) + addm, _ := reflect.TypeOf(&p).MethodByName("Add") + addm.Func.Call([]reflect.Value{reflect.ValueOf(&p), reflect.ValueOf(5)}) + println("ptr func:", addm.Func.Type().String(), p.A) ft := reflect.TypeOf(strings.Repeat) for in := range ft.Ins() { println("in:", in.String()) diff --git a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts index 5c22ec1e4..b735aeee0 100644 --- a/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts +++ b/tests/tests/reflect_value_methods_more/reflect_value_methods_more.gs.ts @@ -28,6 +28,12 @@ export class pair { return this } + public Add(n: number): void { + const p: pair | $.VarRef | null = this; + const p$: pair = p == null ? $.pointerTarget(p) : (p as any).__isVarRef === true ? (p as any).value : (p as any).__goValue === undefined ? (p as any) : $.pointerTarget(p); + ;(p$ as pair).A += n + } + public Sum(): number { const p = this; return p.A + $.stringLen(p.B) @@ -36,7 +42,7 @@ export class pair { static __typeInfo = $.registerStructType( "main.pair", () => new pair(), - () => [$.methodSignature("Sum", [], [/* @__PURE__ */ $.basicType("int")])], + () => [$.methodSignature("Add", [["n", /* @__PURE__ */ $.basicType("int")]], [], true), $.methodSignature("Sum", [], [/* @__PURE__ */ $.basicType("int")])], pair, () => [/* @__PURE__ */ $.structField("A", /* @__PURE__ */ $.basicType("int"), [0], 0, true), /* @__PURE__ */ $.structField("B", /* @__PURE__ */ $.basicType("string"), [1], 8, true)] ) @@ -66,10 +72,10 @@ export async function main(): globalThis.Promise { await $.println("clear:", $.len(m), $.arrayIndex(s.value!, 0), $.sliceLen(s.value), $.cap(s.value)) // Fields and Methods iterate with names and values. - let p = new pair(true, 1, "xy") + let p = $.varRef(new pair(true, 1, "xy")) let __goscriptRangeReturn0 = false ;await (async () => { - await $.markAsStructValue($.cloneStructValue(reflect.ValueOf($.structInterfaceValue((p).clone(), "main.pair", "main.pair")))).Fields()!(async (sf, v) => { + await $.markAsStructValue($.cloneStructValue(reflect.ValueOf($.structInterfaceValue((p.value).clone(), "main.pair", "main.pair")))).Fields()!(async (sf, v) => { await $.println("field:", sf.Name, reflect.Kind_String($.markAsStructValue($.cloneStructValue(v)).Kind())) return true }) @@ -79,7 +85,7 @@ export async function main(): globalThis.Promise { } let __goscriptRangeReturn1 = false ;await (async () => { - await $.markAsStructValue($.cloneStructValue(reflect.ValueOf($.structInterfaceValue((p).clone(), "main.pair", "main.pair")))).Methods()!(async (meth, v) => { + await $.markAsStructValue($.cloneStructValue(reflect.ValueOf($.structInterfaceValue((p.value).clone(), "main.pair", "main.pair")))).Methods()!(async (meth, v) => { await $.println("method:", meth.Name, $.markAsStructValue($.cloneStructValue($.arrayIndex((await $.markAsStructValue($.cloneStructValue(v)).Call(null))!, 0))).Int()) return true }) @@ -89,7 +95,7 @@ export async function main(): globalThis.Promise { } // The Type iterators yield fields, methods, and function inputs and outputs. - let pt = reflect.TypeOf($.structInterfaceValue(p, "main.pair", "main.pair")) + let pt = reflect.TypeOf($.structInterfaceValue((p.value).clone(), "main.pair", "main.pair")) let __goscriptRangeReturn2 = false ;await (async () => { await ((__goscriptAwait = (pt !== null && (pt as any).__isVarRef !== true && ((pt as any).__goValue === undefined || (pt as any).__goType?.charCodeAt(0) !== 42) ? (pt as Exclude) : $.pointerValue>(pt)).Fields(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait) as iter.Seq | null)!(async (sf) => { @@ -110,6 +116,12 @@ export async function main(): globalThis.Promise { if (__goscriptRangeReturn3) { return } + // Method.Func takes the receiver as its first argument. + let [sum, ] = await (pt !== null && (pt as any).__isVarRef !== true && ((pt as any).__goValue === undefined || (pt as any).__goType?.charCodeAt(0) !== 42) ? (pt as Exclude) : $.pointerValue>(pt)).MethodByName("Sum") + await $.println("func:", (__goscriptAwait = $.pointerValue>($.markAsStructValue($.cloneStructValue(sum.Func)).Type()).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), $.markAsStructValue($.cloneStructValue($.arrayIndex((await $.markAsStructValue($.cloneStructValue(sum.Func)).Call($.arrayToSlice([$.markAsStructValue($.cloneStructValue(reflect.ValueOf($.structInterfaceValue((p.value).clone(), "main.pair", "main.pair"))))])))!, 0))).Int()) + let [addm, ] = await $.pointerValue>(reflect.TypeOf($.interfaceValue(p, "*main.pair", /* @__PURE__ */ $.pointerType("main.pair")))).MethodByName("Add") + await $.markAsStructValue($.cloneStructValue(addm.Func)).Call($.arrayToSlice([$.markAsStructValue($.cloneStructValue(reflect.ValueOf($.interfaceValue(p, "*main.pair", /* @__PURE__ */ $.pointerType("main.pair"))))), $.markAsStructValue($.cloneStructValue(reflect.ValueOf($.basicInterfaceValue(5, "int"))))])) + await $.println("ptr func:", (__goscriptAwait = $.pointerValue>($.markAsStructValue($.cloneStructValue(addm.Func)).Type()).String(), __goscriptAwait instanceof Promise ? await __goscriptAwait : __goscriptAwait), p.value.A) let ft = reflect.TypeOf($.interfaceValue($.goFunc(strings.Repeat, "strings.Repeat"), "func(s string, count int) string", ({ kind: $.TypeKind.Function, params: [/* @__PURE__ */ $.basicType("string"), /* @__PURE__ */ $.basicType("int")], results: [/* @__PURE__ */ $.basicType("string")] } as $.FunctionTypeInfo))) let __goscriptRangeReturn4 = false ;await (async () => {