Repository: goplus/gop
Pull request #2278 (2025-04-11 04:47:52)

cl: multiple work classes


Patch:
diff --git a/cl/_testspx/workers/Kai_spx.gox b/cl/_testspx/singlework/Kai_spx.gox
similarity index 100%
rename from cl/_testspx/workers/Kai_spx.gox
rename to cl/_testspx/singlework/Kai_spx.gox
diff --git a/cl/_testspx/workers/main_spx.gox b/cl/_testspx/singlework/main_spx.gox
similarity index 100%
rename from cl/_testspx/workers/main_spx.gox
rename to cl/_testspx/singlework/main_spx.gox
diff --git a/cl/_testspx/workers/out.go b/cl/_testspx/singlework/out.go
similarity index 100%
rename from cl/_testspx/workers/out.go
rename to cl/_testspx/singlework/out.go
diff --git a/cl/classfile.go b/cl/classfile.go
index fbb17ffb..ae6692ee 100644
--- a/cl/classfile.go
+++ b/cl/classfile.go
@@ -59,6 +59,15 @@ type spxObj struct {
 	types []string         // <type>.spx
 }
 
+func spriteByProto(sprites []*spxObj, proto string) *spxObj {
+	for _, sp := range sprites {
+		if sp.proto == proto {
+			return sp
+		}
+	}
+	return nil
+}
+
 type gmxProject struct {
 	gameClass_ string    // <gmtype>.gmx
 	game       gogen.Ref // Game (project base class)
@@ -76,9 +85,9 @@ type gmxProject struct {
 }
 
 func (p *gmxProject) spriteOf(ext string) *spxObj {
-	for _, v := range p.sprites {
-		if v.ext == ext {
-			return v
+	for _, sp := range p.sprites {
+		if sp.ext == ext {
+			return sp
 		}
 	}
 	return nil
@@ -91,6 +100,20 @@ const (
 	spriteClassclone
 )
 
+func spriteFeature(elt types.Type, sp *spxObj) {
+	if intf, ok := elt.(*types.Interface); ok {
+		for i, n := 0, intf.NumMethods(); i < n; i++ {
+			switch m := intf.Method(i); m.Name() {
+			case "Classfname":
+				sp.feats |= spriteClassfname
+			case "Classclone":
+				sp.clone = m.Type().(*types.Signature)
+				sp.feats |= spriteClassclone
+			}
+		}
+	}
+}
+
 func spriteFeatures(game gogen.Ref, sprites []*spxObj) {
 	if mainFn := findMethod(game, "Main"); mainFn != nil {
 		sig := mainFn.Type().(*types.Signature)
@@ -100,7 +123,13 @@ func spriteFeatures(game gogen.Ref, sprites []*spxObj) {
 			}
 		}
 		if n := len(sprites); n > 1 { // multiple work classes
-			panic("TODO(xsw):")
+			in := sig.Params()
+			for i, narg := 1, in.Len(); i < narg; i++ { // TODO(xsw): error handling
+				tslice := in.At(i).Type().(*types.Slice)
+				tn := tslice.Elem().(*types.Named)
+				sp := spriteByProto(sprites, tn.Obj().Name())
+				spriteFeature(tn.Underlying(), sp)
+			}
 		} else if n == 1 && sig.Variadic() { // single work class
 			in := sig.Params()
 			last := in.At(in.Len() - 1)
@@ -108,18 +137,7 @@ func spriteFeatures(game gogen.Ref, sprites []*spxObj) {
 			if tn, ok := elt.(*types.Named); ok {
 				elt = tn.Underlying()
 			}
-			if intf, ok := elt.(*types.Interface); ok {
-				spr := sprites[0]
-				for i, n := 0, intf.NumMethods(); i < n; i++ {
-					switch m := intf.Method(i); m.Name() {
-					case "Classfname":
-						spr.feats |= spriteClassfname
-					case "Classclone":
-						spr.clone = m.Type().(*types.Signature)
-						spr.feats |= spriteClassclone
-					}
-				}
-			}
+			spriteFeature(elt, sprites[0])
 		}
 	}
 }
@@ -446,19 +464,30 @@ func gmxProjMain(pkg *gogen.Package, parent *pkgCtx, proj *gmxProject) {
 			} else {
 				cb.Val(recv).MemberRef(base.Name()).UnaryOp(gotoken.AND)
 			}
+
 			narg := sigParams.Len()
 			if narg > 1 {
 				sprites := proj.sprites
 				if len(sprites) == 1 && sprites[0].proto == "" {
-					spr := sprites[0]
-					narg = 1 + len(spr.types)
+					sp := sprites[0]
+					narg = 1 + len(sp.types)
 					new := pkg.Builtin().Ref("new")
-					for _, spt := range spr.types {
-						sp := pkg.Ref(spt)
-						cb.Val(new).Val(sp).Call(1)
+					for _, spt := range sp.types {
+						spto := pkg.Ref(spt)
+						cb.Val(new).Val(spto).Call(1)
 					}
 				} else {
-					panic("TODO(xsw): prototype")
+					new := pkg.Builtin().Ref("new")
+					for i := 1; i < narg; i++ {
+						tslice := sigParams.At(i).Type()
+						tn := tslice.(*types.Slice).Elem().(*types.Named)
+						sp := spriteByProto(sprites, tn.Obj().Name())
+						for _, spt := range sp.types {
+							spto := pkg.Ref(spt)
+							cb.Val(new).Val(spto).Call(1)
+						}
+						cb.SliceLitEx(tslice, len(sp.types), false)
+					}
 				}
 			}
 


Test patch:
diff --git a/cl/_testspx/_protos/foo_prompt.gox b/cl/_testspx/multiworks/foo_prompt.gox
similarity index 100%
rename from cl/_testspx/_protos/foo_prompt.gox
rename to cl/_testspx/multiworks/foo_prompt.gox
diff --git a/cl/_testspx/_protos/hello_tool.gox b/cl/_testspx/multiworks/hello_tool.gox
similarity index 100%
rename from cl/_testspx/_protos/hello_tool.gox
rename to cl/_testspx/multiworks/hello_tool.gox
diff --git a/cl/_testspx/_protos/main_mcp.gox b/cl/_testspx/multiworks/main_mcp.gox
similarity index 100%
rename from cl/_testspx/_protos/main_mcp.gox
rename to cl/_testspx/multiworks/main_mcp.gox
diff --git a/cl/_testspx/multiworks/out.go b/cl/_testspx/multiworks/out.go
new file mode 100644
index 00000000..8645b1a7
--- /dev/null
+++ b/cl/_testspx/multiworks/out.go
@@ -0,0 +1,33 @@
+package main
+
+import "github.com/goplus/gop/cl/internal/mcp"
+
+type foo struct {
+	mcp.Prompt
+	*Game
+}
+type hello struct {
+	mcp.Tool
+	*Game
+}
+type Game struct {
+	mcp.Game
+}
+
+func (this *Game) MainEntry() {
+	this.Server("protos")
+}
+func (this *Game) Main() {
+	mcp.Gopt_Game_Main(this, []mcp.ToolProto{new(hello)}, []mcp.PromptProto{new(foo)})
+}
+func (this *foo) Main(_gop_arg0 *mcp.Tool) string {
+	this.Prompt.Main(_gop_arg0)
+	return "Hi"
+}
+func (this *hello) Main(_gop_arg0 string) int {
+	this.Tool.Main(_gop_arg0)
+	return -1
+}
+func main() {
+	new(Game).Main()
+}