Repository: goplus/gop
Pull request #1653 (2024-01-21 01:05:17)

classfile: support Main(workers)


Patch:
diff --git a/cl/classfile.go b/cl/classfile.go
index 085181ea..d51e17d6 100644
--- a/cl/classfile.go
+++ b/cl/classfile.go
@@ -185,23 +185,47 @@ func setBodyHandler(ctx *blockCtx) {
 	}
 }
 
-func gmxMainFunc(p *gox.Package, ctx *pkgCtx) bool {
+func gmxMainFunc(p *gox.Package, ctx *pkgCtx) func() {
 	if len(ctx.projs) == 1 { // only one project file
 		var proj *gmxProject
 		for _, v := range ctx.projs {
 			proj = v
 			break
 		}
-		if o := p.Types.Scope().Lookup(proj.gameClass); o != nil && hasMethod(o, "MainEntry") {
+		scope := p.Types.Scope()
+		if o := scope.Lookup(proj.gameClass); o != nil && hasMethod(o, "MainEntry") {
 			// new(Game).Main()
-			p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).
-				Val(p.Builtin().Ref("new")).Val(o).Call(1).
-				MemberVal("Main").Call(0).EndStmt().
-				End()
-			return true
+			// new(Game).Main(workers...)
+			fn := p.NewFunc(nil, "main", nil, nil, false)
+			return func() {
+				new := p.Builtin().Ref("new")
+				cb := fn.BodyStart(p).Val(new).Val(o).Call(1).MemberVal("Main")
+
+				sig := cb.Get(-1).Type.(*types.Signature)
+				narg := gmxMainNarg(sig)
+				if narg > 0 {
+					narg = len(proj.sptypes)
+					for _, spt := range proj.sptypes {
+						sp := scope.Lookup(spt)
+						cb.Val(new).Val(sp).Call(1)
+					}
+				}
+
+				cb.Call(narg).EndStmt().End()
+			}
+		}
+	}
+	return nil
+}
+
+func gmxMainNarg(sig *types.Signature) int {
+	if fex, ok := gox.CheckFuncEx(sig); ok {
+		if trm, ok := fex.(*gox.TyTemplateRecvMethod); ok {
+			sig = trm.Func.Type().(*types.Signature)
+			return sig.Params().Len() - 1
 		}
 	}
-	return false
+	return sig.Params().Len()
 }
 
 // -----------------------------------------------------------------------------
diff --git a/cl/compile.go b/cl/compile.go
index 4bd21ead..54a9c21c 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -517,8 +517,10 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 	})
 
 	for file, gmx := range files {
-		log.Println("==> File", file, "isClass:", gmx.IsClass, "normalGox:", gmx.IsNormalGox)
 		if gmx.IsClass && !gmx.IsNormalGox {
+			if debugLoad {
+				log.Println("==> File", file, "normalGox:", gmx.IsNormalGox)
+			}
 			loadClass(ctx, p, file, gmx, conf)
 		}
 	}
@@ -570,6 +572,7 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 
 	// genMain = true if it is main package and no main func
 	var genMain bool
+	var gen func()
 	if pkg.Name == "main" {
 		_, hasMain := ctx.syms["main"]
 		genMain = !hasMain
@@ -580,8 +583,8 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 			loadFile(ctx, f.File)
 		}
 	}
-	if genMain { // generate main func if need
-		genMain = !gmxMainFunc(p, ctx)
+	if genMain { // make classfile main func if need
+		gen = gmxMainFunc(p, ctx)
 	}
 
 	for _, f := range sfiles {
@@ -602,7 +605,9 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 	}
 	err = ctx.complete()
 
-	if genMain && !conf.NoAutoGenMain { // generate empty main func
+	if gen != nil { // generate classfile main func
+		gen()
+	} else if genMain && !conf.NoAutoGenMain { // generate empty main func
 		old, _ := p.SetCurFile(defaultGoFile, false)
 		p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).End()
 		p.RestoreCurFile(old)
diff --git a/cl/internal/spx3/spx3.go b/cl/internal/spx3/spx3.go
new file mode 100644
index 00000000..6fe29474
--- /dev/null
+++ b/cl/internal/spx3/spx3.go
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package spx3
+
+const (
+	GopPackage = true
+)
+
+type Game struct {
+}
+
+func (p *Game) initGame() {}
+
+func (p *Game) Run() {}
+
+type Sprite struct {
+}
+
+func (p *Sprite) initSprite() {}
+
+func Gopt_Game_Main(game interface{ initGame() }, workers ...interface{ initSprite() }) {
+}


Test patch:
diff --git a/cl/compile_spx_test.go b/cl/compile_spx_test.go
index 652e523c..8768d39e 100644
--- a/cl/compile_spx_test.go
+++ b/cl/compile_spx_test.go
@@ -46,6 +46,11 @@ func lookupClass(ext string) (c *modfile.Project, ok bool) {
 			Works: []*modfile.Class{{Ext: "_t3spx.gox", Class: "Sprite"},
 				{Ext: ".t3spx2", Class: "Sprite2"}},
 			PkgPaths: []string{"github.com/goplus/gop/cl/internal/spx2"}}, true
+	case "_spx.gox":
+		return &modfile.Project{
+			Ext: "_spx.gox", Class: "Game",
+			Works:    []*modfile.Class{{Ext: "_spx.gox", Class: "Sprite"}},
+			PkgPaths: []string{"github.com/goplus/gop/cl/internal/spx3", "math"}}, true
 	}
 	return
 }
@@ -54,6 +59,9 @@ func spxParserConf() parser.Config {
 	return parser.Config{
 		ClassKind: func(fname string) (isProj bool, ok bool) {
 			ext := modfile.ClassExt(fname)
+			if ext == "_spx.gox" {
+				return fname == "main_spx.gox", true
+			}
 			c, ok := lookupClass(ext)
 			if ok {
 				isProj = (c.Ext == ext)
@@ -368,6 +376,43 @@ func (this *Kai) Main() {
 `, "index.tgmx", "Kai.tspx")
 }
 
+func TestSpxRunWithWorkers(t *testing.T) {
+	gopSpxTestEx(t, `
+var (
+	Kai Kai
+)
+
+run
+`, `
+echo "Hi"
+`, `package main
+
+import (
+	"fmt"
+	"github.com/goplus/gop/cl/internal/spx3"
+)
+
+type Kai struct {
+	spx3.Sprite
+	*Game
+}
+type Game struct {
+	spx3.Game
+	Kai Kai
+}
+
+func (this *Game) MainEntry() {
+	this.Run()
+}
+func main() {
+	spx3.Gopt_Game_Main(new(Game), new(Kai))
+}
+func (this *Kai) Main() {
+	fmt.Println("Hi")
+}
+`, "main_spx.gox", "Kai_spx.gox")
+}
+
 func TestSpx2(t *testing.T) {
 	gopSpxTestEx(t, `
 println("Hi")
@@ -400,7 +445,9 @@ type Kai struct {
 func (this *Kai) onMsg(msg string) {
 }
 `, "Game.t2gmx", "Kai.t2spx")
+}
 
+func TestSpx3(t *testing.T) {
 	gopSpxTestEx(t, `
 println("Hi, Sprite2")
 `, `
@@ -434,7 +481,7 @@ func (this *Kai) onMsg(msg string) {
 `, "Game.t2gmx", "Kai.t2spx2")
 }
 
-func TestSpx3(t *testing.T) {
+func TestSpx4(t *testing.T) {
 	gopSpxTestEx(t, `
 println("Hi, Sprite")
 `, `