converters.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from .writer import Writer
  2. from .types import C_INT_TYPES, C_FLOAT_TYPES, C_BOOL_TYPES, C_STRING_TYPES, LINALG_TYPES
  3. class Converter:
  4. def __init__(self, T: str):
  5. self.T = T
  6. def c2py(self, w: Writer, out: str, expr: str):
  7. raise NotImplementedError
  8. def py2c(self, w: Writer, out: str, expr: str):
  9. raise NotImplementedError
  10. @property
  11. def py_T(self) -> str:
  12. raise NotImplementedError
  13. def is_const(self):
  14. return self.T.startswith('const ') or '[' in self.T
  15. class _SimpleConverter(Converter):
  16. def c2py(self, w: Writer, out: str, expr: str):
  17. w.write(f'py_new{self.py_T}({out}, {expr});')
  18. def py2c(self, w: Writer, out: str, expr: str):
  19. w.write(f'if(!py_check{self.py_T}({expr})) return false;')
  20. w.write(f'{out} = py_to{self.py_T}({expr});')
  21. class IntConverter(_SimpleConverter):
  22. @property
  23. def py_T(self) -> str:
  24. return 'int'
  25. class BoolConverter(_SimpleConverter):
  26. @property
  27. def py_T(self) -> str:
  28. return 'bool'
  29. class StringConverter(_SimpleConverter):
  30. @property
  31. def py_T(self) -> str:
  32. return 'str'
  33. class FloatConverter(Converter):
  34. def c2py(self, w: Writer, out: str, expr: str):
  35. w.write(f'py_newfloat({out}, {expr});')
  36. def py2c(self, w: Writer, out: str, expr: str):
  37. if self.T == 'float':
  38. w.write(f'if(!py_castfloat32({expr}, &{out})) return false;')
  39. else:
  40. w.write(f'if(!py_castfloat({expr}, &{out})) return false;')
  41. @property
  42. def py_T(self) -> str:
  43. return 'float'
  44. class PointerConverter(Converter):
  45. def c2py(self, w: Writer, out: str, expr: str):
  46. w.write(f'py_newint({out}, (py_i64){expr});')
  47. def py2c(self, w: Writer, out: str, expr: str):
  48. w.write(f'if(!py_checkint({expr})) return false;')
  49. w.write(f'{out} = ({self.T})py_toint({expr});')
  50. @property
  51. def py_T(self) -> str:
  52. return 'intptr'
  53. class StructConverter(Converter):
  54. def __init__(self, T: str, type_index: str | None):
  55. super().__init__(T)
  56. if type_index is None:
  57. type_index = f'tp_user_{T}'
  58. self.type_index = type_index
  59. def c2py(self, w: Writer, out: str, expr: str):
  60. w.write('do {')
  61. w.indent()
  62. w.write(f'{self.T}* ud = py_newobject({out}, {self.type_index}, 0, sizeof({self.T}));')
  63. w.write(f'*ud = {expr};')
  64. w.dedent()
  65. w.write('} while(0);')
  66. def py2c(self, w: Writer, out: str, expr: str):
  67. w.write('do {')
  68. w.indent()
  69. w.write(f'if(!py_checktype({expr}, {self.type_index})) return false;')
  70. w.write(f'{out} = *({self.T}*)py_touserdata({expr});')
  71. w.dedent()
  72. w.write('} while(0);')
  73. @property
  74. def py_T(self) -> str:
  75. return self.T
  76. class EnumConverter(Converter):
  77. def __init__(self, T: str):
  78. super().__init__(T)
  79. def c2py(self, w: Writer, out: str, expr: str):
  80. w.write(f'py_newint({out}, (py_i64){expr});')
  81. def py2c(self, w: Writer, out: str, expr: str):
  82. w.write(f'if(!py_checkint({expr})) return false;')
  83. w.write(f'{out} = ({self.T})py_toint({expr});')
  84. @property
  85. def py_T(self) -> str:
  86. return 'int'
  87. class VoidConverter(Converter):
  88. def c2py(self, w: Writer, out: str, expr: str):
  89. w.write(f'py_newnone({out});')
  90. def py2c(self, w: Writer, out: str, expr: str):
  91. # raise NotImplementedError
  92. w.write(f'? // VoidConverter.py2c is not implemented')
  93. @property
  94. def py_T(self) -> str:
  95. return 'None'
  96. class BuiltinVectorConverter(Converter):
  97. def __init__(self, T: str, py_builtin_T: str):
  98. super().__init__(T)
  99. self.py_builtin_T = py_builtin_T
  100. def c2py(self, w: Writer, out: str, expr: str):
  101. w.write(f'py_new{self.py_builtin_T}({out}, *(c11_{self.py_T}*)(&{expr}));')
  102. def py2c(self, w: Writer, out: str, expr: str):
  103. w.write('do {')
  104. w.indent()
  105. w.write(f'if(!py_checktype({expr}, tp_{self.py_T})) return false;')
  106. w.write(f'c11_{self.py_T} tmp = py_to{self.py_builtin_T}({expr});')
  107. # w.write(f'memcpy(&{out}, &tmp, sizeof(c11_{self.py_T}));')
  108. w.write(f'{out} = *({self.T}*)(&tmp);')
  109. w.dedent()
  110. w.write('} while(0);')
  111. @property
  112. def py_T(self) -> str:
  113. return self.py_builtin_T
  114. _CONVERTERS: dict[str, Converter] = {}
  115. for t in C_INT_TYPES:
  116. _CONVERTERS[t] = IntConverter(t)
  117. for t in C_FLOAT_TYPES:
  118. _CONVERTERS[t] = FloatConverter(t)
  119. for t in C_BOOL_TYPES:
  120. _CONVERTERS[t] = BoolConverter(t)
  121. for t in C_STRING_TYPES:
  122. _CONVERTERS[t] = StringConverter(t)
  123. for t in LINALG_TYPES:
  124. _CONVERTERS[t] = BuiltinVectorConverter(f'c11_{t}', t)
  125. _CONVERTERS['void'] = VoidConverter('void')
  126. _CONVERTERS['c11_array2d'] = StructConverter('c11_array2d', 'tp_array2d')
  127. def set_linalg_converter(T: str, py_T: str):
  128. assert py_T in LINALG_TYPES
  129. _CONVERTERS[T] = BuiltinVectorConverter(T, py_T)
  130. def set_enum_converters(enums: list[str]):
  131. for T in enums:
  132. _CONVERTERS[T] = EnumConverter(T)
  133. def get_converter(T: str) -> Converter:
  134. if T in _CONVERTERS:
  135. return _CONVERTERS[T]
  136. if T.endswith('*'):
  137. return PointerConverter(T)
  138. if '[' in T:
  139. return PointerConverter(T)
  140. cvt = _CONVERTERS.get(T)
  141. if cvt is None:
  142. return StructConverter(T, None)