blueloveTH 2 месяцев назад
Родитель
Сommit
671ea14c4f

+ 6 - 0
ffigen/ffigen/converters.py

@@ -155,9 +155,15 @@ def is_vmath_type(T: str) -> bool:
         return False
     return isinstance(cvt, BuiltinVMathConverter)
 
+_has_vmath_converter = False
 def set_vmath_converter(T: str, py_T: str):
+    global _has_vmath_converter
     assert py_T in VMATH_TYPES
     _CONVERTERS[T] = BuiltinVMathConverter(T, py_T)
+    _has_vmath_converter = True
+
+def has_vmath_converter() -> bool:
+    return _has_vmath_converter
 
 def set_enum_converters(enums: list[str]):
     for T in enums:

+ 2 - 2
ffigen/ffigen/function.py

@@ -40,12 +40,12 @@ def gen_function(w: Writer, pyi_w: Writer, function: Function):
 
     # pyi
     py_args = []
-    # arg_names = [f'_{i}' for i in range(len(args_cvt))]
     arg_names = [sanitize_name(arg.name) for arg in function.params]
     for i in range(len(args_cvt)):
         py_args.append(f'{arg_names[i]}: {args_cvt[i].py_T}')
 
-    py_args.append('/')
+    if len(py_args) > 0:
+        py_args.append('/')
     pyi_w.write(f'def {name}({", ".join(py_args)}) -> {ret_cvt.py_T}:')
     if function.desc:
         pyi_w.write(f'    """Wraps `{function.signature()}`\n\n    {function.desc}"""')

+ 30 - 19
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
+from .converters import is_vmath_type, has_vmath_converter
 
 from typing import TYPE_CHECKING
 if TYPE_CHECKING:
@@ -14,23 +14,34 @@ class Library:
         self.name = name
         # ['defines', 'structs', 'aliases', 'enums', 'callbacks', 'functions']
         self.structs = []   # type: list[Struct]
-        self.aliases = []   # type: list[Alias]
+        self.aliases = {}   # type: dict[str, str | c_ast.Node]
         self.enums = []     # type: list[Enum]
         self.functions = [] # type: list[Function]
         self.callbacks = set() # type: set[str]
 
+    def unalias(self, name: str) -> c_ast.Node:
+        while name in self.aliases:
+            node = self.aliases[name]
+            if isinstance(node, str):
+                name = node
+            else:
+                return node
+        assert False, f'alias {name} not found'
+
     def build(self, *, glue_dir='.', stub_dir='.', includes: list[str] | None = None):
         self.remove_unsupported()
 
         w, pyi_w = Writer(), Writer()
 
-        pyi_w.write('from vmath import vec2, vec3, vec2i, vec3i, mat3x3, color32')
+        if has_vmath_converter():
+            pyi_w.write('from vmath import vec2, vec3, vec2i, vec3i, mat3x3, color32')
         pyi_w.write('from typing import overload')
-        pyi_w.write('intptr = int')
+        pyi_w.write('from stdc import intptr')
         pyi_w.write('')
 
         w.write('#include "pocketpy.h"')
-        w.write(f'#include "string.h"')
+        w.write(f'#include <string.h>')
+        w.write(f'#include <stdint.h>')
         
         if includes:
             for include in includes:
@@ -49,8 +60,10 @@ class Library:
         w.write('}')
         w.write('')
 
-        for alias in self.aliases:
-            w.write(f'#define tp_user_{alias.name} tp_user_{alias.type}')
+        for k in self.aliases.keys():
+            node = self.unalias(k)
+            if isinstance(node, str):
+                w.write(f'#define tp_user_{k} tp_user_{node}')
         w.write('')
 
         reg_exprs = [
@@ -73,9 +86,14 @@ class Library:
 
         w.write('/* aliases */')
         pyi_w.write('# aliases')
-        for alias in self.aliases:
-            w.write(f'py_setdict(mod, py_name("{alias.name}"), py_getdict(mod, py_name("{alias.type}")));')
-            pyi_w.write(f'{alias.name} = {alias.type}')
+        for k in self.aliases.keys():
+            node = self.unalias(k)
+            if isinstance(node, str):
+                w.write(f'py_setdict(mod, py_name("{k}"), py_getdict(mod, py_name("{node}")));')
+                pyi_w.write(f'{k} = {node}')
+            elif isinstance(node, c_ast.Enum):
+                w.write(f'py_setdict(mod, py_name("{k}"), py_tpobject(tp_int));')
+                pyi_w.write(f'{k} = int')
 
         w.write('/* functions */')
         for function in self.functions:
@@ -125,11 +143,7 @@ class Library:
                 ) for field in struct['fields']]
             ))
         for alias in data['aliases']:
-            self.aliases.append(Alias(
-                type=alias['type'],
-                name=alias['name'],
-                desc=alias['description']
-            ))
+            self.aliases[alias['name']] = str(alias['type'])
         for enum in data['enums']:
             self.enums.append(Enum(
                 name=enum['name'],
@@ -182,10 +196,7 @@ class Library:
                     ) for value in type.values]
                 ))
         for k, v in header.type_aliases.items():
