cgen.py: use C type classes for _CodeGen._ft_c_type()
[deliverable/barectf.git] / barectf / cgen.py
CommitLineData
e5aa0be3
PP
1# The MIT License (MIT)
2#
4a90140d 3# Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com>
e5aa0be3 4#
1378f213
PP
5# Permission is hereby granted, free of charge, to any person obtaining
6# a copy of this software and associated documentation files (the
7# "Software"), to deal in the Software without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish,
9# distribute, sublicense, and/or sell copies of the Software, and to
10# permit persons to whom the Software is furnished to do so, subject to
11# the following conditions:
e5aa0be3 12#
1378f213
PP
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
e5aa0be3 15#
1378f213
PP
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
e5aa0be3 23
8c7c6ed2 24import barectf.template as barectf_template
4810b707 25import barectf.config as barectf_config
d6483c83 26import collections
acfb8213 27import copy
c268d669 28import re
1624d186
PP
29from typing import List, Optional, Mapping, Callable, Any, Set, Tuple
30import typing
31from barectf.typing import Count, Alignment
4810b707
PP
32
33
d6483c83
PP
34# A tuple containing serialization and size computation function
35# templates for a given operation.
36_OpTemplates = collections.namedtuple('_OpTemplates', ['serialize', 'size'])
70e191bd
PP
37
38
2394a4b4 39# Abstract base class of any operation within source code.
d6483c83
PP
40#
41# Any operation has:
42#
d6483c83
PP
43# * A field type.
44#
2394a4b4
PP
45# * A list of names which, when joined with `_`, form the generic
46# C source variable name.
d6483c83
PP
47#
48# * Serialization and size computation templates to generate the
49# operation's source code for those functions.
50class _Op:
2394a4b4 51 def __init__(self, ft: barectf_config._FieldType, names: List[str], templates: _OpTemplates):
4810b707 52 self._ft = ft
d6483c83
PP
53 self._names = copy.copy(names)
54 self._templates = templates
e5aa0be3 55
acfb8213 56 @property
1624d186 57 def ft(self) -> barectf_config._FieldType:
4810b707 58 return self._ft
acfb8213
PP
59
60 @property
1624d186 61 def names(self) -> List[str]:
acfb8213 62 return self._names
e5aa0be3 63
d6483c83 64 @property
1624d186 65 def top_name(self) -> str:
d6483c83 66 return self._names[-1]
e5aa0be3 67
1624d186 68 def _render_template(self, templ: barectf_template._Template, **kwargs) -> str:
d6483c83
PP
69 return templ.render(op=self, root_ft_prefixes=_RootFtPrefixes,
70 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, **kwargs)
71
1624d186 72 def serialize_str(self, **kwargs) -> str:
d6483c83
PP
73 return self._render_template(self._templates.serialize, **kwargs)
74
1624d186 75 def size_str(self, **kwargs) -> str:
d6483c83
PP
76 return self._render_template(self._templates.size, **kwargs)
77
78
2394a4b4
PP
79# Compound operation.
80#
81# A compound operation contains a list of suboperations (leaf or
82# compound).
83#
84# Get the suboperations of a compound operation with its `subops`
85# property.
86#
87# The templates of a compound operation handles its suboperations.
88class _CompoundOp(_Op):
89 def __init__(self, ft: barectf_config._FieldType, names: List[str], templates: _OpTemplates,
90 subops: List[Any] = None):
91 super().__init__(ft, names, templates)
92 self._subops = subops
93
94 @property
95 def subops(self):
96 return self._subops
97
98
99# Leaf operation (abstract class).
100class _LeafOp(_Op):
101 def __init__(self, offset_in_byte: Count, ft: barectf_config._FieldType, names: List[str],
102 templates: _OpTemplates):
103 super().__init__(ft, names, templates)
104 assert offset_in_byte >= 0 and offset_in_byte < 8
105 self._offset_in_byte = offset_in_byte
106
107 @property
108 def offset_in_byte(self) -> Count:
109 return self._offset_in_byte
110
111
d6483c83 112# An "align" operation.
2394a4b4 113class _AlignOp(_LeafOp):
1624d186
PP
114 def __init__(self, offset_in_byte: Count, ft: barectf_config._FieldType, names: List[str],
115 templates: _OpTemplates, value: Alignment):
d6483c83 116 super().__init__(offset_in_byte, ft, names, templates)
acfb8213 117 self._value = value
e5aa0be3 118
acfb8213 119 @property
1624d186 120 def value(self) -> Alignment:
acfb8213 121 return self._value
e5aa0be3 122
e5aa0be3 123
d6483c83 124# A "write" operation.
2394a4b4 125class _WriteOp(_LeafOp):
4810b707 126 pass
70e191bd 127
e5aa0be3 128
1624d186 129_SpecSerializeWriteTemplates = Mapping[str, barectf_template._Template]
1624d186
PP
130
131
2394a4b4 132# An operation builder.
d6483c83 133#
728fc4a7
PP
134# Such a builder is closely connected to a `_CodeGen` object using it to
135# find generic templates.
d6483c83 136#
2394a4b4
PP
137# Call build_for_root_ft() to make an operation builder create a
138# compound operation for a given root structure field type, recursively,
139# and return it.
140class _OpBuilder:
324b1c40 141 def __init__(self, cg: '_CodeGen'):
1624d186
PP
142 self._last_alignment: Optional[Alignment] = None
143 self._last_bit_array_size: Optional[Count] = None
1624d186
PP
144 self._names: List[str] = []
145 self._offset_in_byte = Count(0)
d6483c83 146 self._cg = cg
acfb8213 147
2394a4b4
PP
148 # Creates and returns an operation for the root structure field type
149 # `ft` named `name`.
d6483c83
PP
150 #
151 # `spec_serialize_write_templates` is a mapping of first level
152 # member names to specialized serialization "write" templates.
2394a4b4
PP
153 def build_for_root_ft(self, ft: barectf_config.StructureFieldType, name: str,
154 spec_serialize_write_templates: Optional[_SpecSerializeWriteTemplates] = None) -> _CompoundOp:
155 assert ft is not None
e5aa0be3 156
d6483c83
PP
157 if spec_serialize_write_templates is None:
158 spec_serialize_write_templates = {}
159
160 assert type(ft) is barectf_config.StructureFieldType
161 assert len(self._names) == 0
2394a4b4
PP
162 ops = self._build_for_ft(ft, name, spec_serialize_write_templates)
163 assert len(ops) == 1
164 assert type(ops[0]) is _CompoundOp
165 return typing.cast(_CompoundOp, ops[0])
d6483c83 166
2394a4b4 167 # Creates and returns the operation(s) for a given field type `ft`
d6483c83
PP
168 # named `name`.
169 #
2394a4b4
PP
170 # See build_for_root_ft() for `spec_serialize_write_templates`.
171 def _build_for_ft(self, ft: barectf_config._FieldType, name: str,
172 spec_serialize_write_templates: _SpecSerializeWriteTemplates) -> List[_Op]:
1624d186 173 def top_name() -> str:
d6483c83
PP
174 return self._names[-1]
175
2394a4b4
PP
176 # Creates and returns a "write" operation for the field type
177 # `ft`.
d6483c83
PP
178 #
179 # This function considers `spec_serialize_write_templates` to
180 # override generic templates.
2394a4b4 181 def create_write_op(ft: barectf_config._FieldType) -> _WriteOp:
d6483c83
PP
182 assert type(ft) is not barectf_config.StructureFieldType
183 offset_in_byte = self._offset_in_byte
184
185 if isinstance(ft, barectf_config._BitArrayFieldType):
1624d186 186 self._offset_in_byte = Count((self._offset_in_byte + ft.size) % 8)
d6483c83 187
1624d186 188 serialize_write_templ: Optional[barectf_template._Template] = None
d6483c83
PP
189
190 if len(self._names) == 2:
191 serialize_write_templ = spec_serialize_write_templates.get(top_name())
192
193 if serialize_write_templ is None:
194 if isinstance(ft, barectf_config._IntegerFieldType):
195 serialize_write_templ = self._cg._serialize_write_int_statements_templ
196 elif type(ft) is barectf_config.RealFieldType:
197 serialize_write_templ = self._cg._serialize_write_real_statements_templ
198 else:
199 assert type(ft) is barectf_config.StringFieldType
200 serialize_write_templ = self._cg._serialize_write_string_statements_templ
201
202 size_write_templ = None
e5aa0be3 203
d6483c83
PP
204 if isinstance(ft, barectf_config._BitArrayFieldType):
205 size_write_templ = self._cg._size_write_bit_array_statements_templ
206 elif type(ft) is barectf_config.StringFieldType:
207 size_write_templ = self._cg._size_write_string_statements_templ
208
2394a4b4
PP
209 return _WriteOp(offset_in_byte, ft, self._names,
210 _OpTemplates(serialize_write_templ, size_write_templ))
d6483c83 211
2394a4b4 212 # Creates and returns an "align" operation for the field type
d6483c83
PP
213 # `ft` if needed.
214 #
215 # This function updates the builder's state.
2394a4b4
PP
216 def try_create_align_op(alignment: Alignment, do_align: bool,
217 ft: barectf_config._FieldType) -> Optional[_AlignOp]:
1624d186
PP
218 def align(v: Count, alignment: Alignment) -> Count:
219 return Count((v + (alignment - 1)) & -alignment)
d6483c83
PP
220
221 offset_in_byte = self._offset_in_byte
1624d186 222 self._offset_in_byte = Count(align(self._offset_in_byte, alignment) % 8)
d6483c83
PP
223
224 if do_align and alignment > 1:
2394a4b4
PP
225 return _AlignOp(offset_in_byte, ft, self._names,
226 _OpTemplates(self._cg._serialize_align_statements_templ,
227 self._cg._size_align_statements_templ),
228 alignment)
229
230 return None
acfb8213 231
d6483c83
PP
232 # Returns whether or not, considering the alignment requirement
233 # `align_req` and the builder's current state, we must create
234 # and append an "align" operation.
1624d186
PP
235 def must_align(align_req: Alignment) -> bool:
236 return self._last_alignment != align_req or typing.cast(Count, self._last_bit_array_size) % align_req != 0
acfb8213 237
d6483c83
PP
238 # push field type's name to the builder's name stack initially
239 self._names.append(name)
acfb8213 240
2394a4b4
PP
241 # operations to return
242 ops: List[_Op] = []
243
4810b707 244 if isinstance(ft, (barectf_config.StringFieldType, barectf_config._ArrayFieldType)):
d6483c83
PP
245 assert type(ft) is barectf_config.StringFieldType or top_name() == 'uuid'
246
247 # strings and arrays are always byte-aligned
1624d186
PP
248 do_align = must_align(Alignment(8))
249 self._last_alignment = Alignment(8)
250 self._last_bit_array_size = Count(8)
2394a4b4
PP
251 op = try_create_align_op(Alignment(8), do_align, ft)
252
253 if op is not None:
254 ops.append(op)
255
256 ops.append(create_write_op(ft))
4810b707 257 else:
d6483c83 258 do_align = must_align(ft.alignment)
4810b707
PP
259 self._last_alignment = ft.alignment
260
261 if type(ft) is barectf_config.StructureFieldType:
2394a4b4 262 # reset last bit array size
1624d186 263 self._last_bit_array_size = typing.cast(Count, ft.alignment)
acfb8213 264 else:
1624d186
PP
265 assert isinstance(ft, barectf_config._BitArrayFieldType)
266 ft = typing.cast(barectf_config._BitArrayFieldType, ft)
4810b707 267 self._last_bit_array_size = ft.size
70e191bd 268
2394a4b4 269 init_align_op = try_create_align_op(ft.alignment, do_align, ft)
70e191bd 270
4810b707 271 if type(ft) is barectf_config.StructureFieldType:
1624d186 272 ft = typing.cast(barectf_config.StructureFieldType, ft)
2394a4b4
PP
273 subops: List[_Op] = []
274
275 if init_align_op is not None:
276 # append structure field's alignment as a suboperation
277 subops.append(init_align_op)
278
279 # append suboperations for each member
4810b707 280 for member_name, member in ft.members.items():
2394a4b4
PP
281 subops += self._build_for_ft(member.field_type, member_name,
282 spec_serialize_write_templates)
283
284 # create structre field's compound operation
285 ops.append(_CompoundOp(ft, self._names,
286 _OpTemplates(self._cg._serialize_write_struct_statements_templ,
287 self._cg._size_write_struct_statements_templ),
288 subops))
70e191bd 289 else:
2394a4b4
PP
290 # leaf field: align + write
291 if init_align_op is not None:
292 ops.append(init_align_op)
293
294 ops.append(create_write_op(ft))
d6483c83
PP
295
296 # exiting for this field type: pop its name
297 del self._names[-1]
70e191bd 298
2394a4b4
PP
299 return ops
300
301
302_OptCompoundOp = Optional[_CompoundOp]
303
70e191bd 304
d6483c83
PP
305# The operations for an event.
306#
307# The available operations are:
308#
2394a4b4
PP
309# * Specific context operation.
310# * Payload operation.
1624d186 311class _EvOps:
2394a4b4
PP
312 def __init__(self, spec_ctx_op: _OptCompoundOp, payload_op: _OptCompoundOp):
313 self._spec_ctx_op = spec_ctx_op
314 self._payload_op = payload_op
70e191bd 315
d6483c83 316 @property
2394a4b4
PP
317 def spec_ctx_op(self) -> _OptCompoundOp:
318 return self._spec_ctx_op
acfb8213 319
d6483c83 320 @property
2394a4b4
PP
321 def payload_op(self) -> _OptCompoundOp:
322 return self._payload_op
acfb8213 323
70e191bd 324
1624d186
PP
325_EvOpsMap = Mapping[barectf_config.EventType, _EvOps]
326
327
d6483c83
PP
328# The operations for a stream.
329#
330# The available operations are:
331#
2394a4b4
PP
332# * Packet header operation.
333# * Packet context operation.
334# * Event header operation.
335# * Event common context operation.
1624d186 336# * Event operations (`_EvOps`).
d6483c83 337class _StreamOps:
2394a4b4
PP
338 def __init__(self, pkt_header_op: _OptCompoundOp, pkt_ctx_op: _CompoundOp,
339 ev_header_op: _OptCompoundOp, ev_common_ctx_op: _OptCompoundOp, ev_ops: _EvOpsMap):
340 self._pkt_header_op = pkt_header_op
341 self._pkt_ctx_op = pkt_ctx_op
342 self._ev_header_op = ev_header_op
343 self._ev_common_ctx_op = ev_common_ctx_op
344 self._ev_ops = ev_ops
70e191bd 345
d6483c83 346 @property
2394a4b4
PP
347 def pkt_header_op(self) -> _OptCompoundOp:
348 return self._pkt_header_op
d6483c83
PP
349
350 @property
2394a4b4
PP
351 def pkt_ctx_op(self) -> _CompoundOp:
352 return self._pkt_ctx_op
d6483c83
PP
353
354 @property
2394a4b4
PP
355 def ev_header_op(self) -> _OptCompoundOp:
356 return self._ev_header_op
d6483c83
PP
357
358 @property
2394a4b4
PP
359 def ev_common_ctx_op(self) -> _OptCompoundOp:
360 return self._ev_common_ctx_op
d6483c83
PP
361
362 @property
1624d186 363 def ev_ops(self) -> _EvOpsMap:
d6483c83
PP
364 return self._ev_ops
365
366
367# The C variable name prefixes for the six kinds of root field types.
1b49c7b8 368class _RootFtPrefixes:
1c650e47
PP
369 PH = 'ph'
370 PC = 'pc'
371 EH = 'eh'
372 ECC = 'ecc'
373 SC = 'sc'
374 P = 'p'
d6483c83
PP
375
376
377# The human-readable names of the `_RootFtPrefixes` members.
378_ROOT_FT_PREFIX_NAMES = {
1c650e47
PP
379 _RootFtPrefixes.PH: 'packet header',
380 _RootFtPrefixes.PC: 'packet context',
381 _RootFtPrefixes.EH: 'event header',
382 _RootFtPrefixes.ECC: 'event common context',
383 _RootFtPrefixes.SC: 'specific context',
384 _RootFtPrefixes.P: 'payload',
acfb8213 385}
e5aa0be3
PP
386
387
d6483c83
PP
388# A named function parameter for a given field type.
389_FtParam = collections.namedtuple('_FtParam', ['ft', 'name'])
390
391
2d18e033
PP
392# C type abstract base class.
393class _CType:
394 def __init__(self, is_const: bool):
395 self._is_const = is_const
396
397 @property
398 def is_const(self) -> bool:
399 return self._is_const
400
401
402# Arithmetic C type.
403class _ArithCType(_CType):
404 def __init__(self, name: str, is_const: bool):
405 super().__init__(is_const)
406 self._name = name
407
408 @property
409 def name(self) -> str:
410 return self._name
411
412 def __str__(self) -> str:
413 return f'{"const " if self._is_const else ""}{self._name}'
414
415
416# Pointer C type.
417class _PointerCType(_CType):
418 def __init__(self, pointed_c_type: _CType, is_const: bool):
419 super().__init__(is_const)
420 self._pointed_c_type = pointed_c_type
421
422 @property
423 def pointed_c_type(self) -> _CType:
424 return self._pointed_c_type
425
426 def __str__(self) -> str:
427 s = str(self._pointed_c_type)
428
429 if not s.endswith('*'):
430 s += ' '
431
432 s += '*'
433
434 if self._is_const:
435 s += ' const'
436
437 return s
438
439
d6483c83
PP
440# A C code generator.
441#
442# Such a code generator can generate:
443#
728fc4a7
PP
444# * The bitfield header (gen_bitfield_header()).
445# * The public header (gen_header()).
446# * The source code (gen_src()).
447class _CodeGen:
1624d186 448 def __init__(self, cfg: barectf_config.Configuration):
e5aa0be3 449 self._cfg = cfg
d6483c83 450 self._iden_prefix = cfg.options.code_generation_options.identifier_prefix
1624d186 451 self._templ_filters: Mapping[str, Callable[..., Any]] = {
d6483c83
PP
452 'ft_c_type': self._ft_c_type,
453 'open_func_params_str': self._open_func_params_str,
454 'trace_func_params_str': self._trace_func_params_str,
455 'serialize_ev_common_ctx_func_params_str': self._serialize_ev_common_ctx_func_params_str,
1b49c7b8 456 }
d6483c83
PP
457 self._func_proto_params_templ = self._create_template('func-proto-params.j2')
458 self._serialize_align_statements_templ = self._create_template('serialize-align-statements.j2')
459 self._serialize_write_int_statements_templ = self._create_template('serialize-write-int-statements.j2')
460 self._serialize_write_real_statements_templ = self._create_template('serialize-write-real-statements.j2')
461 self._serialize_write_string_statements_templ = self._create_template('serialize-write-string-statements.j2')
2394a4b4 462 self._serialize_write_struct_statements_templ = self._create_template('serialize-write-struct-statements.j2')
d6483c83
PP
463 self._serialize_write_magic_statements_templ = self._create_template('serialize-write-magic-statements.j2')
464 self._serialize_write_uuid_statements_templ = self._create_template('serialize-write-uuid-statements.j2')
465 self._serialize_write_stream_type_id_statements_templ = self._create_template('serialize-write-stream-type-id-statements.j2')
466 self._serialize_write_time_statements_templ = self._create_template('serialize-write-time-statements.j2')
467 self._serialize_write_packet_size_statements_templ = self._create_template('serialize-write-packet-size-statements.j2')
468 self._serialize_write_skip_save_statements_templ = self._create_template('serialize-write-skip-save-statements.j2')
469 self._serialize_write_ev_type_id_statements_templ = self._create_template('serialize-write-ev-type-id-statements.j2')
470 self._size_align_statements_templ = self._create_template('size-align-statements.j2')
471 self._size_write_bit_array_statements_templ = self._create_template('size-write-bit-array-statements.j2')
472 self._size_write_string_statements_templ = self._create_template('size-write-string-statements.j2')
2394a4b4 473 self._size_write_struct_statements_templ = self._create_template('size-write-struct-statements.j2')
d6483c83
PP
474
475 # Creates and returns a template named `name` which is a file
476 # template if `is_file_template` is `True`.
477 #
478 # `name` is the file name, including the `.j2` extension, within the
479 # `c` directory.
480 #
481 # Such a template has the filters custom filters
482 # `self._templ_filters`.
1624d186
PP
483 def _create_template_base(self, name: str,
484 is_file_template: bool) -> barectf_template._Template:
d6483c83
PP
485 return barectf_template._Template(f'c/{name}', is_file_template, self._cfg,
486 self._templ_filters)
487
488 # Creates and returns a non-file template named `name`.
489 #
490 # See _create_template_base() for `name`.
8c7c6ed2 491 def _create_template(self, name: str) -> barectf_template._Template:
d6483c83 492 return self._create_template_base(name, False)
8c7c6ed2 493
d6483c83
PP
494 # Creates and returns a file template named `name`.
495 #
496 # See _create_template_base() for `name`.
8c7c6ed2 497 def _create_file_template(self, name: str) -> barectf_template._Template:
d6483c83 498 return self._create_template_base(name, True)
8c7c6ed2 499
d6483c83 500 # Trace type of this code generator's barectf configuration.
4810b707 501 @property
1624d186 502 def _trace_type(self) -> barectf_config.TraceType:
4810b707 503 return self._cfg.trace.type
27bc6f1e 504
2d18e033
PP
505 # Returns the C type for the field type `ft`, making it `const` if
506 # `is_const` is `True`.
507 def _ft_c_type(self, ft: barectf_config._FieldType, is_const: bool = False):
4810b707 508 if isinstance(ft, barectf_config._IntegerFieldType):
1624d186 509 ft = typing.cast(barectf_config._IntegerFieldType, ft)
4810b707
PP
510 sign_prefix = 'u' if isinstance(ft, barectf_config.UnsignedIntegerFieldType) else ''
511
512 if ft.size <= 8:
513 sz = 8
514 elif ft.size <= 16:
515 sz = 16
516 elif ft.size <= 32:
517 sz = 32
518 else:
d6483c83 519 assert ft.size <= 64
4810b707
PP
520 sz = 64
521
2d18e033 522 return _ArithCType(f'{sign_prefix}int{sz}_t', is_const)
4810b707 523 elif type(ft) is barectf_config.RealFieldType:
1624d186
PP
524 ft = typing.cast(barectf_config.RealFieldType, ft)
525
4810b707 526 if ft.size == 32 and ft.alignment == 32:
2d18e033 527 s = 'float'
4810b707 528 elif ft.size == 64 and ft.alignment == 64:
2d18e033 529 s = 'double'
4810b707 530 else:
2d18e033 531 s = 'uint64_t'
e18cf9d6 532
2d18e033 533 return _ArithCType(s, is_const)
e5aa0be3 534 else:
4810b707 535 assert type(ft) is barectf_config.StringFieldType
2d18e033 536 return _PointerCType(_ArithCType('char', True), is_const)
e5aa0be3 537
d6483c83
PP
538 # Returns the function prototype parameters for the members of the
539 # root structure field type `root_ft`.
540 #
541 # Each parameter has the prefix `name_prefix` followed with `_`.
542 #
543 # Members of which the name is in `exclude_set` are excluded.
1624d186
PP
544 def _proto_params_str(self, root_ft: Optional[barectf_config.StructureFieldType],
545 name_prefix: str, const_params: bool,
546 exclude_set: Optional[Set[str]] = None, only_dyn: bool = False) -> str:
d6483c83 547 if root_ft is None:
1624d186 548 return ''
e5aa0be3 549
4810b707
PP
550 if exclude_set is None:
551 exclude_set = set()
552
d6483c83 553 params = []
e5aa0be3 554
d6483c83 555 for member_name, member in root_ft.members.items():
4810b707 556 if member_name in exclude_set:
e5aa0be3
PP
557 continue
558
b622b24f
PP
559 if only_dyn and not member.field_type.size_is_dynamic:
560 continue
561
d6483c83 562 params.append(_FtParam(member.field_type, member_name))
e5aa0be3 563
e18cf9d6
PP
564 return self._func_proto_params_templ.render(params=params, prefix=name_prefix,
565 const_params=const_params)
4810b707 566
d6483c83
PP
567 # Returns the packet opening function prototype parameters for the
568 # stream type `stream_type`.
1624d186
PP
569 def _open_func_params_str(self, stream_type: barectf_config.StreamType,
570 const_params: bool) -> str:
d6483c83 571 parts = []
1c650e47 572 parts.append(self._proto_params_str(self._trace_type._pkt_header_ft, _RootFtPrefixes.PH,
e18cf9d6 573 const_params, {'magic', 'stream_id', 'uuid'}))
e5aa0be3 574
4810b707
PP
575 exclude_set = {
576 'timestamp_begin',
577 'timestamp_end',
578 'packet_size',
579 'content_size',
580 'events_discarded',
581 }
1c650e47 582 parts.append(self._proto_params_str(stream_type._pkt_ctx_ft, _RootFtPrefixes.PC,
e18cf9d6 583 const_params, exclude_set))
d6483c83 584 return ''.join(parts)
e5aa0be3 585
d6483c83
PP
586 # Returns the tracing function prototype parameters for the stream
587 # and event types `stream_ev_types`.
1624d186
PP
588 def _trace_func_params_str(self, stream_ev_types: Tuple[barectf_config.StreamType,
589 barectf_config.EventType],
590 const_params: bool, only_dyn: bool = False):
d6483c83
PP
591 stream_type = stream_ev_types[0]
592 ev_type = stream_ev_types[1]
593 parts = []
e5aa0be3 594
4810b707 595 if stream_type._ev_header_ft is not None:
1c650e47 596 parts.append(self._proto_params_str(stream_type._ev_header_ft, _RootFtPrefixes.EH,
b622b24f
PP
597 const_params, {'id', 'timestamp'},
598 only_dyn=only_dyn))
4810b707
PP
599
600 if stream_type.event_common_context_field_type is not None:
d6483c83 601 parts.append(self._proto_params_str(stream_type.event_common_context_field_type,
b622b24f
PP
602 _RootFtPrefixes.ECC, const_params,
603 only_dyn=only_dyn))
4810b707
PP
604
605 if ev_type.specific_context_field_type is not None:
d6483c83 606 parts.append(self._proto_params_str(ev_type.specific_context_field_type,
b622b24f
PP
607 _RootFtPrefixes.SC, const_params,
608 only_dyn=only_dyn))
4810b707
PP
609
610 if ev_type.payload_field_type is not None:
e18cf9d6 611 parts.append(self._proto_params_str(ev_type.payload_field_type, _RootFtPrefixes.P,
b622b24f 612 const_params, only_dyn=only_dyn))
e5aa0be3 613
d6483c83 614 return ''.join(parts)
4810b707 615
d6483c83
PP
616 # Returns the event header serialization function prototype
617 # parameters for the stream type `stream_type`.
1624d186
PP
618 def _serialize_ev_common_ctx_func_params_str(self, stream_type: barectf_config.StreamType,
619 const_params: bool) -> str:
d6483c83 620 return self._proto_params_str(stream_type.event_common_context_field_type,
324b1c40 621 _RootFtPrefixes.ECC, const_params)
e5aa0be3 622
d6483c83 623 # Generates the bitfield header file contents.
1624d186 624 def gen_bitfield_header(self) -> str:
d6483c83 625 return self._create_file_template('bitfield.h.j2').render()
e5aa0be3 626
d6483c83 627 # Generates the public header file contents.
1624d186 628 def gen_header(self) -> str:
d6483c83 629 return self._create_file_template('barectf.h.j2').render(root_ft_prefixes=_RootFtPrefixes)
3cb793a1 630
d6483c83 631 # Generates the source code file contents.
1624d186 632 def gen_src(self, header_file_name: str, bitfield_header_file_name: str) -> str:
d6483c83
PP
633 # Creates and returns the operations for all the stream and for
634 # all their events.
1624d186 635 def create_stream_ops() -> Mapping[barectf_config.StreamType, _StreamOps]:
d6483c83
PP
636 stream_ser_ops = {}
637
638 for stream_type in self._trace_type.stream_types:
2394a4b4
PP
639 pkt_header_ser_op = None
640 builder = _OpBuilder(self)
d6483c83
PP
641 pkt_header_ft = self._trace_type._pkt_header_ft
642
2394a4b4 643 # packet header operations
d6483c83
PP
644 if pkt_header_ft is not None:
645 spec_serialize_write_templates = {
646 'magic': self._serialize_write_magic_statements_templ,
647 'uuid': self._serialize_write_uuid_statements_templ,
648 'stream_id': self._serialize_write_stream_type_id_statements_templ,
649 }
2394a4b4
PP
650 pkt_header_ser_op = builder.build_for_root_ft(pkt_header_ft,
651 _RootFtPrefixes.PH,
652 spec_serialize_write_templates)
d6483c83 653
2394a4b4 654 # packet context operations
d6483c83
PP
655 spec_serialize_write_templates = {
656 'timestamp_begin': self._serialize_write_time_statements_templ,
657 'packet_size': self._serialize_write_packet_size_statements_templ,
658 'timestamp_end': self._serialize_write_skip_save_statements_templ,
659 'events_discarded': self._serialize_write_skip_save_statements_templ,
660 'content_size': self._serialize_write_skip_save_statements_templ,
661 }
2394a4b4
PP
662 pkt_ctx_ser_op = builder.build_for_root_ft(stream_type._pkt_ctx_ft,
663 _RootFtPrefixes.PC,
664 spec_serialize_write_templates)
d6483c83 665
2394a4b4
PP
666 # event header operationss
667 builder = _OpBuilder(self)
668 ev_header_ser_op = None
d6483c83
PP
669
670 if stream_type._ev_header_ft is not None:
671 spec_serialize_write_templates = {
672 'timestamp': self._serialize_write_time_statements_templ,
673 'id': self._serialize_write_ev_type_id_statements_templ,
674 }
2394a4b4
PP
675 ev_header_ser_op = builder.build_for_root_ft(stream_type._ev_header_ft,
676 _RootFtPrefixes.EH,
677 spec_serialize_write_templates)
d6483c83 678
2394a4b4
PP
679 # event common context operations
680 ev_common_ctx_ser_op = None
d6483c83
PP
681
682 if stream_type.event_common_context_field_type is not None:
2394a4b4
PP
683 ev_common_ctx_ser_op = builder.build_for_root_ft(stream_type.event_common_context_field_type,
684 _RootFtPrefixes.ECC)
d6483c83 685
2394a4b4 686 # operations specific to each event type
d6483c83
PP
687 ev_ser_ops = {}
688
689 for ev_type in stream_type.event_types:
690 ev_builder = copy.copy(builder)
691
2394a4b4
PP
692 # specific context operations
693 spec_ctx_ser_op = None
d6483c83
PP
694
695 if ev_type.specific_context_field_type is not None:
2394a4b4
PP
696 spec_ctx_ser_op = ev_builder.build_for_root_ft(ev_type.specific_context_field_type,
697 _RootFtPrefixes.SC)
d6483c83 698
2394a4b4
PP
699 # payload operations
700 payload_ser_op = None
d6483c83
PP
701
702 if ev_type.payload_field_type is not None:
2394a4b4
PP
703 payload_ser_op = ev_builder.build_for_root_ft(ev_type.payload_field_type,
704 _RootFtPrefixes.P)
d6483c83 705
2394a4b4 706 ev_ser_ops[ev_type] = _EvOps(spec_ctx_ser_op, payload_ser_op)
d6483c83 707
2394a4b4
PP
708 stream_ser_ops[stream_type] = _StreamOps(pkt_header_ser_op, pkt_ctx_ser_op,
709 ev_header_ser_op, ev_common_ctx_ser_op,
d6483c83
PP
710 ev_ser_ops)
711
712 return stream_ser_ops
713
714 # Returns the "write" operation for the packet context member
715 # named `member_name` within the stream type `stream_type`.
1624d186
PP
716 def stream_op_pkt_ctx_op(stream_type: barectf_config.StreamType, member_name: str) -> _Op:
717 ret_op = None
718
2394a4b4 719 for op in stream_ops[stream_type].pkt_ctx_op.subops:
d6483c83 720 if op.top_name == member_name and type(op) is _WriteOp:
1624d186
PP
721 ret_op = op
722 break
723
724 assert ret_op is not None
725 return typing.cast(_Op, ret_op)
d6483c83
PP
726
727 stream_ops = create_stream_ops()
c268d669
PP
728 c_src = self._create_file_template('barectf.c.j2').render(header_file_name=header_file_name,
729 bitfield_header_file_name=bitfield_header_file_name,
730 root_ft_prefixes=_RootFtPrefixes,
731 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES,
732 stream_ops=stream_ops,
733 stream_op_pkt_ctx_op=stream_op_pkt_ctx_op)
734
735 # Jinja 2 makes it hard to have multiple contiguous blocks
736 # delimited with empty lines when using a for loop, while not
737 # also having an empty line at the end.
738 #
739 # Therefore, we often get this rendered pattern:
740 #
741 # /* ... */
742 # ...;
743 # ...;
744 #
745 # /* ... */
746 # ...;
747 # ...;
748 # ...;
749 #
750 # }
751 #
752 # It's ugly, so fix it here.
753 return re.sub(r'(\n)\s*\n(\s*})', r'\1\2', c_src)
This page took 0.093865 seconds and 4 git commands to generate.