Repository: goplus/gop
Pull request #1115 (2022-01-25 13:27:47)

 cl: config add NoAutoGenMain for auto generate main func if no entry
fix https://github.com/goplus/gop/issues/1017

`cl.Config add NoAutoGenMain bool`

**empty .gop**
```
//blink
```
generate to
```
package main

func main() {
}
```

**no entry .gop**
```
func test() {
	println "hello"
}
```

generate
```
package main

import fmt "fmt"

func test() {
	fmt.Println("hello")
}
func main() {
}
```

**no entry index.gmx**
```
var (
	Calf Calf
)
```
generate 
```
package main

import spx "github.com/goplus/spx"

type index struct {
	spx.Game
	Calf Calf
}
type Calf struct {
	spx.Sprite
	*index
}

func (this *index) MainEntry() {
}
func main() {
	spx.Gopt_Game_Main(new(index))
}
```


Patch:
diff --git a/cl/compile.go b/cl/compile.go
index 9cddd01c..4fe078a1 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -96,6 +96,9 @@ type Config struct {
 
 	// RelativePath = true means to generate file line comments with relative file path.
 	RelativePath bool
+
+	// NoAutoGenMain = true means not to auto generate main func is no entry.
+	NoAutoGenMain bool
 }
 
 type nodeInterp struct {
@@ -396,6 +399,15 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 		load()
 	}
 	err = ctx.complete()
+
+	if !conf.NoAutoGenMain && pkg.Name == "main" {
+		if obj := p.Types.Scope().Lookup("main"); obj == nil {
+			old := p.SetInTestingFile(false)
+			p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).End()
+			p.SetInTestingFile(old)
+		}
+	}
+
 	return
 }
 
@@ -542,6 +554,26 @@ func preloadFile(p *gox.Package, parent *pkgCtx, file string, f *ast.File, targe
 			},
 		}}}
 	}
