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