-            self.aliases.append(Alias(
-                name=k,
-                type=v
-            ))
+            self.aliases[k] = v
 
         for function in header.functions:
             self.functions.append(Function(

+ 25 - 19
ffigen/ffigen/meta/parser.py

@@ -1,3 +1,4 @@
+from typing import Literal
 from .schema import *
 
 class UnsupportedNode(Exception):
@@ -11,7 +12,12 @@ class UnsupportedNode(Exception):
 class Header:
     def __init__(self):
         self.types = [] # type: list
-        self.type_aliases = {} # type: dict[str, str]
+        self.type_aliases = {} # type: dict[str, str | c_ast.Node]
+        self.builtin_aliases = {
+            'size_t', 'bool',
+            'int8_t', 'int16_t', 'int32_t', 'int64_t',
+            'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t',
+        }
         self.functions = [] # type: list[Function]
 
     def remove_types(self, names: set):
@@ -20,17 +26,17 @@ class Header:
     def remove_functions(self, names: set):
         self.functions = [f for f in self.functions if f.name not in names]
 
+    def add_type_alias(self, k: str, v: str | c_ast.Node):
+        if k in self.builtin_aliases:
+            return
+        self.type_aliases[k] = v
+
     def build_enum(self, node: c_ast.Enum):
         enum = Enum(node.name)
         for item in node.values.enumerators:
             enum.values.append(item.name)
         self.types.append(enum)
 
-    def unalias(self, name: str):
-        while name in self.type_aliases:
-            name = self.type_aliases[name]
-        return name
-
     def build_struct(self, node):
         if isinstance(node, c_ast.Struct):
             cls = Struct
@@ -51,14 +57,19 @@ class Header:
         else:
             self.types.append(cls(node.name, None))
 
-    def build_type(self, name, node):
+    def build_type(self, node, alias_name):
         if isinstance(node, c_ast.Enum):
             self.build_enum(node)
+            if alias_name:
+                self.add_type_alias(alias_name, node)
         elif isinstance(node, (c_ast.Struct, c_ast.Union)):
             self.build_struct(node)
+            if alias_name:
+                self.add_type_alias(alias_name, node)
         elif isinstance(node, c_ast.IdentifierType):
-            assert name
-            self.type_aliases[name] = node.names[0]
+            assert alias_name
+            assert node.names[0]
+            self.add_type_alias(alias_name, node.names[0])
         else:
             raise UnsupportedNode(node)
         
@@ -137,23 +148,18 @@ class Header:
             if isinstance(node, c_ast.Typedef):
                 name, node = node.name, node.type
                 if isinstance(node, c_ast.TypeDecl):
-                    self.build_type(name, node.type)
+                    self.build_type(node.type, name)
                 elif isinstance(node, c_ast.PtrDecl):
-                    type_name = self.get_type_name(node)
-                    self.type_aliases[name] = type_name
+                    self.add_type_alias(name, node)
                 else:
-                    # raise UnsupportedNode(node.type)
-                    # print(f"Unsupported typedef: {type(node)}")
-                    continue
+                    raise UnsupportedNode(node.type)
             elif isinstance(node, c_ast.Decl):
                 if isinstance(node.type, c_ast.FuncDecl):
                     self.build_function(node.type)
                 else:
                     try:
-                        self.build_type(None, node.type)
+                        self.build_type(node.type, None)
                     except UnsupportedNode:
                         pass
             else:
-                # raise UnsupportedNode(node.type)
-                # print(f"Unsupported typedef: {type(node)}")
-                continue
+                raise UnsupportedNode(node.type)

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

@@ -2,7 +2,7 @@ from pycparser import c_ast
 
 class Pointer:
     def __init__(self, base: str, level: int):
-        super().__init__(f'{base}' + '*' * level)
+        # super().__init__(f'{base}' + '*' * level)
         self.base = base
         self.level = level
 

+ 7 - 12
ffigen/ffigen/schema.py

@@ -1,34 +1,29 @@
 from dataclasses import dataclass
+from pycparser import c_ast
 
 @dataclass
 class StructField:
     type: str
     name: str
-    desc: str = None
+    desc: str | None = None
 
 @dataclass
 class EnumValue:
     name: str
     value: int | None
-    desc: str = None
+    desc: str | None = None
 
 @dataclass
 class Struct:
     name: str
-    desc: str = None
-    fields: list[StructField] = None
-
-@dataclass
-class Alias:
-    type: str
-    name: str
-    desc: str = None
+    desc: str | None = None
+    fields: list[StructField] | None = None
 
 @dataclass
 class Enum:
     name: str
     values: list[EnumValue]
-    desc: str = None
+    desc: str | None = None
 
 @dataclass
 class FunctionParam:
@@ -40,7 +35,7 @@ class Function:
     name: str
     params: list[FunctionParam]
     ret_type: str
-    desc: str = None
+    desc: str | None = None
 
     def signature(self) -> str:
         return f'{self.ret_type} {self.name}({", ".join([f"{param.type} {param.name}" for param in self.params])})'

+ 7 - 7
ffigen/ffigen/struct.py

@@ -25,7 +25,7 @@ def gen_setter(w: Writer, name: str, cvt: Converter, field: StructField):
 
 def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     name = struct.name
-    converters = [get_converter(field.type) for field in struct.fields]
+    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.indent()
@@ -73,8 +73,8 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     w.dedent()
     w.write('}')
 
-    for field in struct.fields:
-        cvt = get_converter(field.type)
+    for i, field in enumerate(struct.fields):
+        cvt = converters[i]
         gen_getter(w, name, cvt, field)
         if not cvt.is_const():
             gen_setter(w, name, cvt, field)
@@ -88,8 +88,8 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     w.write(f'py_bindmethod(type, "__address__", struct__address__);')
     w.write(f'py_bindmethod(type, "copy", {name}__copy__);')
 
-    for field in struct.fields:
-        cvt = get_converter(field.type)
+    for i, field in enumerate(struct.fields):
+        cvt = converters[i]
         if cvt.is_const():
             setter = 'NULL'
         else:
@@ -105,8 +105,8 @@ def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
     pyi_w.indent()
 
     py_args = []
-    for field in struct.fields:
-        cvt = get_converter(field.type)
+    for i, field in enumerate(struct.fields):
+        cvt = converters[i]
         desc = (field.desc or '') + f' ({field.type})'
         py_args.append(f"{field.name}: {cvt.py_T}")
         pyi_w.write(f"{py_args[-1]} # {desc}")

+ 0 - 2
ffigen/gen_periphery.py

@@ -18,8 +18,6 @@ header.build(ast)
 
 lib = Library.from_header('periphery', header)
 
-set_enum_converters([enum.name for enum in lib.enums])
-
 lib.build(
     includes=['c-periphery/src/gpio.h'],
     glue_dir='3rd/periphery/src',

+ 1 - 1
ffigen/libc_include/stdarg.h

@@ -1 +1 @@
-#define va_list int
+typedef int va_list;

+ 1 - 1
ffigen/libc_include/stdbool.h

@@ -1 +1 @@
-#define bool _Bool
+typedef _Bool bool;

+ 3 - 1
ffigen/libc_include/stddef.h

@@ -1 +1,3 @@
-#define NULL ((void*)0)
+#define NULL ((void*)0)
+
+typedef unsigned size_t;

+ 8 - 10
ffigen/libc_include/stdint.h

@@ -1,11 +1,9 @@
-#define size_t int
+typedef int int8_t;
+typedef int int16_t;
+typedef int int32_t;
+typedef int int64_t;
 
-#define int8_t int
-#define int16_t int
-#define int32_t int
-#define int64_t int
-
-#define uint8_t unsigned
-#define uint16_t unsigned
-#define uint32_t unsigned
-#define uint64_t unsigned
+typedef unsigned uint8_t;
+typedef unsigned uint16_t;
+typedef unsigned uint32_t;
+typedef unsigned uint64_t;

+ 9 - 8
include/typings/stdc.pyi

@@ -46,14 +46,15 @@ class Double(_BuiltinMemory[float]): ...
 class Pointer(_BuiltinMemory[intptr]): ...
 class Bool(_BuiltinMemory[bool]): ...
 
-INT8: _BuiltinMemory[int] = ...
-UINT8: _BuiltinMemory[int] = ...
-INT16: _BuiltinMemory[int] = ...
-UINT16: _BuiltinMemory[int] = ...
-INT32: _BuiltinMemory[int] = ...
-UINT32: _BuiltinMemory[int] = ...
-INT64: _BuiltinMemory[int] = ...
-UINT64: _BuiltinMemory[int] = ...
+Int8: _BuiltinMemory[int]
+UInt8: _BuiltinMemory[int]
+Int16: _BuiltinMemory[int]
+UInt16: _BuiltinMemory[int]
+Int32: _BuiltinMemory[int]
+UInt32: _BuiltinMemory[int]
+Int64: _BuiltinMemory[int]
+UInt64: _BuiltinMemory[int]
+SizeT: _BuiltinMemory[int]
 
 def addressof(obj: Memory) -> intptr: ...
 def sizeof(obj: type[Memory]) -> int: ...

+ 7 - 0
src/modules/stdc.c

@@ -267,6 +267,13 @@ void pk__add_module_stdc() {
             }
         }
     }
+    for(py_Type t = tp_stdc_Char; t <= tp_stdc_ULongLong; t += 2) {
+        py_Ref size_var = py_getdict(py_tpobject(t), py_name("size"));
+        if(py_toint(size_var) == sizeof(size_t)) {
+            py_setdict(mod, py_name("SizeT"), py_tpobject(t + 1));
+            break;
+        }
+    }
 
     pk__bind_stdc_Float(mod);
     pk__bind_stdc_Double(mod);