Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func NewPackage(pkgPath, pkgName string, files []Source, conf *Config) (ret Pack
if conf == nil {
conf = &Config{}
}
methodCheck, err := newMethodChecks(conf.MethodCheck)
methodCheck, err := newMatchers("MethodCheck", conf.MethodCheck)
if err != nil {
return
}
Expand Down Expand Up @@ -266,7 +266,6 @@ func NewPackage(pkgPath, pkgName string, files []Source, conf *Config) (ret Pack
pkgOf: conf.PackageOf, nameLookup: nameLookup, pubLookup: conf.PubFileLookup,
fileBases: make(map[clang.File]int), ovobjs: make(map[string]*overloadObj),
macroVals: make(map[string]any), types: make(map[string]typeObj),
logicals: make(map[string]*types.Named),
lastSeen: make(map[string]none), impPkgs: make(map[string]none),
}

Expand Down
4 changes: 1 addition & 3 deletions cl/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ type pkgCtx struct {

typeAbbrSuffix []string

mthdCheck []*mthdCheck
mthdCheck []*matcher
nsPrefix []string
fnPrefix []string
varPrefix []string
Expand Down Expand Up @@ -155,8 +155,6 @@ type pkgCtx struct {
lastSeen map[string]none // last seen include file set (loaded include files)
thisSeen map[string]none // include file set seen in this translation unit

logicals map[string]*types.Named // logical Go class name => logical class type

loads []compileUnit
compiles []compileUnit
pubs []Entry
Expand Down
33 changes: 19 additions & 14 deletions cl/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,8 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *overloadObj, this *classCtx) {
var nameInPkg string
if this == nil {
if ctx.lang == LanguageC {
if cls, mayClass := ctx.methodCheck(cName); mayClass {
if cls, obj, mayClass := ctx.methodCheck(pkgTypes, cName); mayClass {
// try to method for C global functions
oldParams := params
params, recv, typRecv, typName = tryToMethod(ctx, pkgTypes, params)
if typRecv != nil {
recvCType := fn.Argument(0).Type()
Expand All @@ -143,18 +142,10 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *overloadObj, this *classCtx) {
recvCType = recvCType.Pointee()
}
typCName = trimTypeTag(clang.String(recvCType.Unqualified()))
// When the function resolves to a logical class distinct from
// the physical receiver type (for example PyList_GetItem
// resolves to List while its receiver is the base class
// Object), emit the method on the logical class - which embeds
// the base - and generate the As<Class> conversion method on
// the base class. See logical.go.
if isPtr && cls != "" && cls != typName {
if contains(cls, ctx.nonClasses) {
params, recv, typName, typCName = oldParams, nil, "", ""
} else if logical, ok := ctx.logicalClassOf(fn, cls, typRecv, recv); ok {
recv = types.NewParam(recv.Pos(), pkgTypes, recv.Name(), types.NewPointer(logical))
typRecv = logical
if t := obj.Type(); isTypeFromBase(t, typRecv) {
recv = types.NewParam(recv.Pos(), pkgTypes, recv.Name(), types.NewPointer(t))
typRecv = types.Unalias(t).(*types.Named)
typName = cls
}
}
Expand Down Expand Up @@ -220,6 +211,20 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *overloadObj, this *classCtx) {
}
}

func isTypeFromBase(t types.Type, base *types.Named) bool {
if t, ok := types.Unalias(t).(*types.Named); ok {
if t == base {
return true
}
if s, ok := t.Underlying().(*types.Struct); ok {
if s.NumFields() > 0 {
return isTypeFromBase(s.Field(0).Type(), base)
}
}
}
return false
}

func findMember(typ *types.Named, name string) (pos token.Pos, isField bool, exists bool) {
for i := range typ.NumMethods() {
m := typ.Method(i)
Expand Down Expand Up @@ -247,7 +252,7 @@ func tryToMethod(ctx *pkgCtx, pkgTypes *types.Package, params []*types.Var) ([]*
first := params[0]
t := first.Type()
if len(params) == 2 && params[1].Type() == t {
// don't convert to method if the first two params have the same type
// don't convert to method if the two params have the same type
return params, nil, nil, ""
}
tPtr, isPtr := t.(*types.Pointer)
Expand Down
130 changes: 0 additions & 130 deletions cl/logical.go

This file was deleted.

61 changes: 36 additions & 25 deletions cl/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cl

import (
"fmt"
"go/types"
"strconv"
"strings"

Expand All @@ -43,31 +44,31 @@ func objUSR(decl clang.Cursor) string {

// -----------------------------------------------------------------------------

type mthdCheck struct {
type matcher struct {
prefix string
pattern []string
result string
}

func newMethodCheck(check string) (*mthdCheck, error) {
pos := strings.IndexByte(check, ':')
func newMatcher(name, expr string) (*matcher, error) {
pos := strings.IndexByte(expr, ':')
if pos < 0 {
return nil, fmt.Errorf("invalid MethodCheck: %s", check)
return nil, fmt.Errorf("invalid %s: %s", name, expr)
}
pattern := strings.TrimSpace(check[:pos])
pattern := strings.TrimSpace(expr[:pos])
parts := strings.Split(pattern, "*")
result := strings.TrimSpace(check[pos+1:])
return &mthdCheck{
result := strings.TrimSpace(expr[pos+1:])
return &matcher{
prefix: parts[0],
pattern: parts[1:],
result: result,
}, nil
}

func newMethodChecks(check []string) ([]*mthdCheck, error) {
ret := make([]*mthdCheck, len(check))
for i, c := range check {
m, err := newMethodCheck(c)
func newMatchers(name string, exprs []string) ([]*matcher, error) {
ret := make([]*matcher, len(exprs))
for i, c := range exprs {
m, err := newMatcher(name, c)
if err != nil {
return nil, err
}
Expand All @@ -76,25 +77,26 @@ func newMethodChecks(check []string) ([]*mthdCheck, error) {
return ret, nil
}

func (p *mthdCheck) check(name string) (cls string, ok bool) {
name, ok = strings.CutPrefix(name, p.prefix)
func (p *matcher) match(source string, matchFull bool) (ret string, matched bool) {
source, ok := strings.CutPrefix(source, p.prefix)
if !ok {
return
}
n := 0
match := make([]string, len(p.pattern))
for i, p := range p.pattern {
pos := strings.Index(name, p)
pos := strings.Index(source, p)
if pos < 0 {
return
}
n += pos
match[i] = name[:pos]
name = name[pos+len(p):]
match[i] = source[:pos]
source = source[pos+len(p):]
}
cls = matchResult(p.result, match, n)
ok = cls != ""
return
if matchFull && source != "" {
return
}
return matchResult(p.result, match, n), true
}

func matchResult(result string, match []string, n int) string {
Expand All @@ -119,6 +121,15 @@ func matchResult(result string, match []string, n int) string {
return string(b)
}

func match(source string, matches []*matcher, matchFull bool) (ret string, matched bool) {
for _, m := range matches {
if r, ok := m.match(source, matchFull); ok {
return r, true
}
}
return "", false
}

// -----------------------------------------------------------------------------

func cNameSplit(cName string) (parts []string, hasNS bool) {
Expand Down Expand Up @@ -247,15 +258,15 @@ func (p *pkgCtx) typeName(cName string, _ bool) string {
return p.cstyleToGo(name, underscoreStart, true)
}

func (p *pkgCtx) methodCheck(cName string) (cls string, mayClass bool) {
func (p *pkgCtx) methodCheck(pkgTypes *types.Package, cName string) (cls string, obj types.Object, mayClass bool) {
if len(p.mthdCheck) == 0 {
return "", true
return "", nil, true // allow tryToMethod
}
for _, m := range p.mthdCheck {
if cls, mayClass = m.check(cName); mayClass {
return
}
cls, mayClass = match(cName, p.mthdCheck, false)
if cls != "" {
obj = pkgTypes.Scope().Lookup(cls)
}
mayClass = obj != nil
return
}

Expand Down
14 changes: 13 additions & 1 deletion tool/_testc/python-3.14.8/include/pythread.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ typedef enum Py_Lock_Status {

typedef struct _Py_tss_t Py_tss_t; /* opaque */

struct _object {};
struct _object {
Py_ssize_t ob_refcnt;
};

typedef struct _object PyObject;

Expand All @@ -26,9 +28,19 @@ PyAPI_FUNC(int) Py_IsTrue(PyObject *x);

PyAPI_FUNC(int) PyObject_IsTrue(PyObject *x);

typedef struct {
struct _object ob_base;
Py_ssize_t ob_size;
} PyListObject;

PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *x, PyObject *index);
PyAPI_FUNC(void) PyList_SetItem(PyObject *x, PyObject *index, PyObject *value);

typedef struct {
struct _object ob_base;
Py_ssize_t ma_used;
} PyDictObject;

PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *x, PyObject *index);

PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name);
Expand Down
4 changes: 2 additions & 2 deletions tool/_testc/python-3.14.8/llcppg.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"Files": ["Python.h"],
"Deps": [],
"Class": [],
"NonClass": ["Import"],
"NonClass": [],
"TypePrefix": ["Py_", "Py"],
"MethodCheck": ["Py*_: $1"],
"MethodCheck": ["PyObject_: Object", "Py_: ", "Py*_: $1Object"],
"FuncPrefix": ["Py_", "Py"],
"MacroPrefix": ["PY_", "Py_"],
"EnumPrefix": ["PY_"],
Expand Down
Loading
Loading