PageRenderTime 29ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/srcgen/c.py

https://github.com/dagss/f2py-g3
Python | 497 lines | 461 code | 12 blank | 24 comment | 7 complexity | fde3f617aba499e84f9e37d45563163a MD5 | raw file
  1. """ Implements components for C programs.
  2. """
  3. # Created: April, 2008
  4. # Author: Pearu Peterson
  5. __all__ = ['Include',
  6. 'Keyword',
  7. 'TypeDefStruct', 'TypeDefFunction', 'TypeDefTypeSpec',
  8. 'TypeDefEnum',
  9. 'TypeSpec', 'Declarator', 'Declaration',
  10. 'Variable', 'Argument', 'Function',
  11. 'SourceFile']
  12. import sys
  13. from .api import Component, basic
  14. # http://en.wikipedia.org/wiki/C_standard_library
  15. clibs_headers = '''assert.h complex.h ctype.h errno.h fenv.h float.h
  16. inttypes.h iso646.h limits.h locale.h math.h setjmp.h signal.h stdarg.h
  17. stdbool.h stddef.h stdint.h stdio.h stdlib.h string.h tgmath.h time.h
  18. wchar.h wctype.h'''.split()
  19. short_type_spec_map = dict(
  20. Struct='S', Function='F', TypeSpec='T', Pointer='p', Enum='E',
  21. void='v',
  22. int='i',unsignedint='ui',signedint='i',
  23. char='c',unsignedchar='uC', signedchar='C',
  24. short='s', shortint='s', unsignedshort='us', signedshort='s',
  25. long='l', longint='l',
  26. signedlong='l', signedlongint='l', longsignedint='l',
  27. unsignedlong='ul', unsignedlongint='ul', longunsignedint='ul',
  28. longlong='L', longlongint='L',
  29. signedlonglong='L', signedlonglongint='L',
  30. unsignedlonglong='uL',
  31. unsignedlonglongint='uL',
  32. float='f',
  33. double='d', longdouble='D',
  34. size_t = 't',
  35. PyObject='PyO',
  36. PyObjectType='PyT',
  37. PyArrayObject='PyA',
  38. )
  39. class Include(Component):
  40. """ Represents include CPP directive.
  41. """
  42. templates = dict(
  43. string = '#include %(include)s',
  44. user_include = '"%(filename)s"',
  45. std_include = '<%(filename)s>',
  46. )
  47. template_options = dict(
  48. include = dict()
  49. )
  50. request_own_data = True
  51. def __init__(self, filename, is_std_header = None):
  52. Component.__init__(self)
  53. self.filename = filename
  54. if is_std_header is None:
  55. is_std_header = filename in clibs_headers
  56. self.is_std_header = is_std_header
  57. def request_data(self, subs_name, parents):
  58. if subs_name=='include':
  59. if self.is_std_header:
  60. return self.get_view('std_include', parents)
  61. else:
  62. return self.get_view('user_include', parents)
  63. if subs_name=='Includes':
  64. return self.filename, self.get_view('string', parents)
  65. return super(type(self), self).request_data(subs_name, parents)
  66. class TypeSpec(Component):
  67. """ C type specification.
  68. Basic <type_spec>-s:
  69. int, char, short, long, void, float, double,
  70. long long, long double,
  71. PyObject, PyObjectType, PyArrayObject
  72. <name of typedef struct>
  73. Pointers:
  74. <type_spec>*, <type_spec>**, etc
  75. Arrays:
  76. <type_spec>[<dim1>], <type_spec>[<dim1>][<dim2>], etc
  77. Not implemented:
  78. pointers to arrays, arrays of pointers
  79. """
  80. templates = dict(
  81. string = '%(name)s',
  82. )
  83. def __init__(self, name):
  84. Component.__init__(self)
  85. self.name = name
  86. @property
  87. def short_type_spec(self):
  88. return self.request_data('short_type_spec', None)
  89. def request_data(self, subs_name, parents):
  90. if subs_name=='type_spec':
  91. return self.name
  92. if subs_name=='short_type_spec':
  93. t = self.name
  94. t = t0 = t.replace(' ','')
  95. while t.endswith('*'):
  96. t = t[:-1]
  97. n = len(t0) - len(t)
  98. p = n*short_type_spec_map['Pointer']
  99. l = []
  100. while t.endswith(']'):
  101. i = t.rfind('[')
  102. l.insert(0, t[i+1:-1])
  103. t = t[:i]
  104. s = 'j'.join(l)
  105. r = short_type_spec_map.get(t)
  106. if r is None and parents is not None:
  107. c = parents.find_component_with_view('type_spec', t)
  108. if c is not None:
  109. r = c.get_view('short_type_spec', parents)
  110. if r is None:
  111. sys.stderr.write('warning: %r is not in short_type_spec map\n' % (t))
  112. r = t
  113. return p + r + s
  114. def type_spec_first_str(joiner):
  115. new = type(joiner)(default='void')
  116. if joiner.keys:
  117. new.add(joiner.values[0], joiner.keys[0])
  118. return str(new)
  119. def type_spec_rest_str(joiner):
  120. new = type(joiner)(default='void', separator=', ')
  121. for k, v in zip(joiner.keys[1:], joiner.values[1:]):
  122. new.add(v, k)
  123. return str(new)
  124. class TypeDefBase(Component):
  125. def __init__(self, name, *leafs):
  126. Component.__init__(self, *leafs)
  127. self._name = name
  128. @property
  129. def name(self):
  130. return self.get_name(None)
  131. def get_name(self, parents):
  132. if self._name is None:
  133. return '%s_type' % (self.get_view('short_type_spec', parents))
  134. return self._name
  135. def request_data(self, subs_name, parents):
  136. if subs_name=='TypeDefs':
  137. return self.get_name(parents), self.get_view('string', parents)
  138. if subs_name=='type_spec':
  139. return self.get_name(parents)
  140. if subs_name=='short_type_spec':
  141. self.get_view('short_type_spec', parents)
  142. return Component.request_data(self, subs_name, parents)
  143. class TypeDefTypeSpec(TypeDefBase):
  144. """ Typedef of a type spec.
  145. """
  146. templates = dict(
  147. string = 'typedef %(type_spec)s %(name)s',
  148. type_spec = '%(name)s',
  149. short_type_spec = short_type_spec_map['TypeSpec'] + '%(short_type_spec)s_',
  150. )
  151. template_options = dict(
  152. type_spec = dict(default='int'),
  153. short_type_spec = dict(default='i', separator=''),
  154. )
  155. def add(self, other):
  156. if isinstance(other, str):
  157. other = TypeSpec(other)
  158. TypeDefBase.add(self, other)
  159. class TypeDefStruct(TypeDefBase):
  160. """ Typedef of a struct.
  161. """
  162. templates = dict(
  163. string = 'typedef struct {\n%(variable_declarations)s} %(name)s',
  164. type_spec = '%(name)s',
  165. short_type_spec = short_type_spec_map['Struct'] + '%(variable_short_type_specs)s_',
  166. )
  167. template_options = dict(
  168. variable_declarations = dict(separator=';\n',
  169. use_indent=True, indent_offset=2,
  170. prefix='', skip_prefix_when_empty=True,
  171. suffix=';\n', skip_suffix_when_empty=True),
  172. variable_short_type_specs = dict(separator='')
  173. )
  174. def add(self, other):
  175. if isinstance(other, str):
  176. other = Declaration(other)
  177. TypeDefBase.add(self, other)
  178. class TypeDefEnum(TypeDefBase):
  179. templates = dict(
  180. string = 'typedef enum {\n%(declarators)s} %(name)s',
  181. type_spec = '%(name)s',
  182. short_type_spec = short_type_spec_map['Enum'] + '%(name)s_',
  183. )
  184. template_options = dict(
  185. declarators = dict(separator=',\n',
  186. use_indent=True, indent_offset=2,
  187. prefix='', skip_prefix_when_empty=True,
  188. suffix='\n', skip_suffix_when_empty=True),
  189. short_type_spec = dict(default='i', separator=''),
  190. )
  191. def add(self, other):
  192. if isinstance(other, str):
  193. other = Declarator(other)
  194. TypeDefBase.add(self, other)
  195. class TypeDefFunction(TypeDefBase):
  196. """ Typedef of a function.
  197. """
  198. templates = dict(
  199. string = 'typedef %(type_spec_first..type_spec)s (*%(name)s)(%(type_spec_rest..type_spec)s)',
  200. type_spec = '%(name)s',
  201. short_type_spec = short_type_spec_map['Function'] + '%(short_type_spec)s_',
  202. )
  203. template_options = dict(
  204. type_spec_first = dict(user_defined_str=type_spec_first_str),
  205. type_spec_rest = dict(user_defined_str=type_spec_rest_str),
  206. short_type_spec = dict(separator=''),
  207. )
  208. def add(self, other):
  209. if isinstance(other, str):
  210. other = TypeSpec(other)
  211. TypeDefBase.add(self, other)
  212. class Declarator(Component):
  213. """ Represents a declarator with optional initialization.
  214. Declarator(<name>, <initial values>,..., is_string=, is_scalar=)
  215. Initial values can be either be string or Line instances.
  216. """
  217. templates = dict(
  218. string = '%(name)s%(init)s',
  219. stringinit = '%(stringvalue..strings)s',
  220. scalarinit = '%(scalarvalue..strings)s',
  221. sequenceinit = '%(sequencevalue..strings)s',
  222. )
  223. template_options = dict(
  224. scalarvalue = dict(prefix=' = ',
  225. skip_prefix_when_empty=True,
  226. skip_suffix_when_empty=True,
  227. ignore_empty_content = True, default=''),
  228. stringvalue = dict(prefix='[] = "', suffix='"',
  229. skip_prefix_when_empty=True,
  230. skip_suffix_when_empty=True,
  231. ignore_empty_content = True, default='',
  232. separator='\\n"\n"', replace_map = {'\n':'\\n'},
  233. use_firstline_indent = True,
  234. ),
  235. sequencevalue = dict(prefix=' = {', suffix='}',
  236. skip_prefix_when_empty=True,
  237. skip_suffix_when_empty=True,
  238. ignore_empty_content = True, default='',
  239. separator=', ',
  240. ),
  241. init = dict() #
  242. )
  243. request_own_data = True
  244. def __init__(self, name, *leafs, **options):
  245. Component.__init__(self, *leafs)
  246. self._check_options(options, 'is_scalar', 'is_string')
  247. is_string = options.get('is_string')
  248. is_scalar = options.get('is_scalar')
  249. self.name = name
  250. if is_string:
  251. self.is_string = True
  252. self.is_scalar = False
  253. self.is_sequence = False
  254. else:
  255. if is_scalar is None:
  256. is_scalar = True
  257. self.is_string = False
  258. self.is_scalar = is_scalar
  259. self.is_sequence = not is_scalar
  260. def add(self, other):
  261. if isinstance(other, str):
  262. other = basic.Line(other)
  263. super(type(self), self).add(other)
  264. def request_data(self, subs_name, parents):
  265. if subs_name=='declarators':
  266. return self.get_view('string', parents)
  267. if subs_name=='declarator_name':
  268. return self.name
  269. if subs_name=='init':
  270. if self.is_sequence:
  271. return self.get_view('sequenceinit')
  272. if self.is_string:
  273. return self.get_view('stringinit')
  274. return self.get_view('scalarinit')
  275. class Keyword(Component):
  276. """ Represents keyword.
  277. Basic keywords:
  278. static, extern, const, etc
  279. """
  280. templates = dict(
  281. string = '%(name)s'
  282. )
  283. def __init__(self, name, *leafs):
  284. Component.__init__(self, *leafs)
  285. self.name = name
  286. def request_data(self, subs_name, parents):
  287. if subs_name == 'keyword':
  288. return self.name, self.name
  289. def check_declarator_name(joiner):
  290. if len(joiner.values)!=1:
  291. raise ValueError('declarator_name must have exactly one value, got %s' % (len(joiner.values)))
  292. class Declaration(Component):
  293. """ Represents declarations.
  294. """
  295. templates = dict(
  296. string = '%(type_spec)s %(declarators)s',
  297. argument= '%(declarator_name)s',
  298. variable= '%(declarator_name)s',
  299. argument_declaration = '%(type_spec)s %(declarator_name)s',
  300. variable_declaration = '%(type_spec)s %(declarator_name)s',
  301. prototype_argument_declaration = '%(type_spec)s',
  302. variable_short_type_spec = '%(short_type_spec)s',
  303. argument_short_type_spec = '%(short_type_spec)s',
  304. static_definition = '%(keyword)s%(type_spec)s %(declarator_name)s;',
  305. )
  306. template_options = dict(
  307. type_spec = dict(default='int'),
  308. short_type_spec = dict(default='i'),
  309. declarators = dict(separator=', ', default='<KILLLINE>'),
  310. declarator_name = dict(check_func = check_declarator_name),
  311. keyword = dict(default='', separator=' ',
  312. suffix=' ', skip_suffix_when_empty=True
  313. )
  314. )
  315. def add(self, other):
  316. if isinstance(other, str):
  317. other = Declarator(other)
  318. Component.add(self, other)
  319. def request_data(self, subs_name, parents):
  320. if subs_name=='variable_declarations':
  321. return self.get_view('string', parents)
  322. if subs_name=='arguments':
  323. return self.get_view('argument', parents)
  324. if subs_name=='argument_declarations':
  325. return self.get_view('argument_declaration', parents)
  326. if subs_name=='variable_declarations':
  327. return self.get_view('variable_declaration', parents)
  328. if subs_name=='prototype_argument_declarations':
  329. return self.get_view('prototype_argument_declaration', parents)
  330. if subs_name=='variable_short_type_specs':
  331. return self.get_view('variable_short_type_spec', parents)
  332. if subs_name=='argument_short_type_specs':
  333. return self.get_view('argument_short_type_spec', parents)
  334. if subs_name=='Definitions':
  335. return self.get_view('variable', parents), self.get_view('static_definition', parents)
  336. class Variable(Declaration):
  337. def request_data(self, subs_name, parents):
  338. if 'argument' in subs_name:
  339. return
  340. return super(type(self), self).request_data(subs_name, parents)
  341. class Argument(Declaration):
  342. def request_data(self, subs_name, parents):
  343. if 'variable' in subs_name:
  344. return
  345. return super(type(self), self).request_data(subs_name, parents)
  346. def check_type_spec(joiner):
  347. if len(joiner.values)>1:
  348. raise ValueError('type_spec must have at most one value, got %s' % (len(joiner.values)))
  349. class Function(basic.Block):
  350. templates = dict(
  351. string = '''\
  352. %(type_spec)s
  353. %(name)s(%(argument_declarations)s) {
  354. %(variable_declarations)s
  355. %(exec_statements..strings)s
  356. }''',
  357. prototype = '%(type_spec)s %(name)s(%(prototype_argument_declarations)s)',
  358. typedef = 'typedef %(type_spec)s (*%(name)s)(%(prototype_argument_declarations)s)',
  359. )
  360. template_options = dict(
  361. type_spec = dict(default='void', check_func=check_type_spec),
  362. argument_declarations = dict(separator=', ', default='void'),
  363. prototype_argument_declarations = dict(separator=', ', default='void'),
  364. variable_declarations = dict(separator=';\n', default='<KILLLINE>',
  365. use_indent=True, indent_offset=2,
  366. suffix=';', skip_suffix_when_empty=True),
  367. exec_statements = dict(use_indent=True, c_block_indent=True, indent_offset=2, default='<KILLLINE>'),
  368. )
  369. request_own_data = True
  370. def request_data(self, subs_name, parents):
  371. if subs_name=='Definitions':
  372. return self.name, self.get_view('string', parents)
  373. if subs_name=='ProtoTypes':
  374. return self.name, self.get_view('prototype', parents)
  375. return super(type(self), self).request_data(subs_name, parents)
  376. class SourceFile(basic.SourceFile):
  377. templates = dict(
  378. string = '''\
  379. %(FileHeader)s
  380. %(Includes)s
  381. %(TypeDefs)s
  382. %(ProtoTypes)s
  383. %(Definitions)s
  384. %(MainProgram)s
  385. %(FileFooter)s
  386. ''',
  387. c_header = '''\
  388. #ifdef __cplusplus
  389. extern \"C\" {
  390. #endif''',
  391. c_footer = '''
  392. #ifdef __cplusplus
  393. }
  394. #endif'''
  395. )
  396. template_options = dict(
  397. FileHeader = dict(separator='\n', default='<KILLLINE>'),
  398. Includes = dict(separator='\n', default='<KILLLINE>',
  399. prefix='\n/* Includes */\n', skip_prefix_when_empty=True),
  400. TypeDefs = dict(separator=';\n', default='<KILLLINE>',
  401. prefix='\n/* TypeDefs */\n', skip_prefix_when_empty=True,
  402. suffix=';', skip_suffix_when_empty=True,
  403. ),
  404. ProtoTypes = dict(separator=';\n', default='<KILLLINE>',
  405. prefix='\n/* ProtoTypes */\n', skip_prefix_when_empty=True,
  406. suffix=';', skip_suffix_when_empty=True,
  407. ),
  408. Definitions = dict(separator='\n\n', default='<KILLLINE>',
  409. prefix='\n/* Definitions */\n', skip_prefix_when_empty=True),
  410. MainProgram = dict(separator='\n', default='<KILLLINE>',
  411. prefix='/* MainProgram */\n', skip_prefix_when_empty=True),
  412. FileFooter = dict(separator='\n', default='<KILLLINE>'),
  413. )
  414. request_own_data = True
  415. def request_data(self, subs_name, parents):
  416. if subs_name=='FileHeader':
  417. return self.get_view('c_header', parents)
  418. if subs_name=='FileFooter':
  419. return self.get_view('c_footer', parents)
  420. return super(type(self), self).request_data(subs_name, parents)