You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

611 lines
21 KiB

4 years ago
  1. import types
  2. import weakref
  3. from .lock import allocate_lock
  4. from .error import CDefError, VerificationError, VerificationMissing
  5. # type qualifiers
  6. Q_CONST = 0x01
  7. Q_RESTRICT = 0x02
  8. Q_VOLATILE = 0x04
  9. def qualify(quals, replace_with):
  10. if quals & Q_CONST:
  11. replace_with = ' const ' + replace_with.lstrip()
  12. if quals & Q_VOLATILE:
  13. replace_with = ' volatile ' + replace_with.lstrip()
  14. if quals & Q_RESTRICT:
  15. # It seems that __restrict is supported by gcc and msvc.
  16. # If you hit some different compiler, add a #define in
  17. # _cffi_include.h for it (and in its copies, documented there)
  18. replace_with = ' __restrict ' + replace_with.lstrip()
  19. return replace_with
  20. class BaseTypeByIdentity(object):
  21. is_array_type = False
  22. is_raw_function = False
  23. def get_c_name(self, replace_with='', context='a C file', quals=0):
  24. result = self.c_name_with_marker
  25. assert result.count('&') == 1
  26. # some logic duplication with ffi.getctype()... :-(
  27. replace_with = replace_with.strip()
  28. if replace_with:
  29. if replace_with.startswith('*') and '&[' in result:
  30. replace_with = '(%s)' % replace_with
  31. elif not replace_with[0] in '[(':
  32. replace_with = ' ' + replace_with
  33. replace_with = qualify(quals, replace_with)
  34. result = result.replace('&', replace_with)
  35. if '$' in result:
  36. raise VerificationError(
  37. "cannot generate '%s' in %s: unknown type name"
  38. % (self._get_c_name(), context))
  39. return result
  40. def _get_c_name(self):
  41. return self.c_name_with_marker.replace('&', '')
  42. def has_c_name(self):
  43. return '$' not in self._get_c_name()
  44. def is_integer_type(self):
  45. return False
  46. def get_cached_btype(self, ffi, finishlist, can_delay=False):
  47. try:
  48. BType = ffi._cached_btypes[self]
  49. except KeyError:
  50. BType = self.build_backend_type(ffi, finishlist)
  51. BType2 = ffi._cached_btypes.setdefault(self, BType)
  52. assert BType2 is BType
  53. return BType
  54. def __repr__(self):
  55. return '<%s>' % (self._get_c_name(),)
  56. def _get_items(self):
  57. return [(name, getattr(self, name)) for name in self._attrs_]
  58. class BaseType(BaseTypeByIdentity):
  59. def __eq__(self, other):
  60. return (self.__class__ == other.__class__ and
  61. self._get_items() == other._get_items())
  62. def __ne__(self, other):
  63. return not self == other
  64. def __hash__(self):
  65. return hash((self.__class__, tuple(self._get_items())))
  66. class VoidType(BaseType):
  67. _attrs_ = ()
  68. def __init__(self):
  69. self.c_name_with_marker = 'void&'
  70. def build_backend_type(self, ffi, finishlist):
  71. return global_cache(self, ffi, 'new_void_type')
  72. void_type = VoidType()
  73. class BasePrimitiveType(BaseType):
  74. def is_complex_type(self):
  75. return False
  76. class PrimitiveType(BasePrimitiveType):
  77. _attrs_ = ('name',)
  78. ALL_PRIMITIVE_TYPES = {
  79. 'char': 'c',
  80. 'short': 'i',
  81. 'int': 'i',
  82. 'long': 'i',
  83. 'long long': 'i',
  84. 'signed char': 'i',
  85. 'unsigned char': 'i',
  86. 'unsigned short': 'i',
  87. 'unsigned int': 'i',
  88. 'unsigned long': 'i',
  89. 'unsigned long long': 'i',
  90. 'float': 'f',
  91. 'double': 'f',
  92. 'long double': 'f',
  93. 'float _Complex': 'j',
  94. 'double _Complex': 'j',
  95. '_Bool': 'i',
  96. # the following types are not primitive in the C sense
  97. 'wchar_t': 'c',
  98. 'char16_t': 'c',
  99. 'char32_t': 'c',
  100. 'int8_t': 'i',
  101. 'uint8_t': 'i',
  102. 'int16_t': 'i',
  103. 'uint16_t': 'i',
  104. 'int32_t': 'i',
  105. 'uint32_t': 'i',
  106. 'int64_t': 'i',
  107. 'uint64_t': 'i',
  108. 'int_least8_t': 'i',
  109. 'uint_least8_t': 'i',
  110. 'int_least16_t': 'i',
  111. 'uint_least16_t': 'i',
  112. 'int_least32_t': 'i',
  113. 'uint_least32_t': 'i',
  114. 'int_least64_t': 'i',
  115. 'uint_least64_t': 'i',
  116. 'int_fast8_t': 'i',
  117. 'uint_fast8_t': 'i',
  118. 'int_fast16_t': 'i',
  119. 'uint_fast16_t': 'i',
  120. 'int_fast32_t': 'i',
  121. 'uint_fast32_t': 'i',
  122. 'int_fast64_t': 'i',
  123. 'uint_fast64_t': 'i',
  124. 'intptr_t': 'i',
  125. 'uintptr_t': 'i',
  126. 'intmax_t': 'i',
  127. 'uintmax_t': 'i',
  128. 'ptrdiff_t': 'i',
  129. 'size_t': 'i',
  130. 'ssize_t': 'i',
  131. }
  132. def __init__(self, name):
  133. assert name in self.ALL_PRIMITIVE_TYPES
  134. self.name = name
  135. self.c_name_with_marker = name + '&'
  136. def is_char_type(self):
  137. return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
  138. def is_integer_type(self):
  139. return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
  140. def is_float_type(self):
  141. return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
  142. def is_complex_type(self):
  143. return self.ALL_PRIMITIVE_TYPES[self.name] == 'j'
  144. def build_backend_type(self, ffi, finishlist):
  145. return global_cache(self, ffi, 'new_primitive_type', self.name)
  146. class UnknownIntegerType(BasePrimitiveType):
  147. _attrs_ = ('name',)
  148. def __init__(self, name):
  149. self.name = name
  150. self.c_name_with_marker = name + '&'
  151. def is_integer_type(self):
  152. return True
  153. def build_backend_type(self, ffi, finishlist):
  154. raise NotImplementedError("integer type '%s' can only be used after "
  155. "compilation" % self.name)
  156. class UnknownFloatType(BasePrimitiveType):
  157. _attrs_ = ('name', )
  158. def __init__(self, name):
  159. self.name = name
  160. self.c_name_with_marker = name + '&'
  161. def build_backend_type(self, ffi, finishlist):
  162. raise NotImplementedError("float type '%s' can only be used after "
  163. "compilation" % self.name)
  164. class BaseFunctionType(BaseType):
  165. _attrs_ = ('args', 'result', 'ellipsis', 'abi')
  166. def __init__(self, args, result, ellipsis, abi=None):
  167. self.args = args
  168. self.result = result
  169. self.ellipsis = ellipsis
  170. self.abi = abi
  171. #
  172. reprargs = [arg._get_c_name() for arg in self.args]
  173. if self.ellipsis:
  174. reprargs.append('...')
  175. reprargs = reprargs or ['void']
  176. replace_with = self._base_pattern % (', '.join(reprargs),)
  177. if abi is not None:
  178. replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
  179. self.c_name_with_marker = (
  180. self.result.c_name_with_marker.replace('&', replace_with))
  181. class RawFunctionType(BaseFunctionType):
  182. # Corresponds to a C type like 'int(int)', which is the C type of
  183. # a function, but not a pointer-to-function. The backend has no
  184. # notion of such a type; it's used temporarily by parsing.
  185. _base_pattern = '(&)(%s)'
  186. is_raw_function = True
  187. def build_backend_type(self, ffi, finishlist):
  188. raise CDefError("cannot render the type %r: it is a function "
  189. "type, not a pointer-to-function type" % (self,))
  190. def as_function_pointer(self):
  191. return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
  192. class FunctionPtrType(BaseFunctionType):
  193. _base_pattern = '(*&)(%s)'
  194. def build_backend_type(self, ffi, finishlist):
  195. result = self.result.get_cached_btype(ffi, finishlist)
  196. args = []
  197. for tp in self.args:
  198. args.append(tp.get_cached_btype(ffi, finishlist))
  199. abi_args = ()
  200. if self.abi == "__stdcall":
  201. if not self.ellipsis: # __stdcall ignored for variadic funcs
  202. try:
  203. abi_args = (ffi._backend.FFI_STDCALL,)
  204. except AttributeError:
  205. pass
  206. return global_cache(self, ffi, 'new_function_type',
  207. tuple(args), result, self.ellipsis, *abi_args)
  208. def as_raw_function(self):
  209. return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)
  210. class PointerType(BaseType):
  211. _attrs_ = ('totype', 'quals')
  212. def __init__(self, totype, quals=0):
  213. self.totype = totype
  214. self.quals = quals
  215. extra = qualify(quals, " *&")
  216. if totype.is_array_type:
  217. extra = "(%s)" % (extra.lstrip(),)
  218. self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
  219. def build_backend_type(self, ffi, finishlist):
  220. BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
  221. return global_cache(self, ffi, 'new_pointer_type', BItem)
  222. voidp_type = PointerType(void_type)
  223. def ConstPointerType(totype):
  224. return PointerType(totype, Q_CONST)
  225. const_voidp_type = ConstPointerType(void_type)
  226. class NamedPointerType(PointerType):
  227. _attrs_ = ('totype', 'name')
  228. def __init__(self, totype, name, quals=0):
  229. PointerType.__init__(self, totype, quals)
  230. self.name = name
  231. self.c_name_with_marker = name + '&'
  232. class ArrayType(BaseType):
  233. _attrs_ = ('item', 'length')
  234. is_array_type = True
  235. def __init__(self, item, length):
  236. self.item = item
  237. self.length = length
  238. #
  239. if length is None:
  240. brackets = '&[]'
  241. elif length == '...':
  242. brackets = '&[/*...*/]'
  243. else:
  244. brackets = '&[%s]' % length
  245. self.c_name_with_marker = (
  246. self.item.c_name_with_marker.replace('&', brackets))
  247. def resolve_length(self, newlength):
  248. return ArrayType(self.item, newlength)
  249. def build_backend_type(self, ffi, finishlist):
  250. if self.length == '...':
  251. raise CDefError("cannot render the type %r: unknown length" %
  252. (self,))
  253. self.item.get_cached_btype(ffi, finishlist) # force the item BType
  254. BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
  255. return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)
  256. char_array_type = ArrayType(PrimitiveType('char'), None)
  257. class StructOrUnionOrEnum(BaseTypeByIdentity):
  258. _attrs_ = ('name',)
  259. forcename = None
  260. def build_c_name_with_marker(self):
  261. name = self.forcename or '%s %s' % (self.kind, self.name)
  262. self.c_name_with_marker = name + '&'
  263. def force_the_name(self, forcename):
  264. self.forcename = forcename
  265. self.build_c_name_with_marker()
  266. def get_official_name(self):
  267. assert self.c_name_with_marker.endswith('&')
  268. return self.c_name_with_marker[:-1]
  269. class StructOrUnion(StructOrUnionOrEnum):
  270. fixedlayout = None
  271. completed = 0
  272. partial = False
  273. packed = False
  274. def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
  275. self.name = name
  276. self.fldnames = fldnames
  277. self.fldtypes = fldtypes
  278. self.fldbitsize = fldbitsize
  279. self.fldquals = fldquals
  280. self.build_c_name_with_marker()
  281. def anonymous_struct_fields(self):
  282. if self.fldtypes is not None:
  283. for name, type in zip(self.fldnames, self.fldtypes):
  284. if name == '' and isinstance(type, StructOrUnion):
  285. yield type
  286. def enumfields(self, expand_anonymous_struct_union=True):
  287. fldquals = self.fldquals
  288. if fldquals is None:
  289. fldquals = (0,) * len(self.fldnames)
  290. for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
  291. self.fldbitsize, fldquals):
  292. if (name == '' and isinstance(type, StructOrUnion)
  293. and expand_anonymous_struct_union):
  294. # nested anonymous struct/union
  295. for result in type.enumfields():
  296. yield result
  297. else:
  298. yield (name, type, bitsize, quals)
  299. def force_flatten(self):
  300. # force the struct or union to have a declaration that lists
  301. # directly all fields returned by enumfields(), flattening
  302. # nested anonymous structs/unions.
  303. names = []
  304. types = []
  305. bitsizes = []
  306. fldquals = []
  307. for name, type, bitsize, quals in self.enumfields():
  308. names.append(name)
  309. types.append(type)
  310. bitsizes.append(bitsize)
  311. fldquals.append(quals)
  312. self.fldnames = tuple(names)
  313. self.fldtypes = tuple(types)
  314. self.fldbitsize = tuple(bitsizes)
  315. self.fldquals = tuple(fldquals)
  316. def get_cached_btype(self, ffi, finishlist, can_delay=False):
  317. BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
  318. can_delay)
  319. if not can_delay:
  320. self.finish_backend_type(ffi, finishlist)
  321. return BType
  322. def finish_backend_type(self, ffi, finishlist):
  323. if self.completed:
  324. if self.completed != 2:
  325. raise NotImplementedError("recursive structure declaration "
  326. "for '%s'" % (self.name,))
  327. return
  328. BType = ffi._cached_btypes[self]
  329. #
  330. self.completed = 1
  331. #
  332. if self.fldtypes is None:
  333. pass # not completing it: it's an opaque struct
  334. #
  335. elif self.fixedlayout is None:
  336. fldtypes = [tp.get_cached_btype(ffi, finishlist)
  337. for tp in self.fldtypes]
  338. lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
  339. sflags = 0
  340. if self.packed:
  341. sflags = 8 # SF_PACKED
  342. ffi._backend.complete_struct_or_union(BType, lst, self,
  343. -1, -1, sflags)
  344. #
  345. else:
  346. fldtypes = []
  347. fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout
  348. for i in range(len(self.fldnames)):
  349. fsize = fieldsize[i]
  350. ftype = self.fldtypes[i]
  351. #
  352. if isinstance(ftype, ArrayType) and ftype.length == '...':
  353. # fix the length to match the total size
  354. BItemType = ftype.item.get_cached_btype(ffi, finishlist)
  355. nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
  356. if nrest != 0:
  357. self._verification_error(
  358. "field '%s.%s' has a bogus size?" % (
  359. self.name, self.fldnames[i] or '{}'))
  360. ftype = ftype.resolve_length(nlen)
  361. self.fldtypes = (self.fldtypes[:i] + (ftype,) +
  362. self.fldtypes[i+1:])
  363. #
  364. BFieldType = ftype.get_cached_btype(ffi, finishlist)
  365. if isinstance(ftype, ArrayType) and ftype.length is None:
  366. assert fsize == 0
  367. else:
  368. bitemsize = ffi.sizeof(BFieldType)
  369. if bitemsize != fsize:
  370. self._verification_error(
  371. "field '%s.%s' is declared as %d bytes, but is "
  372. "really %d bytes" % (self.name,
  373. self.fldnames[i] or '{}',
  374. bitemsize, fsize))
  375. fldtypes.append(BFieldType)
  376. #
  377. lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs))
  378. ffi._backend.complete_struct_or_union(BType, lst, self,
  379. totalsize, totalalignment)
  380. self.completed = 2
  381. def _verification_error(self, msg):
  382. raise VerificationError(msg)
  383. def check_not_partial(self):
  384. if self.partial and self.fixedlayout is None:
  385. raise VerificationMissing(self._get_c_name())
  386. def build_backend_type(self, ffi, finishlist):
  387. self.check_not_partial()
  388. finishlist.append(self)
  389. #
  390. return global_cache(self, ffi, 'new_%s_type' % self.kind,
  391. self.get_official_name(), key=self)
  392. class StructType(StructOrUnion):
  393. kind = 'struct'
  394. class UnionType(StructOrUnion):
  395. kind = 'union'
  396. class EnumType(StructOrUnionOrEnum):
  397. kind = 'enum'
  398. partial = False
  399. partial_resolved = False
  400. def __init__(self, name, enumerators, enumvalues, baseinttype=None):
  401. self.name = name
  402. self.enumerators = enumerators
  403. self.enumvalues = enumvalues
  404. self.baseinttype = baseinttype
  405. self.build_c_name_with_marker()
  406. def force_the_name(self, forcename):
  407. StructOrUnionOrEnum.force_the_name(self, forcename)
  408. if self.forcename is None:
  409. name = self.get_official_name()
  410. self.forcename = '$' + name.replace(' ', '_')
  411. def check_not_partial(self):
  412. if self.partial and not self.partial_resolved:
  413. raise VerificationMissing(self._get_c_name())
  414. def build_backend_type(self, ffi, finishlist):
  415. self.check_not_partial()
  416. base_btype = self.build_baseinttype(ffi, finishlist)
  417. return global_cache(self, ffi, 'new_enum_type',
  418. self.get_official_name(),
  419. self.enumerators, self.enumvalues,
  420. base_btype, key=self)
  421. def build_baseinttype(self, ffi, finishlist):
  422. if self.baseinttype is not None:
  423. return self.baseinttype.get_cached_btype(ffi, finishlist)
  424. #
  425. if self.enumvalues:
  426. smallest_value = min(self.enumvalues)
  427. largest_value = max(self.enumvalues)
  428. else:
  429. import warnings
  430. try:
  431. # XXX! The goal is to ensure that the warnings.warn()
  432. # will not suppress the warning. We want to get it
  433. # several times if we reach this point several times.
  434. __warningregistry__.clear()
  435. except NameError:
  436. pass
  437. warnings.warn("%r has no values explicitly defined; "
  438. "guessing that it is equivalent to 'unsigned int'"
  439. % self._get_c_name())
  440. smallest_value = largest_value = 0
  441. if smallest_value < 0: # needs a signed type
  442. sign = 1
  443. candidate1 = PrimitiveType("int")
  444. candidate2 = PrimitiveType("long")
  445. else:
  446. sign = 0
  447. candidate1 = PrimitiveType("unsigned int")
  448. candidate2 = PrimitiveType("unsigned long")
  449. btype1 = candidate1.get_cached_btype(ffi, finishlist)
  450. btype2 = candidate2.get_cached_btype(ffi, finishlist)
  451. size1 = ffi.sizeof(btype1)
  452. size2 = ffi.sizeof(btype2)
  453. if (smallest_value >= ((-1) << (8*size1-1)) and
  454. largest_value < (1 << (8*size1-sign))):
  455. return btype1
  456. if (smallest_value >= ((-1) << (8*size2-1)) and
  457. largest_value < (1 << (8*size2-sign))):
  458. return btype2
  459. raise CDefError("%s values don't all fit into either 'long' "
  460. "or 'unsigned long'" % self._get_c_name())
  461. def unknown_type(name, structname=None):
  462. if structname is None:
  463. structname = '$%s' % name
  464. tp = StructType(structname, None, None, None)
  465. tp.force_the_name(name)
  466. tp.origin = "unknown_type"
  467. return tp
  468. def unknown_ptr_type(name, structname=None):
  469. if structname is None:
  470. structname = '$$%s' % name
  471. tp = StructType(structname, None, None, None)
  472. return NamedPointerType(tp, name)
  473. global_lock = allocate_lock()
  474. _typecache_cffi_backend = weakref.WeakValueDictionary()
  475. def get_typecache(backend):
  476. # returns _typecache_cffi_backend if backend is the _cffi_backend
  477. # module, or type(backend).__typecache if backend is an instance of
  478. # CTypesBackend (or some FakeBackend class during tests)
  479. if isinstance(backend, types.ModuleType):
  480. return _typecache_cffi_backend
  481. with global_lock:
  482. if not hasattr(type(backend), '__typecache'):
  483. type(backend).__typecache = weakref.WeakValueDictionary()
  484. return type(backend).__typecache
  485. def global_cache(srctype, ffi, funcname, *args, **kwds):
  486. key = kwds.pop('key', (funcname, args))
  487. assert not kwds
  488. try:
  489. return ffi._typecache[key]
  490. except KeyError:
  491. pass
  492. try:
  493. res = getattr(ffi._backend, funcname)(*args)
  494. except NotImplementedError as e:
  495. raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e))
  496. # note that setdefault() on WeakValueDictionary is not atomic
  497. # and contains a rare bug (http://bugs.python.org/issue19542);
  498. # we have to use a lock and do it ourselves
  499. cache = ffi._typecache
  500. with global_lock:
  501. res1 = cache.get(key)
  502. if res1 is None:
  503. cache[key] = res
  504. return res
  505. else:
  506. return res1
  507. def pointer_cache(ffi, BType):
  508. return global_cache('?', ffi, 'new_pointer_type', BType)
  509. def attach_exception_info(e, name):
  510. if e.args and type(e.args[0]) is str:
  511. e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:]