Browse Source

improve ffigen 2

blueloveTH 2 tháng trước cách đây
mục cha
commit
13594f9bfe

+ 2 - 3
ffigen/ffigen/converters.py

@@ -165,9 +165,8 @@ def set_vmath_converter(T: str, py_T: str):
 def has_vmath_converter() -> bool:
     return _has_vmath_converter
 
-def set_enum_converters(enums: list[str]):
-    for T in enums:
-        _CONVERTERS[T] = EnumConverter(T)
+def set_enum_converter(T: str):
+    _CONVERTERS[T] = EnumConverter(T)
 
 def get_converter(T: str) -> Converter:
     if T in _CONVERTERS:

+ 8 - 10
ffigen/ffigen/library.py

@@ -3,7 +3,7 @@ from .writer import Writer
 from .enum import gen_enum
 from .struct import gen_struct
 from .function import gen_function
-from .converters import is_vmath_type, has_vmath_converter
+from .converters import is_vmath_type, has_vmath_converter, set_enum_converter
 
 from typing import TYPE_CHECKING
 if TYPE_CHECKING:
@@ -31,6 +31,11 @@ class Library:
     def build(self, *, glue_dir='.', stub_dir='.', includes: list[str] | None = None):
         self.remove_unsupported()
 
+        for k in self.aliases.keys():
+            node = self.unalias(k)
+            if isinstance(node, c_ast.Enum):
+                set_enum_converter(k)
+
         w, pyi_w = Writer(), Writer()
 
         if has_vmath_converter():
@@ -50,15 +55,6 @@ class Library:
         w.write('')
         w.write('#define ADD_ENUM(name) py_newint(py_emplacedict(mod, py_name(#name)), name)')
         w.write('')
-        w.write('static bool struct__address__(int argc, py_Ref argv) {')
-        w.indent()
-        w.write('PY_CHECK_ARGC(1);')
-        w.write('void* ud = py_touserdata(argv);')
-        w.write('py_newint(py_retval(), (py_i64)ud);')
-        w.write('return true;')
-        w.dedent()
-        w.write('}')
-        w.write('')
 
         for k in self.aliases.keys():
             node = self.unalias(k)
