Skip to content

Commit

Permalink
gop#1847 static method
Browse files Browse the repository at this point in the history
  • Loading branch information
xushiwei committed Apr 12, 2024
1 parent 4586769 commit 42a7df0
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 36 deletions.
6 changes: 5 additions & 1 deletion builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}

Expand Down Expand Up @@ -797,6 +800,7 @@ func TestTypeEx(t *testing.T) {
&unboundMapElemType{},
&TyOverloadFunc{},
&TyOverloadMethod{},
&TyStaticMethod{},
&TyTemplateRecvMethod{},
&TyInstruction{},
&TyOverloadNamed{Obj: types.NewTypeName(0, pkg.Types, "bar", tyInt)},
Expand Down
40 changes: 22 additions & 18 deletions codebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand All @@ -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())
Expand Down
15 changes: 15 additions & 0 deletions func_ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
16 changes: 16 additions & 0 deletions gop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
62 changes: 45 additions & 17 deletions import.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,20 @@ 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 {
n := len(name)
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()
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"
)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions internal/bar/bar.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ func Gopt_Game_Run(game Gamer, resource string) {
game.RunLoop()
}

func Gops_Game_New() *Game {
return nil
}

// -----------------------------------------------------------------------------

0 comments on commit 42a7df0

Please sign in to comment.