diff --git a/cl/ctx.go b/cl/ctx.go index eac9726a..ad0c50ef 100644 --- a/cl/ctx.go +++ b/cl/ctx.go @@ -23,7 +23,6 @@ import ( "go/types" "log" "sort" - "strconv" "strings" "github.com/goplus/gogen" @@ -179,16 +178,6 @@ func (p *pkgCtx) logtf(typ lc.Type, format string, args ...any) { p.logf(typ.Declaration(), format, args...) } -const ( - anonPrefix = "_llcppg_anon_" -) - -func (p *pkgCtx) nextAnonName() string { - name := anonPrefix + strconv.Itoa(p.anonSeq) - p.anonSeq++ - return name -} - func (p *pkgCtx) getFileBase(c clang.Cursor, file clang.File) int { base, ok := p.fileBases[file] if !ok { @@ -301,220 +290,12 @@ func (p *pkgCtx) typeOf(cName string) (types.Type, bool) { return nil, false } -func (p *pkgCtx) isMacroIgnored(name string) bool { - return contains(name, p.macroIgnore) -} - -func (p *pkgCtx) isNSIgnored(ns string) bool { - return contains(ns, p.nsIgnores) -} - -func (p *pkgCtx) globalName(name string, trimPrefixs []string) string { - if v, ok := p.rename[name]; ok { - return v // special case - } - return p.cstyleToGo(rmPrefix(name, trimPrefixs), true) -} - -func (p *pkgCtx) fieldName(name string, public bool) string { - return p.cstyleToGo(name, public) -} - -func (p *pkgCtx) varName(name string) string { - return p.globalName(name, p.varPrefix) -} - -func (p *pkgCtx) macroName(name string) string { - return p.globalName(name, p.macroPrefix) +func (p *pkgCtx) isMacroIgnored(cName string) bool { + return contains(cName, p.macroIgnore) } -func (p *pkgCtx) enumvalName(name, ns string) string { - if strings.HasSuffix(ns, "_") { - return p.globalName(ns, p.enumPrefix) + p.cstyleToGo(name, true) - } - return p.globalName(nameWithNS(name, ns), p.enumPrefix) -} - -func (p *pkgCtx) typeName(name string, _ bool) string { - if v, ok := p.rename[name]; ok { - return v // special case - } - name = rmPrefix(name, p.typePrefix) - name = rmSuffix(name, p.typeSuffix) - return p.cstyleToGo(name, true) -} - -func (p *pkgCtx) funcName(name string, order int, typName, typCName string, global, _ bool) string { - if v, ok := p.rename[name]; ok { - return v // special case - } - if global { - name = rmPrefix(name, p.fnPrefix) - if typCName != "" { - // remove typCName prefix & suffix - if before, ok := strings.CutSuffix(name, typCName); ok { - name = strings.TrimSuffix(before, "_") - } else if after, ok := strings.CutPrefix(name, typCName+"_"); ok { - name = after - } else { - name = strings.TrimPrefix(name, typName+"_") - } - } - } else { - // don't remove type name suffix for a method - typName = "" - } - if !strings.HasPrefix(name, "XGo_") { // avoid rewriting XGo_xxx names - name = p.cstyleToGo(name, true) - if typName != "" { - var typSuffix []string - if v, ok := p.typeAbbr[typName]; ok { // Go type name => abbreviated name - switch v := v.(type) { - case string: - typName = v - typSuffix = []string{v} - case []any: - if n := len(v); n > 0 { - abbrs := make([]string, n) - for i, v := range v { - abbrs[i] = v.(string) - } - typName = abbrs[n-1] - typSuffix = abbrs - } - default: - panic(fmt.Errorf("invalid TypeAbbr for %q: %v", typName, v)) - } - } else { - typName = rmSuffix(typName, p.typeAbbrSuffix) - typSuffix = []string{typName} - } - name = rmSuffix(name, typSuffix) - name = cutMethodPrefix(name, typName) - } - } - if order >= 0 { - name = name + "__" + strconv.FormatInt(int64(order), 36) - } - return name -} - -func (p *pkgCtx) cstyleToGo(cName string, public bool) string { - rename := p.rename - parts := strings.Split(cName, "_") - if isAllUpperStart(parts) { - if parts[0] == "" && public { - return "X" + cName - } - return cName - } - for i := 0; i < len(parts); i++ { - part := parts[i] - if part == "" { - if i == 0 && public { - parts[i] = "X_" - i++ // skip next part - } else { - parts[i] = "_" - } - } else if v, ok := rename[part]; ok { - parts[i] = v - } else if i > 0 || public { - parts[i] = cPubName(part) - } - } - return strings.Join(parts, "") -} - -func (p *pkgCtx) nsName(ns, inner string) string { - if v, ok := p.rename[inner]; ok { - inner = v // special case - } - return nsName(ns, inner) -} - -func nsName(ns, inner string) string { - if ns != "" { - c := ns[len(ns)-1] - if 'A' <= c && c <= 'Z' { - ns += "_" - } - } - if c := inner[0]; 'a' <= c && c <= 'z' { - return ns + string(c-'a'+'A') + inner[1:] - } - return ns + inner -} - -func nameWithNS(name, ns string) string { - if ns == "" { - return name - } - return nsName(ns, name) -} - -func isAllUpperStart(parts []string) bool { - for _, part := range parts { - if part != "" { - if r := part[0]; 'a' <= r && r <= 'z' { - return false - } - } - } - return true -} - -func cutMethodPrefix(name, objName string) string { - name = cutPrefix(name, objName) - name = cutPrefix(name, "Get") - return cutPrefix(name, objName) -} - -func cutPrefix(name, prefix string) string { - after, ok := strings.CutPrefix(name, prefix) - if ok && after != "" { - if c := after[0]; 'A' <= c && c <= 'Z' { - return after - } - } - return name -} - -func cPubName(name string) string { - if r := name[0]; 'a' <= r && r <= 'z' { - r -= 'a' - 'A' - return string(r) + name[1:] - } else if r == '_' { - return "X" + name - } - return name -} - -func rmPrefix(name string, prefix []string) string { - for _, pfx := range prefix { - if strings.HasPrefix(name, pfx) { - return name[len(pfx):] - } - } - return name -} - -func rmSuffix(name string, suffix []string) string { - for _, sfx := range suffix { - if strings.HasSuffix(name, sfx) { - return name[:len(name)-len(sfx)] - } - } - return name -} - -func contains(v string, names []string) bool { - for _, name := range names { - if name == v { - return true - } - } - return false +func (p *pkgCtx) isNSIgnored(cName string) bool { + return contains(cName, p.nsIgnores) } // ----------------------------------------------------------------------------- @@ -698,12 +479,4 @@ func (p *scopeCtx) reorder() { } } -func funcUSR(decl clang.Cursor) string { - return clang.USR(decl) -} - -func funcDisplayName(decl clang.Cursor) string { - return clang.DisplayName(decl) -} - // ----------------------------------------------------------------------------- diff --git a/cl/name.go b/cl/name.go new file mode 100644 index 00000000..d6e50bd7 --- /dev/null +++ b/cl/name.go @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2026 The XGo Authors (xgo.dev). 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 cl + +import ( + "fmt" + "strconv" + "strings" + + "github.com/goplus/llcppg/clang" +) + +// ----------------------------------------------------------------------------- + +const ( + anonPrefix = "_llcppg_anon_" +) + +func (p *pkgCtx) nextAnonName() string { + name := anonPrefix + strconv.Itoa(p.anonSeq) + p.anonSeq++ + return name +} + +// ----------------------------------------------------------------------------- + +func funcUSR(decl clang.Cursor) string { + return clang.USR(decl) +} + +func funcDisplayName(decl clang.Cursor) string { + return clang.DisplayName(decl) +} + +// ----------------------------------------------------------------------------- + +func (p *pkgCtx) globalName(name string, trimPrefixs []string) string { + if v, ok := p.rename[name]; ok { + return v // special case + } + return p.cstyleToGo(rmPrefix(name, trimPrefixs), true) +} + +func (p *pkgCtx) fieldName(name string, public bool) string { + return p.cstyleToGo(name, public) +} + +func (p *pkgCtx) varName(name string) string { + return p.globalName(name, p.varPrefix) +} + +func (p *pkgCtx) macroName(name string) string { + return p.globalName(name, p.macroPrefix) +} + +func (p *pkgCtx) enumvalName(name, ns string) string { + if strings.HasSuffix(ns, "_") { + return p.globalName(ns, p.enumPrefix) + p.cstyleToGo(name, true) + } + return p.globalName(nameWithNS(name, ns), p.enumPrefix) +} + +func (p *pkgCtx) typeName(name string, _ bool) string { + if v, ok := p.rename[name]; ok { + return v // special case + } + name = rmPrefix(name, p.typePrefix) + name = rmSuffix(name, p.typeSuffix) + return p.cstyleToGo(name, true) +} + +func (p *pkgCtx) funcName(name string, order int, typName, typCName string, global, _ bool) string { + if v, ok := p.rename[name]; ok { + return v // special case + } + if global { + name = rmPrefix(name, p.fnPrefix) + if typCName != "" { + // remove typCName prefix & suffix + if before, ok := strings.CutSuffix(name, typCName); ok { + name = strings.TrimSuffix(before, "_") + } else if after, ok := strings.CutPrefix(name, typCName+"_"); ok { + name = after + } else { + name = strings.TrimPrefix(name, typName+"_") + } + } + } else { + // don't remove type name suffix for a method + typName = "" + } + if !strings.HasPrefix(name, "XGo_") { // avoid rewriting XGo_xxx names + name = p.cstyleToGo(name, true) + if typName != "" { + var typSuffix []string + if v, ok := p.typeAbbr[typName]; ok { // Go type name => abbreviated name + switch v := v.(type) { + case string: + typName = v + typSuffix = []string{v} + case []any: + if n := len(v); n > 0 { + abbrs := make([]string, n) + for i, v := range v { + abbrs[i] = v.(string) + } + typName = abbrs[n-1] + typSuffix = abbrs + } + default: + panic(fmt.Errorf("invalid TypeAbbr for %q: %v", typName, v)) + } + } else { + typName = rmSuffix(typName, p.typeAbbrSuffix) + typSuffix = []string{typName} + } + name = rmSuffix(name, typSuffix) + name = cutMethodPrefix(name, typName) + } + } + if order >= 0 { + name = name + "__" + strconv.FormatInt(int64(order), 36) + } + return name +} + +func (p *pkgCtx) cstyleToGo(cName string, public bool) string { + rename := p.rename + parts := strings.Split(cName, "_") + if isAllUpperStart(parts) { + if parts[0] == "" && public { + return "X" + cName + } + return cName + } + for i := 0; i < len(parts); i++ { + part := parts[i] + if part == "" { + if i == 0 && public { + parts[i] = "X_" + i++ // skip next part + } else { + parts[i] = "_" + } + } else if v, ok := rename[part]; ok { + parts[i] = v + } else if i > 0 || public { + parts[i] = cPubName(part) + } + } + return strings.Join(parts, "") +} + +func (p *pkgCtx) nsName(ns, inner string) string { + if v, ok := p.rename[inner]; ok { + inner = v // special case + } + return nsName(ns, inner) +} + +func nsName(ns, inner string) string { + if ns != "" { + c := ns[len(ns)-1] + if 'A' <= c && c <= 'Z' { + ns += "_" + } + } + if c := inner[0]; 'a' <= c && c <= 'z' { + return ns + string(c-'a'+'A') + inner[1:] + } + return ns + inner +} + +func nameWithNS(name, ns string) string { + if ns == "" { + return name + } + return nsName(ns, name) +} + +// ----------------------------------------------------------------------------- + +func isAllUpperStart(parts []string) bool { + for _, part := range parts { + if part != "" { + if r := part[0]; 'a' <= r && r <= 'z' { + return false + } + } + } + return true +} + +func cutMethodPrefix(name, objName string) string { + name = cutPrefix(name, objName) + name = cutPrefix(name, "Get") + return cutPrefix(name, objName) +} + +func cutPrefix(name, prefix string) string { + after, ok := strings.CutPrefix(name, prefix) + if ok && after != "" { + if c := after[0]; 'A' <= c && c <= 'Z' { + return after + } + } + return name +} + +func cPubName(name string) string { + if r := name[0]; 'a' <= r && r <= 'z' { + r -= 'a' - 'A' + return string(r) + name[1:] + } else if r == '_' { + return "X" + name + } + return name +} + +func rmPrefix(name string, prefix []string) string { + for _, pfx := range prefix { + if strings.HasPrefix(name, pfx) { + return name[len(pfx):] + } + } + return name +} + +func rmSuffix(name string, suffix []string) string { + for _, sfx := range suffix { + if strings.HasSuffix(name, sfx) { + return name[:len(name)-len(sfx)] + } + } + return name +} + +func contains(v string, names []string) bool { + for _, name := range names { + if name == v { + return true + } + } + return false +} + +// -----------------------------------------------------------------------------