From 42a7df0a0e6ae9dd461339b01dc493fb96cfd7d7 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 12 Apr 2024 23:33:52 +0800 Subject: [PATCH] gop#1847 static method --- builtin_test.go | 6 ++++- codebuild.go | 40 ++++++++++++++++------------- func_ext.go | 15 +++++++++++ gop_test.go | 16 ++++++++++++ import.go | 62 ++++++++++++++++++++++++++++++++------------- internal/bar/bar.go | 4 +++ 6 files changed, 107 insertions(+), 36 deletions(-) diff --git a/builtin_test.go b/builtin_test.go index e7484963..c179c9a7 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -206,7 +206,10 @@ func TestErrMethodSig(t *testing.T) { arg := &Element{ Type: &TypeType{typ: types.NewPointer(recv)}, } - methodSigOf(method, memberFlagMethodToFunc, arg, &ast.SelectorExpr{Sel: ast.NewIdent("bar")}) + ret := &Element{ + Val: &ast.SelectorExpr{Sel: ast.NewIdent("bar")}, + } + pkg.cb.methodSigOf(method, memberFlagMethodToFunc, arg, ret) }) } @@ -797,6 +800,7 @@ func TestTypeEx(t *testing.T) { &unboundMapElemType{}, &TyOverloadFunc{}, &TyOverloadMethod{}, + &TyStaticMethod{}, &TyTemplateRecvMethod{}, &TyInstruction{}, &TyOverloadNamed{Obj: types.NewTypeName(0, pkg.Types, "bar", tyInt)}, diff --git a/codebuild.go b/codebuild.go index dc91dc7d..a4cae9f5 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1740,16 +1740,9 @@ func (p *CodeBuilder) method( } sel := selector(arg, found.Name()) - ret := &internal.Elem{ - Val: sel, - Type: methodSigOf(typ, flag, arg, sel), - Src: src, - } - // TODO: We should take `methodSigOf` more seriously - if trm, ok := ret.Type.(*TyTemplateRecvMethod); ok { - o := trm.Func - ret.Val = toObjectExpr(p.pkg, o) - ret.Type = o.Type() + ret := &internal.Elem{Val: sel, Src: src} + if t, set := p.methodSigOf(typ, flag, arg, ret); set { + ret.Type = t } p.stk.Ret(1, ret) @@ -1869,7 +1862,7 @@ func toFuncSig(sig *types.Signature, recv *types.Var) *types.Signature { func methodToFuncSig(pkg *Package, o types.Object, fn *Element) *types.Signature { sig := o.Type().(*types.Signature) recv := sig.Recv() - if recv == nil { + if recv == nil { // special signature fn.Val = toObjectExpr(pkg, o) return sig } @@ -1880,20 +1873,24 @@ func methodToFuncSig(pkg *Package, o types.Object, fn *Element) *types.Signature return toFuncSig(sig, recv) } -func methodSigOf(typ types.Type, flag MemberFlag, arg *Element, sel *ast.SelectorExpr) types.Type { +func (p *CodeBuilder) methodSigOf(typ types.Type, flag MemberFlag, arg, ret *Element) (types.Type, bool) { if flag != memberFlagMethodToFunc { - return methodCallSig(typ) + return methodCallSig(typ), true } sig := typ.(*types.Signature) if t, ok := CheckFuncEx(sig); ok { - if trm, ok := t.(*TyTemplateRecvMethod); ok { - // TODO: We should take `methodSigOf` more seriously - return trm + switch ext := t.(type) { + case *TyStaticMethod: + return p.funcExSigOf(ext.Func, ret) + case *TyTemplateRecvMethod: + return p.funcExSigOf(ext.Func, ret) } - return typ + // TODO: We should take `methodSigOf` more seriously + return typ, true } + sel := ret.Val.(*ast.SelectorExpr) at := arg.Type.(*TypeType).typ recv := sig.Recv().Type() _, isPtr := recv.(*types.Pointer) // recv is a pointer @@ -1909,12 +1906,19 @@ func methodSigOf(typ types.Type, flag MemberFlag, arg *Element, sel *ast.Selecto } sel.X = &ast.ParenExpr{X: sel.X} - return toFuncSig(sig, types.NewVar(token.NoPos, nil, "", at)) + return toFuncSig(sig, types.NewVar(token.NoPos, nil, "", at)), true +} + +func (p *CodeBuilder) funcExSigOf(o types.Object, ret *Element) (types.Type, bool) { + ret.Val = toObjectExpr(p.pkg, o) + ret.Type = o.Type() + return nil, false } func methodCallSig(typ types.Type) types.Type { sig := typ.(*types.Signature) if _, ok := CheckFuncEx(sig); ok { + // TODO: We should take `methodSigOf` more seriously return typ } return types.NewSignatureType(nil, nil, nil, sig.Params(), sig.Results(), sig.Variadic()) diff --git a/func_ext.go b/func_ext.go index 2c9b13a7..f84da3a3 100644 --- a/func_ext.go +++ b/func_ext.go @@ -215,6 +215,21 @@ func (p *tyTypeAsParams) funcEx() {} // ---------------------------------------------------------------------------- +type TyStaticMethod struct { + Func types.Object +} + +func (p *TyStaticMethod) Obj() types.Object { return p.Func } +func (p *TyStaticMethod) Underlying() types.Type { return p } +func (p *TyStaticMethod) String() string { return "TyStaticMethod" } +func (p *TyStaticMethod) funcEx() {} + +func NewStaticMethod(typ *types.Named, pos token.Pos, pkg *types.Package, name string, fn types.Object) *types.Func { + return newMethodEx(typ, pos, pkg, name, &TyStaticMethod{fn}) +} + +// ---------------------------------------------------------------------------- + type TyTemplateRecvMethod struct { Func types.Object } diff --git a/gop_test.go b/gop_test.go index b866a2a4..d571f755 100644 --- a/gop_test.go +++ b/gop_test.go @@ -976,6 +976,22 @@ func bar(v *foo.Foo2) { // ---------------------------------------------------------------------------- +func TestStaticMethod(t *testing.T) { + pkg := newMainPackage() + bar := pkg.Import("github.com/goplus/gogen/internal/bar") + pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). + Typ(bar.Ref("Game").Type()).MemberVal("New").Call(0).EndStmt(). + End() + domTest(t, pkg, `package main + +import "github.com/goplus/gogen/internal/bar" + +func main() { + bar.Gops_Game_New() +} +`) +} + func TestTemplateRecvMethod(t *testing.T) { pkg := newMainPackage() bar := pkg.Import("github.com/goplus/gogen/internal/bar") diff --git a/import.go b/import.go index 698a95fe..f89e3015 100644 --- a/import.go +++ b/import.go @@ -81,7 +81,7 @@ func isGopoConst(name string) bool { } func isGopFunc(name string) bool { - return isOverload(name) || strings.HasPrefix(name, goptPrefix) || strings.HasPrefix(name, gopxPrefix) + return isOverload(name) || isGopCommon(name) } func isOverload(name string) bool { @@ -89,6 +89,12 @@ func isOverload(name string) bool { return n > 3 && name[n-3:n-1] == "__" } +// Gop?_xxx +func isGopCommon(name string) bool { + const n = len(commonPrefix) + return len(name) > n+2 && name[n+1] == '_' && name[:n] == commonPrefix +} + // InitThisGopPkg initializes a Go+ package. func InitThisGopPkg(pkg *types.Package) { scope := pkg.Scope() @@ -130,7 +136,7 @@ func InitThisGopPkg(pkg *types.Package) { key := omthd{nil, name[:len(name)-3]} overloads[key] = append(overloads[key], o) } else { - checkGoptGopx(pkg, scope, name, o) + checkGoptsx(pkg, scope, name, o) } } for _, gopoName := range gopos { @@ -235,29 +241,51 @@ func checkTypeMethod(scope *types.Scope, name string) (omthd, string) { // Gopx_Func // Gopt_TypeName_Method // Gopt__TypeName__Method -func checkGoptGopx(pkg *types.Package, scope *types.Scope, name string, o types.Object) { - if strings.HasPrefix(name, goptPrefix) { // Gopt_xxx - name = name[len(goptPrefix):] - if m, tname := checkTypeMethod(pkg.Scope(), name); m.typ != nil { +// Gops_TypeName_Method +// Gops__TypeName__Method +func checkGoptsx(pkg *types.Package, scope *types.Scope, name string, o types.Object) { + const n = len(commonPrefix) + const n2 = n + 2 + if isGopCommon(name) { + switch ch := name[n]; ch { + case gopsCh, goptCh: // Gops_xxx, Gopt_xxx + name = name[n2:] + if m, tname := checkTypeMethod(pkg.Scope(), name); m.typ != nil { + if ch == goptCh { + if debugImport { + log.Println("==> NewTemplateRecvMethod", tname, m.name) + } + NewTemplateRecvMethod(m.typ, token.NoPos, pkg, m.name, o) + } else { + if debugImport { + log.Println("==> NewStaticMethod", tname, m.name) + } + NewStaticMethod(m.typ, token.NoPos, pkg, m.name, o) + } + } + case gopxCh: // Gopx_xxx + aname := name[n2:] + o := newFuncEx(token.NoPos, pkg, nil, aname, &tyTypeAsParams{o}) + scope.Insert(o) if debugImport { - log.Println("==> NewTemplateRecvMethod", tname, m.name) + log.Println("==> AliasFunc", name, "=>", aname) } - NewTemplateRecvMethod(m.typ, token.NoPos, pkg, m.name, o) - } - } else if strings.HasPrefix(name, gopxPrefix) { // Gopx_xxx - aname := name[len(gopxPrefix):] - o := newFuncEx(token.NoPos, pkg, nil, aname, &tyTypeAsParams{o}) - scope.Insert(o) - if debugImport { - log.Println("==> AliasFunc", name, "=>", aname) } } } const ( + commonPrefix = "Gop" + + goptCh = 't' // template method + gopsCh = 's' // static method + gopxCh = 'x' // type as parameters function/method + goptPrefix = "Gopt_" // template method - gopoPrefix = "Gopo_" // overload function/method + gopsPrefix = "Gops_" // static method gopxPrefix = "Gopx_" // type as parameters function/method + gopoPrefix = "Gopo_" // overload function/method + gopPackage = "GopPackage" gopPkgInit = "__gop_inited" ) @@ -289,7 +317,7 @@ func newOverload(pkg *types.Package, scope *types.Scope, m omthd, fns []types.Ob } o := NewOverloadFunc(token.NoPos, pkg, m.name, fns...) scope.Insert(o) - checkGoptGopx(pkg, scope, m.name, o) + checkGoptsx(pkg, scope, m.name, o) } else { if debugImport { log.Println("==> NewOverloadMethod", m.typ.Obj().Name(), m.name) diff --git a/internal/bar/bar.go b/internal/bar/bar.go index 1872f086..f5126b1e 100644 --- a/internal/bar/bar.go +++ b/internal/bar/bar.go @@ -33,4 +33,8 @@ func Gopt_Game_Run(game Gamer, resource string) { game.RunLoop() } +func Gops_Game_New() *Game { + return nil +} + // -----------------------------------------------------------------------------