@@ -135,6 +131,7 @@ class Library:
                 continue
             self.structs.append(Struct(
                 name=struct['name'],
+                typedef_name=struct['name'],
                 desc=struct['description'],
                 fields=[StructField(
                     type=field['type'],
@@ -182,6 +179,7 @@ class Library:
                     assert fields is not None
                     self.structs.append(Struct(
                         name=type.name,
+                        typedef_name=type.typedef_name,
                         fields=[StructField(
                             type=field_type,
                             name=field_name

+ 9 - 6
ffigen/ffigen/meta/parser.py

@@ -31,13 +31,13 @@ class Header:
             return
         self.type_aliases[k] = v
 
-    def build_enum(self, node: c_ast.Enum):
+    def build_enum(self, node: c_ast.Enum, alias_name: str | None = None):
         enum = Enum(node.name)
         for item in node.values.enumerators:
             enum.values.append(item.name)
         self.types.append(enum)
 
-    def build_struct(self, node):
+    def build_struct(self, node: c_ast.Struct | c_ast.Union, alias_name: str | None = None):
         if isinstance(node, c_ast.Struct):
             cls = Struct
         elif isinstance(node, c_ast.Union):
@@ -53,17 +53,17 @@ class Header:
                     fields[name] = type
                 except UnsupportedNode:
                     pass
-            self.types.append(cls(node.name, fields))
+            self.types.append(cls(node.name, fields, alias_name))
         else:
-            self.types.append(cls(node.name, None))
+            self.types.append(cls(node.name, None, alias_name))
 
     def build_type(self, node, alias_name):
         if isinstance(node, c_ast.Enum):
-            self.build_enum(node)
+            self.build_enum(node, alias_name)
             if alias_name:
                 self.add_type_alias(alias_name, node)
         elif isinstance(node, (c_ast.Struct, c_ast.Union)):
-            self.build_struct(node)
+            self.build_struct(node, alias_name)
             if alias_name:
                 self.add_type_alias(alias_name, node)
         elif isinstance(node, c_ast.IdentifierType):
@@ -132,6 +132,9 @@ class Header:
         assert isinstance(node, c_ast.TypeDecl), type(node)
         name = node.declname
         ret = node.type.names[0]
+        is_const = node.quals and 'const' in node.quals
+        if is_const:
+            ret = 'const ' + ret
         func = Function(name, ret + '*' * level)
         if args is not None:
             for param in args.params:

+ 2 - 1
ffigen/ffigen/meta/schema.py

@@ -7,9 +7,10 @@ class Pointer:
         self.level = level
 
 class NamedFields:
-    def __init__(self, name: str, fields: dict[str, str] | None):
+    def __init__(self, name: str, fields: dict[str, str] | None, typedef_name: str | None = None):
         self.name = name
         self.fields = fields
+        self.typedef_name = typedef_name
 
     def is_opaque(self):
         return self.fields is None

+ 16 - 1
ffigen/ffigen/schema.py

@@ -15,10 +15,25 @@ class EnumValue:
 
 @dataclass
 class Struct:
-    name: str
+    name: str | None = None
+    typedef_name: str | None = None
     desc: str | None = None
     fields: list[StructField] | None = None
 
+    @property
+    def code_name(self):
+        if self.typedef_name:
+            return self.typedef_name
+        assert self.name is not None
+        return f'struct {self.name}'
+    
+    @property
+    def identifier(self):
+        if self.name:
+            return self.name
+        assert self.typedef_name is not None
+        return self.typedef_name
+
 @dataclass
 class Enum:
     name: str

+ 21 - 35
ffigen/ffigen/struct.py

@@ -2,21 +2,21 @@ from .writer import Writer
 from .converters import get_converter, Converter
 from .schema import Struct, StructField
 
-def gen_getter(w: Writer, name: str, cvt: Converter, field: StructField):
-    w.write(f'static bool {name}__get_{field.name}(int argc, py_Ref argv) {{')
+def gen_getter(w: Writer, struct: Struct, cvt: Converter, field: StructField):
+    w.write(f'static bool {struct.identifier}__get_{field.name}(int argc, py_Ref argv) {{')
     w.indent()
     w.write(f'PY_CHECK_ARGC(1);')
-    w.write(f'{name}* self = py_touserdata(argv);')
+    w.write(f'{struct.code_name}* self = py_touserdata(argv);')
     cvt.c2py(w, 'py_retval()', f'self->{field.name}')
     w.write('return true;')
     w.dedent()
     w.write('}')
 
-def gen_setter(w: Writer, name: str, cvt: Converter, field: StructField):
-    w.write(f'static bool {name}__set_{field.name}(int argc, py_Ref argv) {{')
+def gen_setter(w: Writer, struct: Struct, cvt: Converter, field: StructField):
+    w.write(f'static bool {struct.identifier}__set_{field.name}(int argc, py_Ref argv) {{')
     w.indent()
     w.write(f'PY_CHECK_ARGC(2);')
-    w.write(f'{name}* self = py_touserdata(argv);')
+    w.write(f'{struct.code_name}* self = py_touserdata(argv);')
     cvt.py2c(w, f'self->{field.name}', 'py_arg(1)')
     w.write('py_newnone(py_retval());')
     w.write('return true;')
@@ -24,10 +24,11 @@ def gen_setter(w: Writer, name: str, cvt: Converter, field: StructField):
     w.write('}')
 
 def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
-    name = struct.name
+    name = struct.code_name
+    identifier = struct.identifier
     converters = [get_converter(field.type) for field in struct.fields or []]
     # default __new__
-    w.write(f'static bool {name}__new__(int argc, py_Ref argv) {{')
+    w.write(f'static bool {identifier}__new__(int argc, py_Ref argv) {{')
     w.indent()
     w.write(f'py_Type cls = py_totype(argv);')
     w.write(f'py_newobject(py_retval(), cls, 0, sizeof({name}));')
@@ -36,7 +37,7 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     w.write('}')
 
     # default __init__
-    w.write(f'static bool {name}__init__(int argc, py_Ref argv) {{')
+    w.write(f'static bool {identifier}__init__(int argc, py_Ref argv) {{')
     w.indent()
     w.write(f'{name}* self = py_touserdata(argv);')
     w.write(f'if(argc == 1) {{')
@@ -62,46 +63,33 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     w.dedent()
     w.write('}')
 
-    # default __copy__
-    w.write(f'static bool {name}__copy__(int argc, py_Ref argv) {{')
-    w.indent()
-    w.write(f'PY_CHECK_ARGC(1);')
-    w.write(f'{name}* self = py_touserdata(argv);')
-    w.write(f'{name}* res = py_newobject(py_retval(), py_typeof(argv), 0, sizeof({name}));')
-    w.write(f'*res = *self;')
-    w.write('return true;')
-    w.dedent()
-    w.write('}')
-
     for i, field in enumerate(struct.fields):
         cvt = converters[i]
-        gen_getter(w, name, cvt, field)
+        gen_getter(w, struct, cvt, field)
         if not cvt.is_const():
-            gen_setter(w, name, cvt, field)
+            gen_setter(w, struct, cvt, field)
 
-    w.write(f'static py_Type register__{name}(py_GlobalRef mod) {{')
+    w.write(f'static py_Type register__{identifier}(py_GlobalRef mod) {{')
     w.indent()
-    w.write(f'py_Type type = py_newtype("{name}", tp_object, mod, NULL);')
+    w.write(f'py_Type type = py_newtype("{identifier}", tp_object, mod, NULL);')
 
-    w.write(f'py_bindmagic(type, __new__, {name}__new__);')
-    w.write(f'py_bindmagic(type, __init__, {name}__init__);')
-    w.write(f'py_bindmethod(type, "__address__", struct__address__);')
-    w.write(f'py_bindmethod(type, "copy", {name}__copy__);')
+    w.write(f'py_bindmethod(type, "__new__", {identifier}__new__);')
+    w.write(f'py_bindmethod(type, "__init__", {identifier}__init__);')
 
     for i, field in enumerate(struct.fields):
         cvt = converters[i]
         if cvt.is_const():
             setter = 'NULL'
         else:
-            setter = f'{name}__set_{field.name}'
-        w.write(f'py_bindproperty(type, "{field.name}", {name}__get_{field.name}, {setter});')
+            setter = f'{identifier}__set_{field.name}'
+        w.write(f'py_bindproperty(type, "{field.name}", {identifier}__get_{field.name}, {setter});')
 
     w.write(f'return type;')
     w.dedent()
     w.write('}')
 
     # pyi
-    pyi_w.write(f'class {name}:')
+    pyi_w.write(f'class {identifier}:')
     pyi_w.indent()
 
     py_args = []
@@ -116,10 +104,8 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     pyi_w.write(f'def __init__(self): ...')
     pyi_w.write(f'@overload')
     pyi_w.write(f'def __init__(self, {", ".join(py_args)}): ...')
-    pyi_w.write(f'def __address__(self) -> int: ...')
-    pyi_w.write(f"def copy(self) -> '{name}': ...")
     pyi_w.write('')
     pyi_w.dedent()
 
-    w.write(f'static py_Type tp_user_{name};')
-    return f'tp_user_{name} = register__{name}(mod);'
+    w.write(f'static py_Type tp_user_{identifier};')
+    return f'tp_user_{identifier} = register__{identifier}(mod);'

+ 1 - 1
ffigen/gen_periphery.py

@@ -1,7 +1,7 @@
 import pcpp
 import pycparser
 from ffigen.library import Library
-from ffigen.converters import set_vmath_converter, set_enum_converters
+from ffigen.converters import set_vmath_converter, set_enum_converter
 from ffigen.meta import Header
 import os