diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 71bb92008..532f1c262 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -581,19 +581,21 @@ func lookupClassErr(ext string) (c *modfile.Project, ok bool) { } func TestGetGoFile(t *testing.T) { - if f := genGoFile("a_test.gop", false); f != testingGoFile { + ctx := &pkgCtx{} + if f := ctx.genGoFile("a_test.xgo", false); f != testingGoFile { t.Fatal("TestGetGoFile:", f) } - if f := genGoFile("a_test.xgo", false); f != testingGoFile { + if f := ctx.genGoFile("a_test.gox", true); f != testingGoFile { t.Fatal("TestGetGoFile:", f) } - if f := genGoFile("a_test.gox", true); f != testingGoFile { + if f := ctx.genGoFile("a.gop", false); f != defaultGoFile { t.Fatal("TestGetGoFile:", f) } - if f := genGoFile("a.gop", false); f != defaultGoFile { + ctx.multiFiles = true + if f := ctx.genGoFile("a.gop", false); f != "a.gop" { t.Fatal("TestGetGoFile:", f) } - if f := genGoFile("a.xgo", false); f != defaultGoFile { + if f := ctx.genGoFile("a.xgo", false); f != "a.xgo" { t.Fatal("TestGetGoFile:", f) } } diff --git a/cl/classfile.go b/cl/classfile.go index afdb7fcfc..ff0715ee7 100644 --- a/cl/classfile.go +++ b/cl/classfile.go @@ -85,6 +85,7 @@ type gmxProject struct { gameIsPtr bool isTest bool hasMain_ bool + file string } func (p *gmxProject) embed(flds []*types.Var, pkg *gogen.Package) []*types.Var { @@ -463,13 +464,14 @@ func gmxCheckProjs(pkg *gogen.Package, ctx *pkgCtx) (*gmxProject, bool) { func gmxProjMain(pkg *gogen.Package, parent *pkgCtx, proj *gmxProject) { base := proj.game // project base class classType := proj.getGameClass(parent) // project class + goFile := parent.genGoFile(proj.file, false) ld := getTypeLoader(parent, parent.syms, token.NoPos, classType) if ld.typ == nil { // no project class, use default ld.typ = func() { if debugLoad { log.Println("==> Load > NewType", classType) } - old, _ := pkg.SetCurFile(defaultGoFile, true) + old, _ := pkg.SetCurFile(goFile, true) defer pkg.RestoreCurFile(old) baseType := base.Type() @@ -486,7 +488,7 @@ func gmxProjMain(pkg *gogen.Package, parent *pkgCtx, proj *gmxProject) { if debugLoad { log.Println("==> Load > InitType", classType) } - old, _ := pkg.SetCurFile(defaultGoFile, true) + old, _ := pkg.SetCurFile(goFile, true) defer pkg.RestoreCurFile(old) decl.InitType(pkg, types.NewStruct(flds, nil)) @@ -495,7 +497,7 @@ func gmxProjMain(pkg *gogen.Package, parent *pkgCtx, proj *gmxProject) { } } ld.methods = append(ld.methods, func() { - old, _ := pkg.SetCurFile(defaultGoFile, true) + old, _ := pkg.SetCurFile(goFile, true) defer pkg.RestoreCurFile(old) doInitType(ld) @@ -504,7 +506,7 @@ func gmxProjMain(pkg *gogen.Package, parent *pkgCtx, proj *gmxProject) { fn := pkg.NewFunc(recv, "Main", nil, nil, false) parent.inits = append(parent.inits, func() { - old, _ := pkg.SetCurFile(defaultGoFile, true) + old, _ := pkg.SetCurFile(goFile, true) defer pkg.RestoreCurFile(old) cb := fn.BodyStart(pkg).Typ(base.Type()).MemberVal("Main") diff --git a/cl/compile.go b/cl/compile.go index 2273352cb..540984dd8 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -204,6 +204,9 @@ type Config struct { // Outline = true means to skip compiling function bodies. Outline bool + + // MultiFiles = true means generate multi files. + MultiFiles bool } type nodeInterp struct { @@ -352,6 +355,7 @@ type pkgCtx struct { goxMain int32 // normal gox files with main func featTypesAlias bool // support types alias + multiFiles bool // generate multi files } type pkgImp struct { @@ -519,6 +523,7 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gogen.Packag overpos: make(map[string]token.Pos), syms: make(map[string]loader), generics: make(map[string]bool), + multiFiles: conf.MultiFiles, } confGox := &gogen.Config{ Types: conf.Types, @@ -657,7 +662,7 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gogen.Packag if mainClass != "" { // generate classfile main func genMainFunc(p, mainClass) } else if genMain && !conf.NoAutoGenMain { // generate empty main func - old, _ := p.SetCurFile(defaultGoFile, false) + old, _ := p.SetCurFile(ctx.genGoFile("", false), false) p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).End() p.RestoreCurFile(old) } @@ -726,10 +731,13 @@ func loadFile(ctx *pkgCtx, f *ast.File) { // *_test.xgo // *_test.gop // *test.gox -func genGoFile(file string, goxTestFile bool) string { +func (ctx *pkgCtx) genGoFile(file string, goxTestFile bool) string { if goxTestFile || strings.HasSuffix(file, "_test.xgo") || strings.HasSuffix(file, "_test.gop") { return testingGoFile } + if ctx.multiFiles { + return file + } return defaultGoFile } @@ -770,6 +778,7 @@ func preloadGopFile(p *gogen.Package, ctx *blockCtx, file string, f *ast.File, c if proj.gameIsPtr { baseType = types.NewPointer(baseType) } + proj.file = file } else { sp = c.sp o := sp.obj @@ -778,7 +787,7 @@ func preloadGopFile(p *gogen.Package, ctx *blockCtx, file string, f *ast.File, c } } } - goFile := genGoFile(file, goxTestFile) + goFile := ctx.genGoFile(file, goxTestFile) if classType != "" { if debugLoad { log.Println("==> Preload type", classType) diff --git a/cmd/internal/clean/clean.go b/cmd/internal/clean/clean.go index cb5e4669f..933288ed9 100644 --- a/cmd/internal/clean/clean.go +++ b/cmd/internal/clean/clean.go @@ -27,6 +27,7 @@ import ( ) const ( + autoGenFilePrefix = "xgo_autogen_" autoGenFileSuffix = "_autogen.go" autoGenGopTestFile = "gop_autogen_test.go" autoGen2GopTestFile = "gop_autogen2_test.go" @@ -55,7 +56,7 @@ func cleanAGFiles(dir string, execAct bool) { } continue } - if strings.HasSuffix(fname, autoGenFileSuffix) { + if strings.HasSuffix(fname, autoGenFileSuffix) || strings.HasPrefix(fname, autoGenFilePrefix) { file := filepath.Join(dir, fname) fmt.Printf("Cleaning %s ...\n", file) if execAct { diff --git a/cmd/internal/gengo/go.go b/cmd/internal/gengo/go.go index 666d0ccaf..19849ffe0 100644 --- a/cmd/internal/gengo/go.go +++ b/cmd/internal/gengo/go.go @@ -44,7 +44,8 @@ var ( flagSingleMode = flag.Bool("s", false, "run in single file mode for package") flagIgnoreNotatedErr = flag.Bool( "ignore-notated-error", false, "ignore notated errors, only available together with -t (check mode)") - flagTags = flag.String("tags", "", "a comma-separated list of additional build tags to consider satisfied") + flagTags = flag.String("tags", "", "a comma-separated list of additional build tags to consider satisfied") + flagMultiFiles = flag.Bool("multi-files", false, "genarate multi files for package") ) func init() { @@ -88,6 +89,9 @@ func runCmd(cmd *base.Command, args []string) { if *flagSingleMode { flags |= tool.GenFlagSingleFile } + if *flagMultiFiles { + flags |= tool.GenFlagMultiFiles + } for _, proj := range projs { switch v := proj.(type) { case *xgoprojs.DirProj: diff --git a/tool/gengo.go b/tool/gengo.go index e155a4be5..cac2f3c5e 100644 --- a/tool/gengo.go +++ b/tool/gengo.go @@ -24,6 +24,7 @@ import ( "strings" "syscall" + "github.com/goplus/gogen" "github.com/goplus/mod/modcache" "github.com/goplus/mod/modfetch" "github.com/goplus/mod/xgomod" @@ -35,6 +36,7 @@ const ( autoGenFile = "xgo_autogen.go" autoGenTestFile = "xgo_autogen_test.go" autoGen2TestFile = "xgo_autogen2_test.go" + autoGenPrefix = "xgo_autogen_" ) type GenFlags int @@ -42,6 +44,7 @@ type GenFlags int const ( GenFlagCheckOnly GenFlags = 1 << iota GenFlagSingleFile + GenFlagMultiFiles GenFlagPrintError GenFlagPrompt ) @@ -166,7 +169,7 @@ func genGoSingleFile(file string, extn int, conf *Config, flags GenFlags) (err e } func genGoIn(dir string, conf *Config, genTestPkg bool, flags GenFlags, gen ...*bool) (err error) { - out, test, err := LoadDir(dir, conf, genTestPkg, (flags&GenFlagPrompt) != 0) + out, test, err := LoadDir(dir, conf, genTestPkg, (flags&GenFlagPrompt) != 0, (flags&GenFlagMultiFiles) != 0) if err != nil { if NotFound(err) { // no XGo source files return nil @@ -177,10 +180,18 @@ func genGoIn(dir string, conf *Config, genTestPkg bool, flags GenFlags, gen ...* return nil } os.MkdirAll(dir, 0755) - file := filepath.Join(dir, autoGenFile) - err = out.WriteFile(file) - if err != nil { - return errors.NewWith(err, `out.WriteFile(file)`, -2, "(*gogen.Package).WriteFile", out, file) + + if flags&GenFlagMultiFiles != 0 { + err = writeMultiFiles(out, dir) + if err != nil { + return errors.NewWith(err, `writeMultiFiles(out, dir)`, -2, "(*gogen.Package).WriteFile", out, dir) + } + } else { + file := filepath.Join(dir, autoGenFile) + err = out.WriteFile(file) + if err != nil { + return errors.NewWith(err, `out.WriteFile(file)`, -2, "(*gogen.Package).WriteFile", out, file) + } } if gen != nil { // say `xgo_autogen.go generated` *gen[0] = true @@ -204,6 +215,29 @@ func genGoIn(dir string, conf *Config, genTestPkg bool, flags GenFlags, gen ...* return } +func writeMultiFiles(pkg *gogen.Package, dir string) error { + names := make(map[string]string) + pkg.ForEachFile(func(fname string, file *gogen.File) { + if fname == "" { + names[fname] = autoGenFile + } else { + _, name := filepath.Split(fname) + name = name[:len(name)-len(filepath.Ext(name))] + if strings.HasSuffix(name, "_test") { + return + } + names[fname] = autoGenPrefix + name + ".go" + } + }) + for fname, file := range names { + err := pkg.WriteFile(filepath.Join(dir, file), fname) + if err != nil { + return err + } + } + return nil +} + // ----------------------------------------------------------------------------- const ( diff --git a/tool/load.go b/tool/load.go index 31ed88447..a760ba818 100644 --- a/tool/load.go +++ b/tool/load.go @@ -277,6 +277,9 @@ func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (ou Importer: imp, LookupClass: mod.LookupClass, } + if len(promptGenGo) > 1 && promptGenGo[1] { + clConf.MultiFiles = true + } for name, pkg := range pkgs { if strings.HasSuffix(name, "_test") {