+	// check class project no MainEntry and auto added
+	if !conf.NoAutoGenMain && f.IsProj && !f.NoEntrypoint && f.Name.Name == "main" {
+		entry := getEntrypoint(f, false)
+		var hasEntry bool
+		for _, decl := range f.Decls {
+			switch d := decl.(type) {
+			case *ast.FuncDecl:
+				if d.Name.Name == entry {
+					hasEntry = true
+				}
+			}
+		}
+		if !hasEntry {
+			f.Decls = append(f.Decls, &ast.FuncDecl{
+				Name: ast.NewIdent(entry),
+				Type: &ast.FuncType{Params: &ast.FieldList{}},
+				Body: &ast.BlockStmt{},
+			})
+		}
+	}
 	for _, decl := range f.Decls {
 		switch d := decl.(type) {
 		case *ast.FuncDecl:


Test patch:
diff --git a/cl/compile_spx_test.go b/cl/compile_spx_test.go
index 7c5c264f..9bf77e2c 100644
--- a/cl/compile_spx_test.go
+++ b/cl/compile_spx_test.go
@@ -70,6 +70,10 @@ func gopSpxTest(t *testing.T, gmx, spxcode, expected string) {
 }
 
 func gopSpxTestEx(t *testing.T, gmx, spxcode, expected, gmxfile, spxfile string) {
+	gopSpxTestExConf(t, gblConf, gmx, spxcode, expected, gmxfile, spxfile)
+}
+
+func gopSpxTestExConf(t *testing.T, conf *cl.Config, gmx, spxcode, expected, gmxfile, spxfile string) {
 	cl.SetDisableRecover(true)
 	defer cl.SetDisableRecover(false)
 
@@ -80,7 +84,7 @@ func gopSpxTestEx(t *testing.T, gmx, spxcode, expected, gmxfile, spxfile string)
 		t.Fatal("ParseFSDir:", err)
 	}
 	bar := pkgs["main"]
-	pkg, err := cl.NewPackage("", bar, gblConf)
+	pkg, err := cl.NewPackage("", bar, conf)
 	if err != nil {
 		t.Fatal("NewPackage:", err)
 	}
@@ -392,3 +396,91 @@ func (this *Kai) onMsg(msg string) {
 }
 `, "Game.t2gmx", "Kai.t2spx")
 }
+
+func TestSpxMainEntry(t *testing.T) {
+	conf := *gblConf
+	conf.NoAutoGenMain = false
+
+	gopSpxTestExConf(t, &conf, `
+`, `
+`, `package main
+
+import spx2 "github.com/goplus/gop/cl/internal/spx2"
+
+type Game struct {
+	spx2.Game
+}
+
+func (this *Game) MainEntry() {
+}
+func main() {
+	new(Game).Main()
+}
+`, "Game.t2gmx", "Kai.t2spx")
+	gopSpxTestExConf(t, &conf, `
+var (
+	Kai Kai
+)
+`, `
+`, `package main
+
+import spx2 "github.com/goplus/gop/cl/internal/spx2"
+
+type Game struct {
+	spx2.Game
+	Kai Kai
+}
+type Kai struct {
+	spx2.Sprite
+	*Game
+}
+
+func (this *Game) MainEntry() {
+}
+func main() {
+	new(Game).Main()
+}
+`, "Game.t2gmx", "Kai.t2spx")
+
+	gopSpxTestExConf(t, &conf, `
+var (
+	Kai Kai
+)
+func MainEntry() {
+	println "Hi"
+}
+`, `
+func Main() {
+	println "Hello"
+}
+func onMsg(msg string) {
+}
+`, `package main
+
+import (
+	fmt "fmt"
+	spx2 "github.com/goplus/gop/cl/internal/spx2"
+)
+
+type Game struct {
+	spx2.Game
+	Kai Kai
+}
+type Kai struct {
+	spx2.Sprite
+	*Game
+}
+
+func (this *Game) MainEntry() {
+	fmt.Println("Hi")
+}
+func main() {
+	new(Game).Main()
+}
+func (this *Kai) Main() {
+	fmt.Println("Hello")
+}
+func (this *Kai) onMsg(msg string) {
+}
+`, "Game.t2gmx", "Kai.t2spx")
+}
diff --git a/cl/compile_test.go b/cl/compile_test.go
index f52f74c8..8f2fcc91 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -60,18 +60,19 @@ func init() {
 		panic(err)
 	}
 	gblConf = &cl.Config{
-		Fset:        gblFset,
-		Importer:    imp,
-		LookupClass: lookupClass,
-		NoFileLine:  true,
+		Fset:          gblFset,
+		Importer:      imp,
+		LookupClass:   lookupClass,
+		NoFileLine:    true,
+		NoAutoGenMain: true,
 	}
 }
 
 func gopClTest(t *testing.T, gopcode, expected string) {
-	gopClTestEx(t, "main", gopcode, expected)
+	gopClTestEx(t, gblConf, "main", gopcode, expected)
 }
 
-func gopClTestEx(t *testing.T, pkgname, gopcode, expected string) {
+func gopClTestEx(t *testing.T, conf *cl.Config, pkgname, gopcode, expected string) {
 	cl.SetDisableRecover(true)
 	defer cl.SetDisableRecover(false)
 
@@ -82,7 +83,7 @@ func gopClTestEx(t *testing.T, pkgname, gopcode, expected string) {
 		t.Fatal("ParseFSDir:", err)
 	}
 	bar := pkgs[pkgname]
-	pkg, err := cl.NewPackage("github.com/goplus/gop/cl", bar, gblConf)
+	pkg, err := cl.NewPackage("github.com/goplus/gop/cl", bar, conf)
 	if err != nil {
 		t.Fatal("NewPackage:", err)
 	}
@@ -3515,7 +3516,7 @@ func main() {
 	fmt.Println("init")
 }
 `)
-	gopClTestEx(t, "bar", `package bar
+	gopClTestEx(t, gblConf, "bar", `package bar
 println("init")
 `, `package bar
 
@@ -3619,3 +3620,42 @@ func main() {
 }
 `)
 }
+
+func TestMainEntry(t *testing.T) {
+	conf := *gblConf
+	conf.NoAutoGenMain = false
+
+	gopClTestEx(t, &conf, "main", `
+`, `package main
+
+func main() {
+}
+`)
+	gopClTestEx(t, &conf, "main", `
+func test() {
+	println "hello"
+}
+`, `package main
+
+import fmt "fmt"
+
+func test() {
+	fmt.Println("hello")
+}
+func main() {
+}
+`)
+
+	gopClTestEx(t, &conf, "main", `
+func main() {
+	println "hello"
+}
+`, `package main
+
+import fmt "fmt"
+
+func main() {
+	fmt.Println("hello")
+}
+`)
+}