Repository: goplus/gop
Pull request #2337 (2025-05-07 07:43:06)

cl: classfile spName support Class.Prefix


Patch:
diff --git a/cl/classfile.go b/cl/classfile.go
index edb51626..0b70acc1 100644
--- a/cl/classfile.go
+++ b/cl/classfile.go
@@ -37,27 +37,29 @@ import (
 // -----------------------------------------------------------------------------
 
 type gmxClass struct {
-	tname_  string // class type
+	name    string // class type, empty for default project class
 	clsfile string
 	ext     string
 	proj    *gmxProject
+	sp      *spxObj
 }
 
 func (p *gmxClass) getName(ctx *pkgCtx) string {
-	tname := p.tname_
-	if tname == "main" {
+	tname := p.name
+	if tname == "" { // use default project class
 		tname = p.proj.getGameClass(ctx)
 	}
 	return tname
 }
 
 type spxObj struct {
-	obj   gogen.Ref // work base class
-	ext   string
-	proto string           // work class prototype
-	feats spriteFeat       // work class features
-	clone *types.Signature // prototype of Classclone
-	types []string         // work classes (ie. <type>.spx)
+	obj    gogen.Ref // work base class
+	ext    string
+	proto  string           // work class prototype
+	prefix string           // work class prefix
+	feats  spriteFeat       // work class features
+	clone  *types.Signature // prototype of Classclone
+	types  []string         // work classes (ie. <type>.spx)
 }
 
 func spriteByProto(sprites []*spxObj, proto string) *spxObj {
@@ -98,15 +100,6 @@ func (p *gmxProject) embed(flds []*types.Var, pkg *gogen.Package) []*types.Var {
 	return flds
 }
 
-func (p *gmxProject) spriteOf(ext string) *spxObj {
-	for _, sp := range p.sprites {
-		if sp.ext == ext {
-			return sp
-		}
-	}
-	return nil
-}
-
 type spriteFeat uint
 
 const (
@@ -205,36 +198,20 @@ var (
 	repl = strings.NewReplacer(":", "", "#", "", "-", "_", ".", "_")
 )
 
-func exClassNameAndExt(file string, keepMain bool) (name, clsfile, ext string) {
+func ClassNameAndExt(file string) (name, clsfile, ext string) {
 	fname := filepath.Base(file)
 	clsfile, ext = modfile.SplitFname(fname)
 	name = clsfile
 	if strings.ContainsAny(name, ":#-.") {
 		name = repl.Replace(name)
-	} else {
-		switch name {
-		case "main":
-			if !keepMain {
-				name = "_main"
-			}
-		case "init", "go":
-			name = "_" + name
-		}
 	}
 	return
 }
 
-// ClassNameAndExt func
+// GetFileClassType get ast.File classType
 // TODO(xsw): to refactor
 //
 // Deprecated: Don't use it
-func ClassNameAndExt(file string) (name, clsfile, ext string) {
-	return exClassNameAndExt(file, true)
-}
-
-// GetFileClassType get ast.File classType
-//
-// Deprecated: Don't use it (to refactor)
 func GetFileClassType(file *ast.File, filename string, lookupClass func(ext string) (c *Project, ok bool)) (classType string, isTest bool) {
 	if file.IsClass {
 		var ext string
@@ -265,7 +242,7 @@ func isGoxTestFile(ext string) bool {
 }
 
 func loadClass(ctx *pkgCtx, pkg *gogen.Package, file string, f *ast.File, conf *Config) *gmxProject {
-	tname, clsfile, ext := exClassNameAndExt(file, true)
+	tname, clsfile, ext := ClassNameAndExt(file)
 	gt, ok := conf.LookupClass(ext)
 	if !ok {
 		panic("class not found: " + ext)
@@ -303,7 +280,7 @@ func loadClass(ctx *pkgCtx, pkg *gogen.Package, file string, f *ast.File, conf *
 				panic("should have prototype if there are multiple work classes")
 			}
 			obj, _ := spxRef(spx, v.Class)
-			sp := &spxObj{obj: obj, ext: v.Ext, proto: v.Proto}
+			sp := &spxObj{obj: obj, ext: v.Ext, proto: v.Proto, prefix: v.Prefix}
 			if v.Embedded {
 				sp.feats |= spriteEmbedded
 			}
@@ -318,6 +295,7 @@ func loadClass(ctx *pkgCtx, pkg *gogen.Package, file string, f *ast.File, conf *
 			p.scheds, p.hasScheds = strings.SplitN(x, ",", 2), true
 		}
 	}
+	cls := &gmxClass{clsfile: clsfile, ext: ext, proj: p}
 	if f.IsProj {
 		if p.gameClass_ != "" {
 			panic("multiple project files found: " + tname + ", " + p.gameClass_)
@@ -327,17 +305,51 @@ func loadClass(ctx *pkgCtx, pkg *gogen.Package, file string, f *ast.File, conf *
 		if !p.isTest {
 			ctx.nproj++
 		}
+		if tname != "main" {
+			cls.name = tname
+		}
 	} else {
-		sp := p.spriteOf(ext)
+		sp := getSpxObj(p, ext)
+		tname := spName(sp, tname)
 		sp.types = append(sp.types, tname)
+		cls.sp = sp
+		cls.name = tname
 	}
-	ctx.classes[f] = &gmxClass{tname, clsfile, ext, p}
+	ctx.classes[f] = cls
 	if debugLoad {
 		log.Println("==> InitClass", tname, "isProj:", f.IsProj)
 	}
 	return p
 }
 
+type none = struct{}
+
+var specialNames = map[string]none{
+	"init": {}, "main": {}, "go": {}, "goto": {}, "type": {}, "var": {}, "import": {},
+	"package": {}, "interface": {}, "struct": {}, "const": {}, "func": {}, "map": {},
+	"for": {}, "if": {}, "else": {}, "switch": {}, "case": {}, "select": {}, "defer": {},
+	"range": {}, "return": {}, "break": {}, "continue": {}, "fallthrough": {}, "default": {},
+}
+
+func spName(sp *spxObj, name string) string {
+	if sp.prefix != "" {
+		return sp.prefix + name
+	}
+	if _, ok := specialNames[name]; ok {
+		name = "_" + name
+	}
+	return name
+}
+
+func getSpxObj(p *gmxProject, ext string) *spxObj {
+	for _, sp := range p.sprites {
+		if sp.ext == ext {
+			return sp
+		}
+	}
+	return nil
+}
+
 func spxLookup(pkgImps []gogen.PkgRef, name string) gogen.Ref {
 	for _, pkg := range pkgImps {
 		if o := pkg.TryRef(name); o != nil {
diff --git a/cl/compile.go b/cl/compile.go
index d5184d95..e2c05495 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -729,7 +729,7 @@ func preloadGopFile(p *gogen.Package, ctx *blockCtx, file string, f *ast.File, c
 	var parent = ctx.pkgCtx
 	if f.IsClass {
 		if f.IsNormalGox {
-			classType, _, _ = exClassNameAndExt(file, false)
+			classType, _, _ = ClassNameAndExt(file)
 			if f.ShadowEntry != nil {
 				parent.goxMainClass = classType
 				parent.goxMain++
@@ -755,7 +755,7 @@ func preloadGopFile(p *gogen.Package, ctx *blockCtx, file string, f *ast.File, c
 					baseType = types.NewPointer(baseType)
 				}
 			} else {
-				sp = proj.spriteOf(c.ext)
+				sp = c.sp
 				o := sp.obj
 				ctx.baseClass = o
 				baseTypeName, baseType = o.Name(), o.Type()


Test patch:
diff --git a/cl/_testspx/multiworks/out.go b/cl/_testspx/multiworks/out.go
index aa9d0972..6956d519 100644
--- a/cl/_testspx/multiworks/out.go
+++ b/cl/_testspx/multiworks/out.go
@@ -6,7 +6,7 @@ type foo struct {
 	mcp.Prompt
 	*Game
 }
-type hello struct {
+type Tool_hello struct {
 	mcp.Tool
 	*Game
 }
@@ -19,7 +19,7 @@ func (this *Game) MainEntry() {
 	this.Server("protos")
 }
 func (this *Game) Main() {
-	_gop_obj0 := &hello{Game: this}
+	_gop_obj0 := &Tool_hello{Game: this}
 	_gop_lst1 := []mcp.ToolProto{_gop_obj0}
 	_gop_obj1 := &foo{Game: this}
 	this.foo = _gop_obj1
@@ -30,7 +30,7 @@ func (this *foo) Main(_gop_arg0 *mcp.Tool) string {
 	this.Prompt.Main(_gop_arg0)
 	return "Hi"
 }
-func (this *hello) Main(_gop_arg0 string) int {
+func (this *Tool_hello) Main(_gop_arg0 string) int {
 	this.Tool.Main(_gop_arg0)
 	return -1
 }
diff --git a/cl/builtin_test.go b/cl/builtin_test.go
index 57270975..f6a1914e 100644
--- a/cl/builtin_test.go
+++ b/cl/builtin_test.go
@@ -55,7 +55,7 @@ func TestLoadExpr(t *testing.T) {
 
 func TestSpriteOf(t *testing.T) {
 	proj := &gmxProject{}
-	if proj.spriteOf("a") != nil {
+	if getSpxObj(proj, "a") != nil {
 		t.Fatal("spriteOf: not nil?")
 	}
 }
diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go
index 256d2b1b..44000f38 100644
--- a/cl/cltest/cltest.go
+++ b/cl/cltest/cltest.go
@@ -100,7 +100,7 @@ func LookupClass(ext string) (c *modfile.Project, ok bool) {
 		return &modfile.Project{
 			Ext: "_mcp.gox", Class: "Game",
 			Works: []*modfile.Class{
-				{Ext: "_tool.gox", Class: "Tool", Proto: "ToolProto"},
+				{Ext: "_tool.gox", Class: "Tool", Proto: "ToolProto", Prefix: "Tool_"},
 				{Ext: "_prompt.gox", Class: "Prompt", Proto: "PromptProto", Embedded: true},
 				{Ext: "_res.gox", Class: "Resource", Proto: "ResourceProto"},
 			},