Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

recompiler.py 63KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. import os, sys, io
  2. from . import ffiplatform, model
  3. from .error import VerificationError
  4. from .cffi_opcode import *
  5. VERSION_BASE = 0x2601
  6. VERSION_EMBEDDED = 0x2701
  7. VERSION_CHAR16CHAR32 = 0x2801
  8. USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or
  9. sys.version_info >= (3, 5))
  10. class GlobalExpr:
  11. def __init__(self, name, address, type_op, size=0, check_value=0):
  12. self.name = name
  13. self.address = address
  14. self.type_op = type_op
  15. self.size = size
  16. self.check_value = check_value
  17. def as_c_expr(self):
  18. return ' { "%s", (void *)%s, %s, (void *)%s },' % (
  19. self.name, self.address, self.type_op.as_c_expr(), self.size)
  20. def as_python_expr(self):
  21. return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
  22. self.check_value)
  23. class FieldExpr:
  24. def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
  25. self.name = name
  26. self.field_offset = field_offset
  27. self.field_size = field_size
  28. self.fbitsize = fbitsize
  29. self.field_type_op = field_type_op
  30. def as_c_expr(self):
  31. spaces = " " * len(self.name)
  32. return (' { "%s", %s,\n' % (self.name, self.field_offset) +
  33. ' %s %s,\n' % (spaces, self.field_size) +
  34. ' %s %s },' % (spaces, self.field_type_op.as_c_expr()))
  35. def as_python_expr(self):
  36. raise NotImplementedError
  37. def as_field_python_expr(self):
  38. if self.field_type_op.op == OP_NOOP:
  39. size_expr = ''
  40. elif self.field_type_op.op == OP_BITFIELD:
  41. size_expr = format_four_bytes(self.fbitsize)
  42. else:
  43. raise NotImplementedError
  44. return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
  45. size_expr,
  46. self.name)
  47. class StructUnionExpr:
  48. def __init__(self, name, type_index, flags, size, alignment, comment,
  49. first_field_index, c_fields):
  50. self.name = name
  51. self.type_index = type_index
  52. self.flags = flags
  53. self.size = size
  54. self.alignment = alignment
  55. self.comment = comment
  56. self.first_field_index = first_field_index
  57. self.c_fields = c_fields
  58. def as_c_expr(self):
  59. return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
  60. + '\n %s, %s, ' % (self.size, self.alignment)
  61. + '%d, %d ' % (self.first_field_index, len(self.c_fields))
  62. + ('/* %s */ ' % self.comment if self.comment else '')
  63. + '},')
  64. def as_python_expr(self):
  65. flags = eval(self.flags, G_FLAGS)
  66. fields_expr = [c_field.as_field_python_expr()
  67. for c_field in self.c_fields]
  68. return "(b'%s%s%s',%s)" % (
  69. format_four_bytes(self.type_index),
  70. format_four_bytes(flags),
  71. self.name,
  72. ','.join(fields_expr))
  73. class EnumExpr:
  74. def __init__(self, name, type_index, size, signed, allenums):
  75. self.name = name
  76. self.type_index = type_index
  77. self.size = size
  78. self.signed = signed
  79. self.allenums = allenums
  80. def as_c_expr(self):
  81. return (' { "%s", %d, _cffi_prim_int(%s, %s),\n'
  82. ' "%s" },' % (self.name, self.type_index,
  83. self.size, self.signed, self.allenums))
  84. def as_python_expr(self):
  85. prim_index = {
  86. (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8,
  87. (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16,
  88. (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32,
  89. (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64,
  90. }[self.size, self.signed]
  91. return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index),
  92. format_four_bytes(prim_index),
  93. self.name, self.allenums)
  94. class TypenameExpr:
  95. def __init__(self, name, type_index):
  96. self.name = name
  97. self.type_index = type_index
  98. def as_c_expr(self):
  99. return ' { "%s", %d },' % (self.name, self.type_index)
  100. def as_python_expr(self):
  101. return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
  102. # ____________________________________________________________
  103. class Recompiler:
  104. _num_externpy = 0
  105. def __init__(self, ffi, module_name, target_is_python=False):
  106. self.ffi = ffi
  107. self.module_name = module_name
  108. self.target_is_python = target_is_python
  109. self._version = VERSION_BASE
  110. def needs_version(self, ver):
  111. self._version = max(self._version, ver)
  112. def collect_type_table(self):
  113. self._typesdict = {}
  114. self._generate("collecttype")
  115. #
  116. all_decls = sorted(self._typesdict, key=str)
  117. #
  118. # prepare all FUNCTION bytecode sequences first
  119. self.cffi_types = []
  120. for tp in all_decls:
  121. if tp.is_raw_function:
  122. assert self._typesdict[tp] is None
  123. self._typesdict[tp] = len(self.cffi_types)
  124. self.cffi_types.append(tp) # placeholder
  125. for tp1 in tp.args:
  126. assert isinstance(tp1, (model.VoidType,
  127. model.BasePrimitiveType,
  128. model.PointerType,
  129. model.StructOrUnionOrEnum,
  130. model.FunctionPtrType))
  131. if self._typesdict[tp1] is None:
  132. self._typesdict[tp1] = len(self.cffi_types)
  133. self.cffi_types.append(tp1) # placeholder
  134. self.cffi_types.append('END') # placeholder
  135. #
  136. # prepare all OTHER bytecode sequences
  137. for tp in all_decls:
  138. if not tp.is_raw_function and self._typesdict[tp] is None:
  139. self._typesdict[tp] = len(self.cffi_types)
  140. self.cffi_types.append(tp) # placeholder
  141. if tp.is_array_type and tp.length is not None:
  142. self.cffi_types.append('LEN') # placeholder
  143. assert None not in self._typesdict.values()
  144. #
  145. # collect all structs and unions and enums
  146. self._struct_unions = {}
  147. self._enums = {}
  148. for tp in all_decls:
  149. if isinstance(tp, model.StructOrUnion):
  150. self._struct_unions[tp] = None
  151. elif isinstance(tp, model.EnumType):
  152. self._enums[tp] = None
  153. for i, tp in enumerate(sorted(self._struct_unions,
  154. key=lambda tp: tp.name)):
  155. self._struct_unions[tp] = i
  156. for i, tp in enumerate(sorted(self._enums,
  157. key=lambda tp: tp.name)):
  158. self._enums[tp] = i
  159. #
  160. # emit all bytecode sequences now
  161. for tp in all_decls:
  162. method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__)
  163. method(tp, self._typesdict[tp])
  164. #
  165. # consistency check
  166. for op in self.cffi_types:
  167. assert isinstance(op, CffiOp)
  168. self.cffi_types = tuple(self.cffi_types) # don't change any more
  169. def _enum_fields(self, tp):
  170. # When producing C, expand all anonymous struct/union fields.
  171. # That's necessary to have C code checking the offsets of the
  172. # individual fields contained in them. When producing Python,
  173. # don't do it and instead write it like it is, with the
  174. # corresponding fields having an empty name. Empty names are
  175. # recognized at runtime when we import the generated Python
  176. # file.
  177. expand_anonymous_struct_union = not self.target_is_python
  178. return tp.enumfields(expand_anonymous_struct_union)
  179. def _do_collect_type(self, tp):
  180. if not isinstance(tp, model.BaseTypeByIdentity):
  181. if isinstance(tp, tuple):
  182. for x in tp:
  183. self._do_collect_type(x)
  184. return
  185. if tp not in self._typesdict:
  186. self._typesdict[tp] = None
  187. if isinstance(tp, model.FunctionPtrType):
  188. self._do_collect_type(tp.as_raw_function())
  189. elif isinstance(tp, model.StructOrUnion):
  190. if tp.fldtypes is not None and (
  191. tp not in self.ffi._parser._included_declarations):
  192. for name1, tp1, _, _ in self._enum_fields(tp):
  193. self._do_collect_type(self._field_type(tp, name1, tp1))
  194. else:
  195. for _, x in tp._get_items():
  196. self._do_collect_type(x)
  197. def _generate(self, step_name):
  198. lst = self.ffi._parser._declarations.items()
  199. for name, (tp, quals) in sorted(lst):
  200. kind, realname = name.split(' ', 1)
  201. try:
  202. method = getattr(self, '_generate_cpy_%s_%s' % (kind,
  203. step_name))
  204. except AttributeError:
  205. raise VerificationError(
  206. "not implemented in recompile(): %r" % name)
  207. try:
  208. self._current_quals = quals
  209. method(tp, realname)
  210. except Exception as e:
  211. model.attach_exception_info(e, name)
  212. raise
  213. # ----------
  214. ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
  215. def collect_step_tables(self):
  216. # collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
  217. self._lsts = {}
  218. for step_name in self.ALL_STEPS:
  219. self._lsts[step_name] = []
  220. self._seen_struct_unions = set()
  221. self._generate("ctx")
  222. self._add_missing_struct_unions()
  223. #
  224. for step_name in self.ALL_STEPS:
  225. lst = self._lsts[step_name]
  226. if step_name != "field":
  227. lst.sort(key=lambda entry: entry.name)
  228. self._lsts[step_name] = tuple(lst) # don't change any more
  229. #
  230. # check for a possible internal inconsistency: _cffi_struct_unions
  231. # should have been generated with exactly self._struct_unions
  232. lst = self._lsts["struct_union"]
  233. for tp, i in self._struct_unions.items():
  234. assert i < len(lst)
  235. assert lst[i].name == tp.name
  236. assert len(lst) == len(self._struct_unions)
  237. # same with enums
  238. lst = self._lsts["enum"]
  239. for tp, i in self._enums.items():
  240. assert i < len(lst)
  241. assert lst[i].name == tp.name
  242. assert len(lst) == len(self._enums)
  243. # ----------
  244. def _prnt(self, what=''):
  245. self._f.write(what + '\n')
  246. def write_source_to_f(self, f, preamble):
  247. if self.target_is_python:
  248. assert preamble is None
  249. self.write_py_source_to_f(f)
  250. else:
  251. assert preamble is not None
  252. self.write_c_source_to_f(f, preamble)
  253. def _rel_readlines(self, filename):
  254. g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
  255. lines = g.readlines()
  256. g.close()
  257. return lines
  258. def write_c_source_to_f(self, f, preamble):
  259. self._f = f
  260. prnt = self._prnt
  261. if self.ffi._embedding is not None:
  262. prnt('#define _CFFI_USE_EMBEDDING')
  263. if not USE_LIMITED_API:
  264. prnt('#define _CFFI_NO_LIMITED_API')
  265. #
  266. # first the '#include' (actually done by inlining the file's content)
  267. lines = self._rel_readlines('_cffi_include.h')
  268. i = lines.index('#include "parse_c_type.h"\n')
  269. lines[i:i+1] = self._rel_readlines('parse_c_type.h')
  270. prnt(''.join(lines))
  271. #
  272. # if we have ffi._embedding != None, we give it here as a macro
  273. # and include an extra file
  274. base_module_name = self.module_name.split('.')[-1]
  275. if self.ffi._embedding is not None:
  276. prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,))
  277. prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {')
  278. self._print_string_literal_in_array(self.ffi._embedding)
  279. prnt('0 };')
  280. prnt('#ifdef PYPY_VERSION')
  281. prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % (
  282. base_module_name,))
  283. prnt('#elif PY_MAJOR_VERSION >= 3')
  284. prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % (
  285. base_module_name,))
  286. prnt('#else')
  287. prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % (
  288. base_module_name,))
  289. prnt('#endif')
  290. lines = self._rel_readlines('_embedding.h')
  291. i = lines.index('#include "_cffi_errors.h"\n')
  292. lines[i:i+1] = self._rel_readlines('_cffi_errors.h')
  293. prnt(''.join(lines))
  294. self.needs_version(VERSION_EMBEDDED)
  295. #
  296. # then paste the C source given by the user, verbatim.
  297. prnt('/************************************************************/')
  298. prnt()
  299. prnt(preamble)
  300. prnt()
  301. prnt('/************************************************************/')
  302. prnt()
  303. #
  304. # the declaration of '_cffi_types'
  305. prnt('static void *_cffi_types[] = {')
  306. typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
  307. for i, op in enumerate(self.cffi_types):
  308. comment = ''
  309. if i in typeindex2type:
  310. comment = ' // ' + typeindex2type[i]._get_c_name()
  311. prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment))
  312. if not self.cffi_types:
  313. prnt(' 0')
  314. prnt('};')
  315. prnt()
  316. #
  317. # call generate_cpy_xxx_decl(), for every xxx found from
  318. # ffi._parser._declarations. This generates all the functions.
  319. self._seen_constants = set()
  320. self._generate("decl")
  321. #
  322. # the declaration of '_cffi_globals' and '_cffi_typenames'
  323. nums = {}
  324. for step_name in self.ALL_STEPS:
  325. lst = self._lsts[step_name]
  326. nums[step_name] = len(lst)
  327. if nums[step_name] > 0:
  328. prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
  329. step_name, step_name))
  330. for entry in lst:
  331. prnt(entry.as_c_expr())
  332. prnt('};')
  333. prnt()
  334. #
  335. # the declaration of '_cffi_includes'
  336. if self.ffi._included_ffis:
  337. prnt('static const char * const _cffi_includes[] = {')
  338. for ffi_to_include in self.ffi._included_ffis:
  339. try:
  340. included_module_name, included_source = (
  341. ffi_to_include._assigned_source[:2])
  342. except AttributeError:
  343. raise VerificationError(
  344. "ffi object %r includes %r, but the latter has not "
  345. "been prepared with set_source()" % (
  346. self.ffi, ffi_to_include,))
  347. if included_source is None:
  348. raise VerificationError(
  349. "not implemented yet: ffi.include() of a Python-based "
  350. "ffi inside a C-based ffi")
  351. prnt(' "%s",' % (included_module_name,))
  352. prnt(' NULL')
  353. prnt('};')
  354. prnt()
  355. #
  356. # the declaration of '_cffi_type_context'
  357. prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
  358. prnt(' _cffi_types,')
  359. for step_name in self.ALL_STEPS:
  360. if nums[step_name] > 0:
  361. prnt(' _cffi_%ss,' % step_name)
  362. else:
  363. prnt(' NULL, /* no %ss */' % step_name)
  364. for step_name in self.ALL_STEPS:
  365. if step_name != "field":
  366. prnt(' %d, /* num_%ss */' % (nums[step_name], step_name))
  367. if self.ffi._included_ffis:
  368. prnt(' _cffi_includes,')
  369. else:
  370. prnt(' NULL, /* no includes */')
  371. prnt(' %d, /* num_types */' % (len(self.cffi_types),))
  372. flags = 0
  373. if self._num_externpy > 0 or self.ffi._embedding is not None:
  374. flags |= 1 # set to mean that we use extern "Python"
  375. prnt(' %d, /* flags */' % flags)
  376. prnt('};')
  377. prnt()
  378. #
  379. # the init function
  380. prnt('#ifdef __GNUC__')
  381. prnt('# pragma GCC visibility push(default) /* for -fvisibility= */')
  382. prnt('#endif')
  383. prnt()
  384. prnt('#ifdef PYPY_VERSION')
  385. prnt('PyMODINIT_FUNC')
  386. prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,))
  387. prnt('{')
  388. if flags & 1:
  389. prnt(' if (((intptr_t)p[0]) >= 0x0A03) {')
  390. prnt(' _cffi_call_python_org = '
  391. '(void(*)(struct _cffi_externpy_s *, char *))p[1];')
  392. prnt(' }')
  393. prnt(' p[0] = (const void *)0x%x;' % self._version)
  394. prnt(' p[1] = &_cffi_type_context;')
  395. prnt('#if PY_MAJOR_VERSION >= 3')
  396. prnt(' return NULL;')
  397. prnt('#endif')
  398. prnt('}')
  399. # on Windows, distutils insists on putting init_cffi_xyz in
  400. # 'export_symbols', so instead of fighting it, just give up and
  401. # give it one
  402. prnt('# ifdef _MSC_VER')
  403. prnt(' PyMODINIT_FUNC')
  404. prnt('# if PY_MAJOR_VERSION >= 3')
  405. prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,))
  406. prnt('# else')
  407. prnt(' init%s(void) { }' % (base_module_name,))
  408. prnt('# endif')
  409. prnt('# endif')
  410. prnt('#elif PY_MAJOR_VERSION >= 3')
  411. prnt('PyMODINIT_FUNC')
  412. prnt('PyInit_%s(void)' % (base_module_name,))
  413. prnt('{')
  414. prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
  415. self.module_name, self._version))
  416. prnt('}')
  417. prnt('#else')
  418. prnt('PyMODINIT_FUNC')
  419. prnt('init%s(void)' % (base_module_name,))
  420. prnt('{')
  421. prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
  422. self.module_name, self._version))
  423. prnt('}')
  424. prnt('#endif')
  425. prnt()
  426. prnt('#ifdef __GNUC__')
  427. prnt('# pragma GCC visibility pop')
  428. prnt('#endif')
  429. self._version = None
  430. def _to_py(self, x):
  431. if isinstance(x, str):
  432. return "b'%s'" % (x,)
  433. if isinstance(x, (list, tuple)):
  434. rep = [self._to_py(item) for item in x]
  435. if len(rep) == 1:
  436. rep.append('')
  437. return "(%s)" % (','.join(rep),)
  438. return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp.
  439. def write_py_source_to_f(self, f):
  440. self._f = f
  441. prnt = self._prnt
  442. #
  443. # header
  444. prnt("# auto-generated file")
  445. prnt("import _cffi_backend")
  446. #
  447. # the 'import' of the included ffis
  448. num_includes = len(self.ffi._included_ffis or ())
  449. for i in range(num_includes):
  450. ffi_to_include = self.ffi._included_ffis[i]
  451. try:
  452. included_module_name, included_source = (
  453. ffi_to_include._assigned_source[:2])
  454. except AttributeError:
  455. raise VerificationError(
  456. "ffi object %r includes %r, but the latter has not "
  457. "been prepared with set_source()" % (
  458. self.ffi, ffi_to_include,))
  459. if included_source is not None:
  460. raise VerificationError(
  461. "not implemented yet: ffi.include() of a C-based "
  462. "ffi inside a Python-based ffi")
  463. prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
  464. prnt()
  465. prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
  466. prnt(" _version = 0x%x," % (self._version,))
  467. self._version = None
  468. #
  469. # the '_types' keyword argument
  470. self.cffi_types = tuple(self.cffi_types) # don't change any more
  471. types_lst = [op.as_python_bytes() for op in self.cffi_types]
  472. prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
  473. typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
  474. #
  475. # the keyword arguments from ALL_STEPS
  476. for step_name in self.ALL_STEPS:
  477. lst = self._lsts[step_name]
  478. if len(lst) > 0 and step_name != "field":
  479. prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
  480. #
  481. # the '_includes' keyword argument
  482. if num_includes > 0:
  483. prnt(' _includes = (%s,),' % (
  484. ', '.join(['_ffi%d' % i for i in range(num_includes)]),))
  485. #
  486. # the footer
  487. prnt(')')
  488. # ----------
  489. def _gettypenum(self, type):
  490. # a KeyError here is a bug. please report it! :-)
  491. return self._typesdict[type]
  492. def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
  493. extraarg = ''
  494. if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type():
  495. if tp.is_integer_type() and tp.name != '_Bool':
  496. converter = '_cffi_to_c_int'
  497. extraarg = ', %s' % tp.name
  498. elif isinstance(tp, model.UnknownFloatType):
  499. # don't check with is_float_type(): it may be a 'long
  500. # double' here, and _cffi_to_c_double would loose precision
  501. converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
  502. else:
  503. cname = tp.get_c_name('')
  504. converter = '(%s)_cffi_to_c_%s' % (cname,
  505. tp.name.replace(' ', '_'))
  506. if cname in ('char16_t', 'char32_t'):
  507. self.needs_version(VERSION_CHAR16CHAR32)
  508. errvalue = '-1'
  509. #
  510. elif isinstance(tp, model.PointerType):
  511. self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
  512. tovar, errcode)
  513. return
  514. #
  515. elif (isinstance(tp, model.StructOrUnionOrEnum) or
  516. isinstance(tp, model.BasePrimitiveType)):
  517. # a struct (not a struct pointer) as a function argument;
  518. # or, a complex (the same code works)
  519. self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
  520. % (tovar, self._gettypenum(tp), fromvar))
  521. self._prnt(' %s;' % errcode)
  522. return
  523. #
  524. elif isinstance(tp, model.FunctionPtrType):
  525. converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
  526. extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
  527. errvalue = 'NULL'
  528. #
  529. else:
  530. raise NotImplementedError(tp)
  531. #
  532. self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
  533. self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
  534. tovar, tp.get_c_name(''), errvalue))
  535. self._prnt(' %s;' % errcode)
  536. def _extra_local_variables(self, tp, localvars, freelines):
  537. if isinstance(tp, model.PointerType):
  538. localvars.add('Py_ssize_t datasize')
  539. localvars.add('struct _cffi_freeme_s *large_args_free = NULL')
  540. freelines.add('if (large_args_free != NULL)'
  541. ' _cffi_free_array_arguments(large_args_free);')
  542. def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
  543. self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
  544. self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
  545. self._gettypenum(tp), fromvar, tovar))
  546. self._prnt(' if (datasize != 0) {')
  547. self._prnt(' %s = ((size_t)datasize) <= 640 ? '
  548. '(%s)alloca((size_t)datasize) : NULL;' % (
  549. tovar, tp.get_c_name('')))
  550. self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, '
  551. '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar))
  552. self._prnt(' datasize, &large_args_free) < 0)')
  553. self._prnt(' %s;' % errcode)
  554. self._prnt(' }')
  555. def _convert_expr_from_c(self, tp, var, context):
  556. if isinstance(tp, model.BasePrimitiveType):
  557. if tp.is_integer_type() and tp.name != '_Bool':
  558. return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
  559. elif isinstance(tp, model.UnknownFloatType):
  560. return '_cffi_from_c_double(%s)' % (var,)
  561. elif tp.name != 'long double' and not tp.is_complex_type():
  562. cname = tp.name.replace(' ', '_')
  563. if cname in ('char16_t', 'char32_t'):
  564. self.needs_version(VERSION_CHAR16CHAR32)
  565. return '_cffi_from_c_%s(%s)' % (cname, var)
  566. else:
  567. return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
  568. var, self._gettypenum(tp))
  569. elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
  570. return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
  571. var, self._gettypenum(tp))
  572. elif isinstance(tp, model.ArrayType):
  573. return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
  574. var, self._gettypenum(model.PointerType(tp.item)))
  575. elif isinstance(tp, model.StructOrUnion):
  576. if tp.fldnames is None:
  577. raise TypeError("'%s' is used as %s, but is opaque" % (
  578. tp._get_c_name(), context))
  579. return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
  580. var, self._gettypenum(tp))
  581. elif isinstance(tp, model.EnumType):
  582. return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
  583. var, self._gettypenum(tp))
  584. else:
  585. raise NotImplementedError(tp)
  586. # ----------
  587. # typedefs
  588. def _typedef_type(self, tp, name):
  589. return self._global_type(tp, "(*(%s *)0)" % (name,))
  590. def _generate_cpy_typedef_collecttype(self, tp, name):
  591. self._do_collect_type(self._typedef_type(tp, name))
  592. def _generate_cpy_typedef_decl(self, tp, name):
  593. pass
  594. def _typedef_ctx(self, tp, name):
  595. type_index = self._typesdict[tp]
  596. self._lsts["typename"].append(TypenameExpr(name, type_index))
  597. def _generate_cpy_typedef_ctx(self, tp, name):
  598. tp = self._typedef_type(tp, name)
  599. self._typedef_ctx(tp, name)
  600. if getattr(tp, "origin", None) == "unknown_type":
  601. self._struct_ctx(tp, tp.name, approxname=None)
  602. elif isinstance(tp, model.NamedPointerType):
  603. self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name,
  604. named_ptr=tp)
  605. # ----------
  606. # function declarations
  607. def _generate_cpy_function_collecttype(self, tp, name):
  608. self._do_collect_type(tp.as_raw_function())
  609. if tp.ellipsis and not self.target_is_python:
  610. self._do_collect_type(tp)
  611. def _generate_cpy_function_decl(self, tp, name):
  612. assert not self.target_is_python
  613. assert isinstance(tp, model.FunctionPtrType)
  614. if tp.ellipsis:
  615. # cannot support vararg functions better than this: check for its
  616. # exact type (including the fixed arguments), and build it as a
  617. # constant function pointer (no CPython wrapper)
  618. self._generate_cpy_constant_decl(tp, name)
  619. return
  620. prnt = self._prnt
  621. numargs = len(tp.args)
  622. if numargs == 0:
  623. argname = 'noarg'
  624. elif numargs == 1:
  625. argname = 'arg0'
  626. else:
  627. argname = 'args'
  628. #
  629. # ------------------------------
  630. # the 'd' version of the function, only for addressof(lib, 'func')
  631. arguments = []
  632. call_arguments = []
  633. context = 'argument of %s' % name
  634. for i, type in enumerate(tp.args):
  635. arguments.append(type.get_c_name(' x%d' % i, context))
  636. call_arguments.append('x%d' % i)
  637. repr_arguments = ', '.join(arguments)
  638. repr_arguments = repr_arguments or 'void'
  639. if tp.abi:
  640. abi = tp.abi + ' '
  641. else:
  642. abi = ''
  643. name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments)
  644. prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
  645. prnt('{')
  646. call_arguments = ', '.join(call_arguments)
  647. result_code = 'return '
  648. if isinstance(tp.result, model.VoidType):
  649. result_code = ''
  650. prnt(' %s%s(%s);' % (result_code, name, call_arguments))
  651. prnt('}')
  652. #
  653. prnt('#ifndef PYPY_VERSION') # ------------------------------
  654. #
  655. prnt('static PyObject *')
  656. prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
  657. prnt('{')
  658. #
  659. context = 'argument of %s' % name
  660. for i, type in enumerate(tp.args):
  661. arg = type.get_c_name(' x%d' % i, context)
  662. prnt(' %s;' % arg)
  663. #
  664. localvars = set()
  665. freelines = set()
  666. for type in tp.args:
  667. self._extra_local_variables(type, localvars, freelines)
  668. for decl in sorted(localvars):
  669. prnt(' %s;' % (decl,))
  670. #
  671. if not isinstance(tp.result, model.VoidType):
  672. result_code = 'result = '
  673. context = 'result of %s' % name
  674. result_decl = ' %s;' % tp.result.get_c_name(' result', context)
  675. prnt(result_decl)
  676. prnt(' PyObject *pyresult;')
  677. else:
  678. result_decl = None
  679. result_code = ''
  680. #
  681. if len(tp.args) > 1:
  682. rng = range(len(tp.args))
  683. for i in rng:
  684. prnt(' PyObject *arg%d;' % i)
  685. prnt()
  686. prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % (
  687. name, len(rng), len(rng),
  688. ', '.join(['&arg%d' % i for i in rng])))
  689. prnt(' return NULL;')
  690. prnt()
  691. #
  692. for i, type in enumerate(tp.args):
  693. self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
  694. 'return NULL')
  695. prnt()
  696. #
  697. prnt(' Py_BEGIN_ALLOW_THREADS')
  698. prnt(' _cffi_restore_errno();')
  699. call_arguments = ['x%d' % i for i in range(len(tp.args))]
  700. call_arguments = ', '.join(call_arguments)
  701. prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
  702. prnt(' _cffi_save_errno();')
  703. prnt(' Py_END_ALLOW_THREADS')
  704. prnt()
  705. #
  706. prnt(' (void)self; /* unused */')
  707. if numargs == 0:
  708. prnt(' (void)noarg; /* unused */')
  709. if result_code:
  710. prnt(' pyresult = %s;' %
  711. self._convert_expr_from_c(tp.result, 'result', 'result type'))
  712. for freeline in freelines:
  713. prnt(' ' + freeline)
  714. prnt(' return pyresult;')
  715. else:
  716. for freeline in freelines:
  717. prnt(' ' + freeline)
  718. prnt(' Py_INCREF(Py_None);')
  719. prnt(' return Py_None;')
  720. prnt('}')
  721. #
  722. prnt('#else') # ------------------------------
  723. #
  724. # the PyPy version: need to replace struct/union arguments with
  725. # pointers, and if the result is a struct/union, insert a first
  726. # arg that is a pointer to the result. We also do that for
  727. # complex args and return type.
  728. def need_indirection(type):
  729. return (isinstance(type, model.StructOrUnion) or
  730. (isinstance(type, model.PrimitiveType) and
  731. type.is_complex_type()))
  732. difference = False
  733. arguments = []
  734. call_arguments = []
  735. context = 'argument of %s' % name
  736. for i, type in enumerate(tp.args):
  737. indirection = ''
  738. if need_indirection(type):
  739. indirection = '*'
  740. difference = True
  741. arg = type.get_c_name(' %sx%d' % (indirection, i), context)
  742. arguments.append(arg)
  743. call_arguments.append('%sx%d' % (indirection, i))
  744. tp_result = tp.result
  745. if need_indirection(tp_result):
  746. context = 'result of %s' % name
  747. arg = tp_result.get_c_name(' *result', context)
  748. arguments.insert(0, arg)
  749. tp_result = model.void_type
  750. result_decl = None
  751. result_code = '*result = '
  752. difference = True
  753. if difference:
  754. repr_arguments = ', '.join(arguments)
  755. repr_arguments = repr_arguments or 'void'
  756. name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name,
  757. repr_arguments)
  758. prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
  759. prnt('{')
  760. if result_decl:
  761. prnt(result_decl)
  762. call_arguments = ', '.join(call_arguments)
  763. prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
  764. if result_decl:
  765. prnt(' return result;')
  766. prnt('}')
  767. else:
  768. prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name))
  769. #
  770. prnt('#endif') # ------------------------------
  771. prnt()
  772. def _generate_cpy_function_ctx(self, tp, name):
  773. if tp.ellipsis and not self.target_is_python:
  774. self._generate_cpy_constant_ctx(tp, name)
  775. return
  776. type_index = self._typesdict[tp.as_raw_function()]
  777. numargs = len(tp.args)
  778. if self.target_is_python:
  779. meth_kind = OP_DLOPEN_FUNC
  780. elif numargs == 0:
  781. meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS'
  782. elif numargs == 1:
  783. meth_kind = OP_CPYTHON_BLTN_O # 'METH_O'
  784. else:
  785. meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
  786. self._lsts["global"].append(
  787. GlobalExpr(name, '_cffi_f_%s' % name,
  788. CffiOp(meth_kind, type_index),
  789. size='_cffi_d_%s' % name))
  790. # ----------
  791. # named structs or unions
  792. def _field_type(self, tp_struct, field_name, tp_field):
  793. if isinstance(tp_field, model.ArrayType):
  794. actual_length = tp_field.length
  795. if actual_length == '...':
  796. ptr_struct_name = tp_struct.get_c_name('*')
  797. actual_length = '_cffi_array_len(((%s)0)->%s)' % (
  798. ptr_struct_name, field_name)
  799. tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
  800. tp_field.item)
  801. tp_field = model.ArrayType(tp_item, actual_length)
  802. return tp_field
  803. def _struct_collecttype(self, tp):
  804. self._do_collect_type(tp)
  805. if self.target_is_python:
  806. # also requires nested anon struct/unions in ABI mode, recursively
  807. for fldtype in tp.anonymous_struct_fields():
  808. self._struct_collecttype(fldtype)
  809. def _struct_decl(self, tp, cname, approxname):
  810. if tp.fldtypes is None:
  811. return
  812. prnt = self._prnt
  813. checkfuncname = '_cffi_checkfld_%s' % (approxname,)
  814. prnt('_CFFI_UNUSED_FN')
  815. prnt('static void %s(%s *p)' % (checkfuncname, cname))
  816. prnt('{')
  817. prnt(' /* only to generate compile-time warnings or errors */')
  818. prnt(' (void)p;')
  819. for fname, ftype, fbitsize, fqual in self._enum_fields(tp):
  820. try:
  821. if ftype.is_integer_type() or fbitsize >= 0:
  822. # accept all integers, but complain on float or double
  823. if fname != '':
  824. prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is "
  825. "an integer */" % (fname, cname, fname))
  826. continue
  827. # only accept exactly the type declared, except that '[]'
  828. # is interpreted as a '*' and so will match any array length.
  829. # (It would also match '*', but that's harder to detect...)
  830. while (isinstance(ftype, model.ArrayType)
  831. and (ftype.length is None or ftype.length == '...')):
  832. ftype = ftype.item
  833. fname = fname + '[0]'
  834. prnt(' { %s = &p->%s; (void)tmp; }' % (
  835. ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
  836. fname))
  837. except VerificationError as e:
  838. prnt(' /* %s */' % str(e)) # cannot verify it, ignore
  839. prnt('}')
  840. prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname))
  841. prnt()
  842. def _struct_ctx(self, tp, cname, approxname, named_ptr=None):
  843. type_index = self._typesdict[tp]
  844. reason_for_not_expanding = None
  845. flags = []
  846. if isinstance(tp, model.UnionType):
  847. flags.append("_CFFI_F_UNION")
  848. if tp.fldtypes is None:
  849. flags.append("_CFFI_F_OPAQUE")
  850. reason_for_not_expanding = "opaque"
  851. if (tp not in self.ffi._parser._included_declarations and
  852. (named_ptr is None or
  853. named_ptr not in self.ffi._parser._included_declarations)):
  854. if tp.fldtypes is None:
  855. pass # opaque
  856. elif tp.partial or any(tp.anonymous_struct_fields()):
  857. pass # field layout obtained silently from the C compiler
  858. else:
  859. flags.append("_CFFI_F_CHECK_FIELDS")
  860. if tp.packed:
  861. if tp.packed > 1:
  862. raise NotImplementedError(
  863. "%r is declared with 'pack=%r'; only 0 or 1 are "
  864. "supported in API mode (try to use \"...;\", which "
  865. "does not require a 'pack' declaration)" %
  866. (tp, tp.packed))
  867. flags.append("_CFFI_F_PACKED")
  868. else:
  869. flags.append("_CFFI_F_EXTERNAL")
  870. reason_for_not_expanding = "external"
  871. flags = '|'.join(flags) or '0'
  872. c_fields = []
  873. if reason_for_not_expanding is None:
  874. enumfields = list(self._enum_fields(tp))
  875. for fldname, fldtype, fbitsize, fqual in enumfields:
  876. fldtype = self._field_type(tp, fldname, fldtype)
  877. self._check_not_opaque(fldtype,
  878. "field '%s.%s'" % (tp.name, fldname))
  879. # cname is None for _add_missing_struct_unions() only
  880. op = OP_NOOP
  881. if fbitsize >= 0:
  882. op = OP_BITFIELD
  883. size = '%d /* bits */' % fbitsize
  884. elif cname is None or (
  885. isinstance(fldtype, model.ArrayType) and
  886. fldtype.length is None):
  887. size = '(size_t)-1'
  888. else:
  889. size = 'sizeof(((%s)0)->%s)' % (
  890. tp.get_c_name('*') if named_ptr is None
  891. else named_ptr.name,
  892. fldname)
  893. if cname is None or fbitsize >= 0:
  894. offset = '(size_t)-1'
  895. elif named_ptr is not None:
  896. offset = '((char *)&((%s)0)->%s) - (char *)0' % (
  897. named_ptr.name, fldname)
  898. else:
  899. offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
  900. c_fields.append(
  901. FieldExpr(fldname, offset, size, fbitsize,
  902. CffiOp(op, self._typesdict[fldtype])))
  903. first_field_index = len(self._lsts["field"])
  904. self._lsts["field"].extend(c_fields)
  905. #
  906. if cname is None: # unknown name, for _add_missing_struct_unions
  907. size = '(size_t)-2'
  908. align = -2
  909. comment = "unnamed"
  910. else:
  911. if named_ptr is not None:
  912. size = 'sizeof(*(%s)0)' % (named_ptr.name,)
  913. align = '-1 /* unknown alignment */'
  914. else:
  915. size = 'sizeof(%s)' % (cname,)
  916. align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
  917. comment = None
  918. else:
  919. size = '(size_t)-1'
  920. align = -1
  921. first_field_index = -1
  922. comment = reason_for_not_expanding
  923. self._lsts["struct_union"].append(
  924. StructUnionExpr(tp.name, type_index, flags, size, align, comment,
  925. first_field_index, c_fields))
  926. self._seen_struct_unions.add(tp)
  927. def _check_not_opaque(self, tp, location):
  928. while isinstance(tp, model.ArrayType):
  929. tp = tp.item
  930. if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
  931. raise TypeError(
  932. "%s is of an opaque type (not declared in cdef())" % location)
  933. def _add_missing_struct_unions(self):
  934. # not very nice, but some struct declarations might be missing
  935. # because they don't have any known C name. Check that they are
  936. # not partial (we can't complete or verify them!) and emit them
  937. # anonymously.
  938. lst = list(self._struct_unions.items())
  939. lst.sort(key=lambda tp_order: tp_order[1])
  940. for tp, order in lst:
  941. if tp not in self._seen_struct_unions:
  942. if tp.partial:
  943. raise NotImplementedError("internal inconsistency: %r is "
  944. "partial but was not seen at "
  945. "this point" % (tp,))
  946. if tp.name.startswith('$') and tp.name[1:].isdigit():
  947. approxname = tp.name[1:]
  948. elif tp.name == '_IO_FILE' and tp.forcename == 'FILE':
  949. approxname = 'FILE'
  950. self._typedef_ctx(tp, 'FILE')
  951. else:
  952. raise NotImplementedError("internal inconsistency: %r" %
  953. (tp,))
  954. self._struct_ctx(tp, None, approxname)
  955. def _generate_cpy_struct_collecttype(self, tp, name):
  956. self._struct_collecttype(tp)
  957. _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype
  958. def _struct_names(self, tp):
  959. cname = tp.get_c_name('')
  960. if ' ' in cname:
  961. return cname, cname.replace(' ', '_')
  962. else:
  963. return cname, '_' + cname
  964. def _generate_cpy_struct_decl(self, tp, name):
  965. self._struct_decl(tp, *self._struct_names(tp))
  966. _generate_cpy_union_decl = _generate_cpy_struct_decl
  967. def _generate_cpy_struct_ctx(self, tp, name):
  968. self._struct_ctx(tp, *self._struct_names(tp))
  969. _generate_cpy_union_ctx = _generate_cpy_struct_ctx
  970. # ----------
  971. # 'anonymous' declarations. These are produced for anonymous structs
  972. # or unions; the 'name' is obtained by a typedef.
  973. def _generate_cpy_anonymous_collecttype(self, tp, name):
  974. if isinstance(tp, model.EnumType):
  975. self._generate_cpy_enum_collecttype(tp, name)
  976. else:
  977. self._struct_collecttype(tp)
  978. def _generate_cpy_anonymous_decl(self, tp, name):
  979. if isinstance(tp, model.EnumType):
  980. self._generate_cpy_enum_decl(tp)
  981. else:
  982. self._struct_decl(tp, name, 'typedef_' + name)
  983. def _generate_cpy_anonymous_ctx(self, tp, name):
  984. if isinstance(tp, model.EnumType):
  985. self._enum_ctx(tp, name)
  986. else:
  987. self._struct_ctx(tp, name, 'typedef_' + name)
  988. # ----------
  989. # constants, declared with "static const ..."
  990. def _generate_cpy_const(self, is_int, name, tp=None, category='const',
  991. check_value=None):
  992. if (category, name) in self._seen_constants:
  993. raise VerificationError(
  994. "duplicate declaration of %s '%s'" % (category, name))
  995. self._seen_constants.add((category, name))
  996. #
  997. prnt = self._prnt
  998. funcname = '_cffi_%s_%s' % (category, name)
  999. if is_int:
  1000. prnt('static int %s(unsigned long long *o)' % funcname)
  1001. prnt('{')
  1002. prnt(' int n = (%s) <= 0;' % (name,))
  1003. prnt(' *o = (unsigned long long)((%s) | 0);'
  1004. ' /* check that %s is an integer */' % (name, name))
  1005. if check_value is not None:
  1006. if check_value > 0:
  1007. check_value = '%dU' % (check_value,)
  1008. prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,))
  1009. prnt(' n |= 2;')
  1010. prnt(' return n;')
  1011. prnt('}')
  1012. else:
  1013. assert check_value is None
  1014. prnt('static void %s(char *o)' % funcname)
  1015. prnt('{')
  1016. prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name))
  1017. prnt('}')
  1018. prnt()
  1019. def _generate_cpy_constant_collecttype(self, tp, name):
  1020. is_int = tp.is_integer_type()
  1021. if not is_int or self.target_is_python:
  1022. self._do_collect_type(tp)
  1023. def _generate_cpy_constant_decl(self, tp, name):
  1024. is_int = tp.is_integer_type()
  1025. self._generate_cpy_const(is_int, name, tp)
  1026. def _generate_cpy_constant_ctx(self, tp, name):
  1027. if not self.target_is_python and tp.is_integer_type():
  1028. type_op = CffiOp(OP_CONSTANT_INT, -1)
  1029. else:
  1030. if self.target_is_python:
  1031. const_kind = OP_DLOPEN_CONST
  1032. else:
  1033. const_kind = OP_CONSTANT
  1034. type_index = self._typesdict[tp]
  1035. type_op = CffiOp(const_kind, type_index)
  1036. self._lsts["global"].append(
  1037. GlobalExpr(name, '_cffi_const_%s' % name, type_op))
  1038. # ----------
  1039. # enums
  1040. def _generate_cpy_enum_collecttype(self, tp, name):
  1041. self._do_collect_type(tp)
  1042. def _generate_cpy_enum_decl(self, tp, name=None):
  1043. for enumerator in tp.enumerators:
  1044. self._generate_cpy_const(True, enumerator)
  1045. def _enum_ctx(self, tp, cname):
  1046. type_index = self._typesdict[tp]
  1047. type_op = CffiOp(OP_ENUM, -1)
  1048. if self.target_is_python:
  1049. tp.check_not_partial()
  1050. for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
  1051. self._lsts["global"].append(
  1052. GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
  1053. check_value=enumvalue))
  1054. #
  1055. if cname is not None and '$' not in cname and not self.target_is_python:
  1056. size = "sizeof(%s)" % cname
  1057. signed = "((%s)-1) <= 0" % cname
  1058. else:
  1059. basetp = tp.build_baseinttype(self.ffi, [])
  1060. size = self.ffi.sizeof(basetp)
  1061. signed = int(int(self.ffi.cast(basetp, -1)) < 0)
  1062. allenums = ",".join(tp.enumerators)
  1063. self._lsts["enum"].append(
  1064. EnumExpr(tp.name, type_index, size, signed, allenums))
  1065. def _generate_cpy_enum_ctx(self, tp, name):
  1066. self._enum_ctx(tp, tp._get_c_name())
  1067. # ----------
  1068. # macros: for now only for integers
  1069. def _generate_cpy_macro_collecttype(self, tp, name):
  1070. pass
  1071. def _generate_cpy_macro_decl(self, tp, name):
  1072. if tp == '...':
  1073. check_value = None
  1074. else:
  1075. check_value = tp # an integer
  1076. self._generate_cpy_const(True, name, check_value=check_value)
  1077. def _generate_cpy_macro_ctx(self, tp, name):
  1078. if tp == '...':
  1079. if self.target_is_python:
  1080. raise VerificationError(
  1081. "cannot use the syntax '...' in '#define %s ...' when "
  1082. "using the ABI mode" % (name,))
  1083. check_value = None
  1084. else:
  1085. check_value = tp # an integer
  1086. type_op = CffiOp(OP_CONSTANT_INT, -1)
  1087. self._lsts["global"].append(
  1088. GlobalExpr(name, '_cffi_const_%s' % name, type_op,
  1089. check_value=check_value))
  1090. # ----------
  1091. # global variables
  1092. def _global_type(self, tp, global_name):
  1093. if isinstance(tp, model.ArrayType):
  1094. actual_length = tp.length
  1095. if actual_length == '...':
  1096. actual_length = '_cffi_array_len(%s)' % (global_name,)
  1097. tp_item = self._global_type(tp.item, '%s[0]' % global_name)
  1098. tp = model.ArrayType(tp_item, actual_length)
  1099. return tp
  1100. def _generate_cpy_variable_collecttype(self, tp, name):
  1101. self._do_collect_type(self._global_type(tp, name))
  1102. def _generate_cpy_variable_decl(self, tp, name):
  1103. prnt = self._prnt
  1104. tp = self._global_type(tp, name)
  1105. if isinstance(tp, model.ArrayType) and tp.length is None:
  1106. tp = tp.item
  1107. ampersand = ''
  1108. else:
  1109. ampersand = '&'
  1110. # This code assumes that casts from "tp *" to "void *" is a
  1111. # no-op, i.e. a function that returns a "tp *" can be called
  1112. # as if it returned a "void *". This should be generally true
  1113. # on any modern machine. The only exception to that rule (on
  1114. # uncommon architectures, and as far as I can tell) might be
  1115. # if 'tp' were a function type, but that is not possible here.
  1116. # (If 'tp' is a function _pointer_ type, then casts from "fn_t
  1117. # **" to "void *" are again no-ops, as far as I can tell.)
  1118. decl = '*_cffi_var_%s(void)' % (name,)
  1119. prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
  1120. prnt('{')
  1121. prnt(' return %s(%s);' % (ampersand, name))
  1122. prnt('}')
  1123. prnt()
  1124. def _generate_cpy_variable_ctx(self, tp, name):
  1125. tp = self._global_type(tp, name)
  1126. type_index = self._typesdict[tp]
  1127. if self.target_is_python:
  1128. op = OP_GLOBAL_VAR
  1129. else:
  1130. op = OP_GLOBAL_VAR_F
  1131. self._lsts["global"].append(
  1132. GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
  1133. # ----------
  1134. # extern "Python"
  1135. def _generate_cpy_extern_python_collecttype(self, tp, name):
  1136. assert isinstance(tp, model.FunctionPtrType)
  1137. self._do_collect_type(tp)
  1138. _generate_cpy_dllexport_python_collecttype = \
  1139. _generate_cpy_extern_python_plus_c_collecttype = \
  1140. _generate_cpy_extern_python_collecttype
  1141. def _extern_python_decl(self, tp, name, tag_and_space):
  1142. prnt = self._prnt
  1143. if isinstance(tp.result, model.VoidType):
  1144. size_of_result = '0'
  1145. else:
  1146. context = 'result of %s' % name
  1147. size_of_result = '(int)sizeof(%s)' % (
  1148. tp.result.get_c_name('', context),)
  1149. prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
  1150. prnt(' { "%s.%s", %s, 0, 0 };' % (
  1151. self.module_name, name, size_of_result))
  1152. prnt()
  1153. #
  1154. arguments = []
  1155. context = 'argument of %s' % name
  1156. for i, type in enumerate(tp.args):
  1157. arg = type.get_c_name(' a%d' % i, context)
  1158. arguments.append(arg)
  1159. #
  1160. repr_arguments = ', '.join(arguments)
  1161. repr_arguments = repr_arguments or 'void'
  1162. name_and_arguments = '%s(%s)' % (name, repr_arguments)
  1163. if tp.abi == "__stdcall":
  1164. name_and_arguments = '_cffi_stdcall ' + name_and_arguments
  1165. #
  1166. def may_need_128_bits(tp):
  1167. return (isinstance(tp, model.PrimitiveType) and
  1168. tp.name == 'long double')
  1169. #
  1170. size_of_a = max(len(tp.args)*8, 8)
  1171. if may_need_128_bits(tp.result):
  1172. size_of_a = max(size_of_a, 16)
  1173. if isinstance(tp.result, model.StructOrUnion):
  1174. size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % (
  1175. tp.result.get_c_name(''), size_of_a,
  1176. tp.result.get_c_name(''), size_of_a)
  1177. prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments)))
  1178. prnt('{')
  1179. prnt(' char a[%s];' % size_of_a)
  1180. prnt(' char *p = a;')
  1181. for i, type in enumerate(tp.args):
  1182. arg = 'a%d' % i
  1183. if (isinstance(type, model.StructOrUnion) or
  1184. may_need_128_bits(type)):
  1185. arg = '&' + arg
  1186. type = model.PointerType(type)
  1187. prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg))
  1188. prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name)
  1189. if not isinstance(tp.result, model.VoidType):
  1190. prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),))
  1191. prnt('}')
  1192. prnt()
  1193. self._num_externpy += 1
  1194. def _generate_cpy_extern_python_decl(self, tp, name):
  1195. self._extern_python_decl(tp, name, 'static ')
  1196. def _generate_cpy_dllexport_python_decl(self, tp, name):
  1197. self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ')
  1198. def _generate_cpy_extern_python_plus_c_decl(self, tp, name):
  1199. self._extern_python_decl(tp, name, '')
  1200. def _generate_cpy_extern_python_ctx(self, tp, name):
  1201. if self.target_is_python:
  1202. raise VerificationError(
  1203. "cannot use 'extern \"Python\"' in the ABI mode")
  1204. if tp.ellipsis:
  1205. raise NotImplementedError("a vararg function is extern \"Python\"")
  1206. type_index = self._typesdict[tp]
  1207. type_op = CffiOp(OP_EXTERN_PYTHON, type_index)
  1208. self._lsts["global"].append(
  1209. GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name))
  1210. _generate_cpy_dllexport_python_ctx = \
  1211. _generate_cpy_extern_python_plus_c_ctx = \
  1212. _generate_cpy_extern_python_ctx
  1213. def _print_string_literal_in_array(self, s):
  1214. prnt = self._prnt
  1215. prnt('// # NB. this is not a string because of a size limit in MSVC')
  1216. if not isinstance(s, bytes): # unicode
  1217. s = s.encode('utf-8') # -> bytes
  1218. else:
  1219. s.decode('utf-8') # got bytes, check for valid utf-8
  1220. try:
  1221. s.decode('ascii')
  1222. except UnicodeDecodeError:
  1223. s = b'# -*- encoding: utf8 -*-\n' + s
  1224. for line in s.splitlines(True):
  1225. comment = line
  1226. if type('//') is bytes: # python2
  1227. line = map(ord, line) # make a list of integers
  1228. else: # python3
  1229. # type(line) is bytes, which enumerates like a list of integers
  1230. comment = ascii(comment)[1:-1]
  1231. prnt(('// ' + comment).rstrip())
  1232. printed_line = ''
  1233. for c in line:
  1234. if len(printed_line) >= 76:
  1235. prnt(printed_line)
  1236. printed_line = ''
  1237. printed_line += '%d,' % (c,)
  1238. prnt(printed_line)
  1239. # ----------
  1240. # emitting the opcodes for individual types
  1241. def _emit_bytecode_VoidType(self, tp, index):
  1242. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID)
  1243. def _emit_bytecode_PrimitiveType(self, tp, index):
  1244. prim_index = PRIMITIVE_TO_INDEX[tp.name]
  1245. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)
  1246. def _emit_bytecode_UnknownIntegerType(self, tp, index):
  1247. s = ('_cffi_prim_int(sizeof(%s), (\n'
  1248. ' ((%s)-1) | 0 /* check that %s is an integer type */\n'
  1249. ' ) <= 0)' % (tp.name, tp.name, tp.name))
  1250. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
  1251. def _emit_bytecode_UnknownFloatType(self, tp, index):
  1252. s = ('_cffi_prim_float(sizeof(%s) *\n'
  1253. ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n'
  1254. ' )' % (tp.name, tp.name))
  1255. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
  1256. def _emit_bytecode_RawFunctionType(self, tp, index):
  1257. self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result])
  1258. index += 1
  1259. for tp1 in tp.args:
  1260. realindex = self._typesdict[tp1]
  1261. if index != realindex:
  1262. if isinstance(tp1, model.PrimitiveType):
  1263. self._emit_bytecode_PrimitiveType(tp1, index)
  1264. else:
  1265. self.cffi_types[index] = CffiOp(OP_NOOP, realindex)
  1266. index += 1
  1267. flags = int(tp.ellipsis)
  1268. if tp.abi is not None:
  1269. if tp.abi == '__stdcall':
  1270. flags |= 2
  1271. else:
  1272. raise NotImplementedError("abi=%r" % (tp.abi,))
  1273. self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags)
  1274. def _emit_bytecode_PointerType(self, tp, index):
  1275. self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype])
  1276. _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType
  1277. _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType
  1278. def _emit_bytecode_FunctionPtrType(self, tp, index):
  1279. raw = tp.as_raw_function()
  1280. self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw])
  1281. def _emit_bytecode_ArrayType(self, tp, index):
  1282. item_index = self._typesdict[tp.item]
  1283. if tp.length is None:
  1284. self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
  1285. elif tp.length == '...':
  1286. raise VerificationError(
  1287. "type %s badly placed: the '...' array length can only be "
  1288. "used on global arrays or on fields of structures" % (
  1289. str(tp).replace('/*...*/', '...'),))
  1290. else:
  1291. assert self.cffi_types[index + 1] == 'LEN'
  1292. self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
  1293. self.cffi_types[index + 1] = CffiOp(None, str(tp.length))
  1294. def _emit_bytecode_StructType(self, tp, index):
  1295. struct_index = self._struct_unions[tp]
  1296. self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index)
  1297. _emit_bytecode_UnionType = _emit_bytecode_StructType
  1298. def _emit_bytecode_EnumType(self, tp, index):
  1299. enum_index = self._enums[tp]
  1300. self.cffi_types[index] = CffiOp(OP_ENUM, enum_index)
  1301. if sys.version_info >= (3,):
  1302. NativeIO = io.StringIO
  1303. else:
  1304. class NativeIO(io.BytesIO):
  1305. def write(self, s):
  1306. if isinstance(s, unicode):
  1307. s = s.encode('ascii')
  1308. super(NativeIO, self).write(s)
  1309. def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose):
  1310. if verbose:
  1311. print("generating %s" % (target_file,))
  1312. recompiler = Recompiler(ffi, module_name,
  1313. target_is_python=(preamble is None))
  1314. recompiler.collect_type_table()
  1315. recompiler.collect_step_tables()
  1316. f = NativeIO()
  1317. recompiler.write_source_to_f(f, preamble)
  1318. output = f.getvalue()
  1319. try:
  1320. with open(target_file, 'r') as f1:
  1321. if f1.read(len(output) + 1) != output:
  1322. raise IOError
  1323. if verbose:
  1324. print("(already up-to-date)")
  1325. return False # already up-to-date
  1326. except IOError:
  1327. tmp_file = '%s.~%d' % (target_file, os.getpid())
  1328. with open(tmp_file, 'w') as f1:
  1329. f1.write(output)
  1330. try:
  1331. os.rename(tmp_file, target_file)
  1332. except OSError:
  1333. os.unlink(target_file)
  1334. os.rename(tmp_file, target_file)
  1335. return True
  1336. def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False):
  1337. assert preamble is not None
  1338. return _make_c_or_py_source(ffi, module_name, preamble, target_c_file,
  1339. verbose)
  1340. def make_py_source(ffi, module_name, target_py_file, verbose=False):
  1341. return _make_c_or_py_source(ffi, module_name, None, target_py_file,
  1342. verbose)
  1343. def _modname_to_file(outputdir, modname, extension):
  1344. parts = modname.split('.')
  1345. try:
  1346. os.makedirs(os.path.join(outputdir, *parts[:-1]))
  1347. except OSError:
  1348. pass
  1349. parts[-1] += extension
  1350. return os.path.join(outputdir, *parts), parts
  1351. # Aaargh. Distutils is not tested at all for the purpose of compiling
  1352. # DLLs that are not extension modules. Here are some hacks to work
  1353. # around that, in the _patch_for_*() functions...
  1354. def _patch_meth(patchlist, cls, name, new_meth):
  1355. old = getattr(cls, name)
  1356. patchlist.append((cls, name, old))
  1357. setattr(cls, name, new_meth)
  1358. return old
  1359. def _unpatch_meths(patchlist):
  1360. for cls, name, old_meth in reversed(patchlist):
  1361. setattr(cls, name, old_meth)
  1362. def _patch_for_embedding(patchlist):
  1363. if sys.platform == 'win32':
  1364. # we must not remove the manifest when building for embedding!
  1365. from distutils.msvc9compiler import MSVCCompiler
  1366. _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
  1367. lambda self, manifest_file: manifest_file)
  1368. if sys.platform == 'darwin':
  1369. # we must not make a '-bundle', but a '-dynamiclib' instead
  1370. from distutils.ccompiler import CCompiler
  1371. def my_link_shared_object(self, *args, **kwds):
  1372. if '-bundle' in self.linker_so:
  1373. self.linker_so = list(self.linker_so)
  1374. i = self.linker_so.index('-bundle')
  1375. self.linker_so[i] = '-dynamiclib'
  1376. return old_link_shared_object(self, *args, **kwds)
  1377. old_link_shared_object = _patch_meth(patchlist, CCompiler,
  1378. 'link_shared_object',
  1379. my_link_shared_object)
  1380. def _patch_for_target(patchlist, target):
  1381. from distutils.command.build_ext import build_ext
  1382. # if 'target' is different from '*', we need to patch some internal
  1383. # method to just return this 'target' value, instead of having it
  1384. # built from module_name
  1385. if target.endswith('.*'):
  1386. target = target[:-2]
  1387. if sys.platform == 'win32':
  1388. target += '.dll'
  1389. elif sys.platform == 'darwin':
  1390. target += '.dylib'
  1391. else:
  1392. target += '.so'
  1393. _patch_meth(patchlist, build_ext, 'get_ext_filename',
  1394. lambda self, ext_name: target)
  1395. def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
  1396. c_file=None, source_extension='.c', extradir=None,
  1397. compiler_verbose=1, target=None, debug=None, **kwds):
  1398. if not isinstance(module_name, str):
  1399. module_name = module_name.encode('ascii')
  1400. if ffi._windows_unicode:
  1401. ffi._apply_windows_unicode(kwds)
  1402. if preamble is not None:
  1403. embedding = (ffi._embedding is not None)
  1404. if embedding:
  1405. ffi._apply_embedding_fix(kwds)
  1406. if c_file is None:
  1407. c_file, parts = _modname_to_file(tmpdir, module_name,
  1408. source_extension)
  1409. if extradir:
  1410. parts = [extradir] + parts
  1411. ext_c_file = os.path.join(*parts)
  1412. else:
  1413. ext_c_file = c_file
  1414. #
  1415. if target is None:
  1416. if embedding:
  1417. target = '%s.*' % module_name
  1418. else:
  1419. target = '*'
  1420. #
  1421. ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
  1422. updated = make_c_source(ffi, module_name, preamble, c_file,
  1423. verbose=compiler_verbose)
  1424. if call_c_compiler:
  1425. patchlist = []
  1426. cwd = os.getcwd()
  1427. try:
  1428. if embedding:
  1429. _patch_for_embedding(patchlist)
  1430. if target != '*':
  1431. _patch_for_target(patchlist, target)
  1432. if compiler_verbose:
  1433. if tmpdir == '.':
  1434. msg = 'the current directory is'
  1435. else:
  1436. msg = 'setting the current directory to'
  1437. print('%s %r' % (msg, os.path.abspath(tmpdir)))
  1438. os.chdir(tmpdir)
  1439. outputfilename = ffiplatform.compile('.', ext,
  1440. compiler_verbose, debug)
  1441. finally:
  1442. os.chdir(cwd)
  1443. _unpatch_meths(patchlist)
  1444. return outputfilename
  1445. else:
  1446. return ext, updated
  1447. else:
  1448. if c_file is None:
  1449. c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
  1450. updated = make_py_source(ffi, module_name, c_file,
  1451. verbose=compiler_verbose)
  1452. if call_c_compiler:
  1453. return c_file
  1454. else:
  1455. return None, updated