docs: cleanup: Rephrase and correct typos
[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
1624d186
PP
28from typing import List, Optional, Mapping, Callable, Any, Set, Tuple
29import typing
30from barectf.typing import Count, Alignment
4810b707
PP
31
32
d6483c83
PP
33# A tuple containing serialization and size computation function
34# templates for a given operation.
35_OpTemplates = collections.namedtuple('_OpTemplates', ['serialize', 'size'])
70e191bd
PP
36
37
2394a4b4 38# Abstract base class of any operation within source code.
d6483c83
PP
39#
40# Any operation has:
41#
d6483c83
PP
42# * A field type.
43#
2394a4b4
PP
44# * A list of names which, when joined with `_`, form the generic
45# C source variable name.
d6483c83 46#
6bc97055
PP
47# * A level: how deep this operation is within the operation tree.
48#
d6483c83
PP
49# * Serialization and size computation templates to generate the
50# operation's source code for those functions.
51class _Op:
6bc97055
PP
52 def __init__(self, ft: barectf_config._FieldType, names: List[str], level: Count,
53 templates: _OpTemplates):
4810b707 54 self._ft = ft
d6483c83 55 self._names = copy.copy(names)
6bc97055 56 self._level = level
d6483c83 57 self._templates = templates
e5aa0be3 58
acfb8213 59 @property
1624d186 60 def ft(self) -> barectf_config._FieldType:
4810b707 61 return self._ft
acfb8213
PP
62
63 @property
1624d186 64 def names(self) -> List[str]:
acfb8213 65 return self._names
e5aa0be3 66
6bc97055
PP
67 @property
68 def level(self) -> Count:
69 return self._level
70
d6483c83 71 @property
1624d186 72 def top_name(self) -> str:
d6483c83 73 return self._names[-1]
e5aa0be3 74
1624d186 75 def _render_template(self, templ: barectf_template._Template, **kwargs) -> str:
d6483c83
PP
76 return templ.render(op=self, root_ft_prefixes=_RootFtPrefixes,
77 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, **kwargs)
78
1624d186 79 def serialize_str(self, **kwargs) -> str:
d6483c83
PP
80 return self._render_template(self._templates.serialize, **kwargs)
81
1624d186 82 def size_str(self, **kwargs) -> str:
d6483c83
PP
83 return self._render_template(self._templates.size, **kwargs)
84
85
2394a4b4
PP
86# Compound operation.
87#
88# A compound operation contains a list of suboperations (leaf or
89# compound).
90#
91# Get the suboperations of a compound operation with its `subops`
92# property.
93#
94# The templates of a compound operation handles its suboperations.
95class _CompoundOp(_Op):
6bc97055 96 def __init__(self, ft: barectf_config._FieldType, names: List[str], level: Count,
cfee1573 97 templates: _OpTemplates, subops: Optional[List[Any]] = None):
6bc97055 98 super().__init__(ft, names, level, templates)
2394a4b4
PP
99 self._subops = subops
100
101 @property
102 def subops(self):
103 return self._subops
104
105
106# Leaf operation (abstract class).
107class _LeafOp(_Op):
be9f12dc 108 pass
2394a4b4
PP
109
110
d6483c83 111# An "align" operation.
2394a4b4 112class _AlignOp(_LeafOp):
be9f12dc
PP
113 def __init__(self, ft: barectf_config._FieldType, names: List[str], level: Count,
114 templates: _OpTemplates, value: Alignment):
115 super().__init__(ft, names, level, templates)
acfb8213 116 self._value = value
e5aa0be3 117
acfb8213 118 @property
1624d186 119 def value(self) -> Alignment:
acfb8213 120 return self._value
e5aa0be3 121
e5aa0be3 122
d6483c83 123# A "write" operation.
2394a4b4 124class _WriteOp(_LeafOp):
be9f12dc
PP
125 def __init__(self, ft: barectf_config._FieldType, names: List[str], level: Count,
126 templates: _OpTemplates, offset_in_byte: Optional[Count]):
127 super().__init__(ft, names, level, templates)
128 assert offset_in_byte is None or (offset_in_byte >= 0 and offset_in_byte < 8)
129 self._offset_in_byte = offset_in_byte
130
131 @property
132 def offset_in_byte(self) -> Optional[Count]:
133 return self._offset_in_byte
70e191bd 134
e5aa0be3 135
1624d186 136_SpecSerializeWriteTemplates = Mapping[str, barectf_template._Template]
1624d186
PP
137
138
2394a4b4 139# An operation builder.
d6483c83 140#
728fc4a7
PP
141# Such a builder is closely connected to a `_CodeGen` object using it to
142# find generic templates.
d6483c83 143#
2394a4b4
PP
144# Call build_for_root_ft() to make an operation builder create a
145# compound operation for a given root structure field type, recursively,
146# and return it.
147class _OpBuilder:
324b1c40 148 def __init__(self, cg: '_CodeGen'):
1624d186 149 self._names: List[str] = []
6bc97055 150 self._level = Count(0)
be9f12dc 151 self._offset_in_byte: Optional[Count] = None
d6483c83 152 self._cg = cg
acfb8213 153
be9f12dc
PP
154 # Whether or not we're within an array operation.
155 @property
156 def _in_array(self):
157 return self._level > 0
158
2394a4b4
PP
159 # Creates and returns an operation for the root structure field type
160 # `ft` named `name`.
d6483c83
PP
161 #
162 # `spec_serialize_write_templates` is a mapping of first level
163 # member names to specialized serialization "write" templates.
2394a4b4
PP
164 def build_for_root_ft(self, ft: barectf_config.StructureFieldType, name: str,
165 spec_serialize_write_templates: Optional[_SpecSerializeWriteTemplates] = None) -> _CompoundOp:
166 assert ft is not None
e5aa0be3 167
d6483c83
PP
168 if spec_serialize_write_templates is None:
169 spec_serialize_write_templates = {}
170
171 assert type(ft) is barectf_config.StructureFieldType
172 assert len(self._names) == 0
6bc97055 173 assert self._level == 0
2394a4b4
PP
174 ops = self._build_for_ft(ft, name, spec_serialize_write_templates)
175 assert len(ops) == 1
176 assert type(ops[0]) is _CompoundOp
177 return typing.cast(_CompoundOp, ops[0])
d6483c83 178
2394a4b4 179 # Creates and returns the operation(s) for a given field type `ft`
d6483c83
PP
180 # named `name`.
181 #
2394a4b4
PP
182 # See build_for_root_ft() for `spec_serialize_write_templates`.
183 def _build_for_ft(self, ft: barectf_config._FieldType, name: str,
184 spec_serialize_write_templates: _SpecSerializeWriteTemplates) -> List[_Op]:
1624d186 185 def top_name() -> str:
d6483c83
PP
186 return self._names[-1]
187
2394a4b4
PP
188 # Creates and returns a "write" operation for the field type
189 # `ft`.
d6483c83
PP
190 #
191 # This function considers `spec_serialize_write_templates` to
192 # override generic templates.
2394a4b4 193 def create_write_op(ft: barectf_config._FieldType) -> _WriteOp:
d6483c83
PP
194 assert type(ft) is not barectf_config.StructureFieldType
195 offset_in_byte = self._offset_in_byte
196
be9f12dc 197 if isinstance(ft, barectf_config._BitArrayFieldType) and self._offset_in_byte is not None:
1624d186 198 self._offset_in_byte = Count((self._offset_in_byte + ft.size) % 8)
d6483c83 199
1624d186 200 serialize_write_templ: Optional[barectf_template._Template] = None
d6483c83
PP
201
202 if len(self._names) == 2:
203 serialize_write_templ = spec_serialize_write_templates.get(top_name())
204
205 if serialize_write_templ is None:
206 if isinstance(ft, barectf_config._IntegerFieldType):
207 serialize_write_templ = self._cg._serialize_write_int_statements_templ
208 elif type(ft) is barectf_config.RealFieldType:
209 serialize_write_templ = self._cg._serialize_write_real_statements_templ
210 else:
211 assert type(ft) is barectf_config.StringFieldType
212 serialize_write_templ = self._cg._serialize_write_string_statements_templ
213
214 size_write_templ = None
e5aa0be3 215
d6483c83
PP
216 if isinstance(ft, barectf_config._BitArrayFieldType):
217 size_write_templ = self._cg._size_write_bit_array_statements_templ
218 elif type(ft) is barectf_config.StringFieldType:
219 size_write_templ = self._cg._size_write_string_statements_templ
220
be9f12dc
PP
221 return _WriteOp(ft, self._names, self._level,
222 _OpTemplates(serialize_write_templ, size_write_templ), offset_in_byte)
d6483c83 223
2394a4b4 224 # Creates and returns an "align" operation for the field type
d6483c83
PP
225 # `ft` if needed.
226 #
227 # This function updates the builder's state.
be9f12dc 228 def try_create_align_op(alignment: Alignment, ft: barectf_config._FieldType) -> Optional[_AlignOp]:
1624d186
PP
229 def align(v: Count, alignment: Alignment) -> Count:
230 return Count((v + (alignment - 1)) & -alignment)
d6483c83 231
be9f12dc
PP
232 if self._offset_in_byte is None and alignment % 8 == 0:
233 self._offset_in_byte = Count(0)
234 else:
235 if self._in_array:
236 self._offset_in_byte = None
237 elif self._offset_in_byte is not None:
238 self._offset_in_byte = Count(align(self._offset_in_byte, alignment) % 8)
d6483c83 239
be9f12dc
PP
240 if alignment > 1:
241 return _AlignOp(ft, self._names, self._level,
2394a4b4
PP
242 _OpTemplates(self._cg._serialize_align_statements_templ,
243 self._cg._size_align_statements_templ),
244 alignment)
245
246 return None
acfb8213 247
6bc97055
PP
248 # Returns whether or not `ft` is a compound field type.
249 def ft_is_compound(ft: barectf_config._FieldType) -> bool:
250 return isinstance(ft, (barectf_config.StructureFieldType, barectf_config.StaticArrayFieldType))
251
d6483c83
PP
252 # push field type's name to the builder's name stack initially
253 self._names.append(name)
acfb8213 254
2394a4b4
PP
255 # operations to return
256 ops: List[_Op] = []
257
be9f12dc 258 if type(ft) is barectf_config.StringFieldType or self._names == [_RootFtPrefixes.PH, 'uuid']:
6bc97055 259 # strings and UUID array are always byte-aligned
be9f12dc 260 op = try_create_align_op(Alignment(8), ft)
2394a4b4
PP
261
262 if op is not None:
263 ops.append(op)
264
265 ops.append(create_write_op(ft))
4810b707 266 else:
6bc97055 267 if ft_is_compound(ft):
be9f12dc 268 self._offset_in_byte = None
70e191bd 269
be9f12dc 270 init_align_op = try_create_align_op(ft.alignment, ft)
6bc97055 271 subops: List[_Op] = []
70e191bd 272
4810b707 273 if type(ft) is barectf_config.StructureFieldType:
1624d186 274 ft = typing.cast(barectf_config.StructureFieldType, ft)
2394a4b4
PP
275
276 if init_align_op is not None:
be9f12dc
PP
277 # Append structure field's alignment as a
278 # suboperation.
279 #
280 # This is not strictly needed (could be appended to
e8f0d548
PP
281 # `ops`), but the properties of `_DsOps` and
282 # `_ErOps` offer a single (structure field type)
be9f12dc 283 # operation.
2394a4b4
PP
284 subops.append(init_align_op)
285
286 # append suboperations for each member
4810b707 287 for member_name, member in ft.members.items():
2394a4b4
PP
288 subops += self._build_for_ft(member.field_type, member_name,
289 spec_serialize_write_templates)
290
6bc97055
PP
291 # create structure field's compound operation
292 ops.append(_CompoundOp(ft, self._names, self._level,
2394a4b4
PP
293 _OpTemplates(self._cg._serialize_write_struct_statements_templ,
294 self._cg._size_write_struct_statements_templ),
6bc97055 295 subops))
be9f12dc
PP
296 elif isinstance(ft, barectf_config._ArrayFieldType):
297 ft = typing.cast(barectf_config._ArrayFieldType, ft)
298 assert ft.alignment == 1 or init_align_op is not None
6bc97055
PP
299
300 if init_align_op is not None:
be9f12dc 301 ops.append(init_align_op)
6bc97055
PP
302
303 # append element's suboperations
304 self._level = Count(self._level + 1)
305 subops += self._build_for_ft(ft.element_field_type,
306 f'[{_loop_var_name(Count(self._level - 1))}]',
307 spec_serialize_write_templates)
308 self._level = Count(self._level - 1)
309
be9f12dc
PP
310 # select the right templates
311 if type(ft) is barectf_config.StaticArrayFieldType:
312 templates = _OpTemplates(self._cg._serialize_write_static_array_statements_templ,
313 self._cg._size_write_static_array_statements_templ)
314 else:
315 assert type(ft) is barectf_config.DynamicArrayFieldType
316 templates = _OpTemplates(self._cg._serialize_write_dynamic_array_statements_templ,
317 self._cg._size_write_dynamic_array_statements_templ)
318
319 # create array field's compound operation
320 ops.append(_CompoundOp(ft, self._names, self._level, templates, subops))
70e191bd 321 else:
2394a4b4
PP
322 # leaf field: align + write
323 if init_align_op is not None:
324 ops.append(init_align_op)
325
326 ops.append(create_write_op(ft))
d6483c83
PP
327
328 # exiting for this field type: pop its name
329 del self._names[-1]
70e191bd 330
2394a4b4
PP
331 return ops
332
333
334_OptCompoundOp = Optional[_CompoundOp]
335
70e191bd 336
e8f0d548 337# The operations for an event record.
d6483c83
PP
338#
339# The available operations are:
340#
2394a4b4
PP
341# * Specific context operation.
342# * Payload operation.
e8f0d548 343class _ErOps:
2394a4b4
PP
344 def __init__(self, spec_ctx_op: _OptCompoundOp, payload_op: _OptCompoundOp):
345 self._spec_ctx_op = spec_ctx_op
346 self._payload_op = payload_op
70e191bd 347
d6483c83 348 @property
2394a4b4
PP
349 def spec_ctx_op(self) -> _OptCompoundOp:
350 return self._spec_ctx_op
acfb8213 351
d6483c83 352 @property
2394a4b4
PP
353 def payload_op(self) -> _OptCompoundOp:
354 return self._payload_op
acfb8213 355
70e191bd 356
e8f0d548 357_ErOpsMap = Mapping[barectf_config.EventRecordType, _ErOps]
1624d186
PP
358
359
e8f0d548 360# The operations for a data stream.
d6483c83
PP
361#
362# The available operations are:
363#
2394a4b4
PP
364# * Packet header operation.
365# * Packet context operation.
e8f0d548
PP
366# * Event record header operation.
367# * Event record common context operation.
368# * Event record operations (`_ErOps`).
369class _DsOps:
2394a4b4 370 def __init__(self, pkt_header_op: _OptCompoundOp, pkt_ctx_op: _CompoundOp,
e8f0d548 371 er_header_op: _OptCompoundOp, er_common_ctx_op: _OptCompoundOp, er_ops: _ErOpsMap):
2394a4b4
PP
372 self._pkt_header_op = pkt_header_op
373 self._pkt_ctx_op = pkt_ctx_op
e8f0d548
PP
374 self._er_header_op = er_header_op
375 self._er_common_ctx_op = er_common_ctx_op
376 self._er_ops = er_ops
70e191bd 377
d6483c83 378 @property
2394a4b4
PP
379 def pkt_header_op(self) -> _OptCompoundOp:
380 return self._pkt_header_op
d6483c83
PP
381
382 @property
2394a4b4
PP
383 def pkt_ctx_op(self) -> _CompoundOp:
384 return self._pkt_ctx_op
d6483c83
PP
385
386 @property
e8f0d548
PP
387 def er_header_op(self) -> _OptCompoundOp:
388 return self._er_header_op
d6483c83
PP
389
390 @property
e8f0d548
PP
391 def er_common_ctx_op(self) -> _OptCompoundOp:
392 return self._er_common_ctx_op
d6483c83
PP
393
394 @property
e8f0d548
PP
395 def er_ops(self) -> _ErOpsMap:
396 return self._er_ops
d6483c83
PP
397
398
399# The C variable name prefixes for the six kinds of root field types.
1b49c7b8 400class _RootFtPrefixes:
1c650e47
PP
401 PH = 'ph'
402 PC = 'pc'
a7e54146
PP
403 ERH = 'h'
404 ERCC = 'cc'
405 ERSC = 'sc'
406 ERP = 'p'
d6483c83
PP
407
408
409# The human-readable names of the `_RootFtPrefixes` members.
410_ROOT_FT_PREFIX_NAMES = {
1c650e47
PP
411 _RootFtPrefixes.PH: 'packet header',
412 _RootFtPrefixes.PC: 'packet context',
a7e54146
PP
413 _RootFtPrefixes.ERH: 'header',
414 _RootFtPrefixes.ERCC: 'common context',
415 _RootFtPrefixes.ERSC: 'specific context',
416 _RootFtPrefixes.ERP: 'payload',
acfb8213 417}
e5aa0be3
PP
418
419
d6483c83
PP
420# A named function parameter for a given field type.
421_FtParam = collections.namedtuple('_FtParam', ['ft', 'name'])
422
423
2d18e033
PP
424# C type abstract base class.
425class _CType:
426 def __init__(self, is_const: bool):
427 self._is_const = is_const
428
429 @property
430 def is_const(self) -> bool:
431 return self._is_const
432
433
434# Arithmetic C type.
435class _ArithCType(_CType):
436 def __init__(self, name: str, is_const: bool):
437 super().__init__(is_const)
438 self._name = name
439
440 @property
441 def name(self) -> str:
442 return self._name
443
444 def __str__(self) -> str:
445 return f'{"const " if self._is_const else ""}{self._name}'
446
447
448# Pointer C type.
449class _PointerCType(_CType):
450 def __init__(self, pointed_c_type: _CType, is_const: bool):
451 super().__init__(is_const)
452 self._pointed_c_type = pointed_c_type
453
454 @property
455 def pointed_c_type(self) -> _CType:
456 return self._pointed_c_type
457
458 def __str__(self) -> str:
459 s = str(self._pointed_c_type)
460
461 if not s.endswith('*'):
462 s += ' '
463
464 s += '*'
465
466 if self._is_const:
467 s += ' const'
468
469 return s
470
471
6bc97055
PP
472# Returns the name of a loop variable given a nesting level `level`.
473def _loop_var_name(level: Count) -> str:
474 if level < 3:
475 return 'ijk'[level]
476
477 return f'k{level - 2}'
478
479
d6483c83
PP
480# A C code generator.
481#
482# Such a code generator can generate:
483#
728fc4a7
PP
484# * The bitfield header (gen_bitfield_header()).
485# * The public header (gen_header()).
486# * The source code (gen_src()).
487class _CodeGen:
1624d186 488 def __init__(self, cfg: barectf_config.Configuration):
e5aa0be3 489 self._cfg = cfg
d6483c83 490 self._iden_prefix = cfg.options.code_generation_options.identifier_prefix
1624d186 491 self._templ_filters: Mapping[str, Callable[..., Any]] = {
d6483c83
PP
492 'ft_c_type': self._ft_c_type,
493 'open_func_params_str': self._open_func_params_str,
494 'trace_func_params_str': self._trace_func_params_str,
e8f0d548 495 'serialize_er_common_ctx_func_params_str': self._serialize_er_common_ctx_func_params_str,
6bc97055
PP
496 'loop_var_name': _loop_var_name,
497 'op_src_var_name': self._op_src_var_name,
1b49c7b8 498 }
d6483c83
PP
499 self._func_proto_params_templ = self._create_template('func-proto-params.j2')
500 self._serialize_align_statements_templ = self._create_template('serialize-align-statements.j2')
501 self._serialize_write_int_statements_templ = self._create_template('serialize-write-int-statements.j2')
502 self._serialize_write_real_statements_templ = self._create_template('serialize-write-real-statements.j2')
503 self._serialize_write_string_statements_templ = self._create_template('serialize-write-string-statements.j2')
2394a4b4 504 self._serialize_write_struct_statements_templ = self._create_template('serialize-write-struct-statements.j2')
6bc97055 505 self._serialize_write_static_array_statements_templ = self._create_template('serialize-write-static-array-statements.j2')
be9f12dc 506 self._serialize_write_dynamic_array_statements_templ = self._create_template('serialize-write-dynamic-array-statements.j2')
d6483c83
PP
507 self._serialize_write_magic_statements_templ = self._create_template('serialize-write-magic-statements.j2')
508 self._serialize_write_uuid_statements_templ = self._create_template('serialize-write-uuid-statements.j2')
e8f0d548 509 self._serialize_write_dst_id_statements_templ = self._create_template('serialize-write-dst-id-statements.j2')
462e49b3 510 self._serialize_write_timestamp_statements_templ = self._create_template('serialize-write-timestamp-statements.j2')
d6483c83 511 self._serialize_write_packet_size_statements_templ = self._create_template('serialize-write-packet-size-statements.j2')
af09c4fc 512 self._serialize_write_seq_num_statements_templ = self._create_template('serialize-write-seq-num-statements.j2')
d6483c83 513 self._serialize_write_skip_save_statements_templ = self._create_template('serialize-write-skip-save-statements.j2')
e8f0d548 514 self._serialize_write_ert_id_statements_templ = self._create_template('serialize-write-ert-id-statements.j2')
d6483c83
PP
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
a209cf4d 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 635 # Returns the packet opening function prototype parameters for the
e8f0d548
PP
636 # data stream type `dst`.
637 def _open_func_params_str(self, dst: barectf_config.DataStreamType, const_params: bool) -> str:
d6483c83 638 parts = []
1c650e47 639 parts.append(self._proto_params_str(self._trace_type._pkt_header_ft, _RootFtPrefixes.PH,
e18cf9d6 640 const_params, {'magic', 'stream_id', 'uuid'}))
e5aa0be3 641
4810b707
PP
642 exclude_set = {
643 'timestamp_begin',
644 'timestamp_end',
645 'packet_size',
646 'content_size',
647 'events_discarded',
af09c4fc 648 'packet_seq_num',
4810b707 649 }
e8f0d548
PP
650 parts.append(self._proto_params_str(dst._pkt_ctx_ft, _RootFtPrefixes.PC, const_params,
651 exclude_set))
d6483c83 652 return ''.join(parts)
e5aa0be3 653
e8f0d548
PP
654 # Returns the tracing function prototype parameters for the data
655 # stream and event record types `ds_er_types`.
656 def _trace_func_params_str(self, ds_er_types: Tuple[barectf_config.DataStreamType,
657 barectf_config.EventRecordType],
1624d186 658 const_params: bool, only_dyn: bool = False):
e8f0d548
PP
659 dst = ds_er_types[0]
660 ert = ds_er_types[1]
d6483c83 661 parts = []
e5aa0be3 662
e8f0d548
PP
663 if dst._er_header_ft is not None:
664 parts.append(self._proto_params_str(dst._er_header_ft, _RootFtPrefixes.ERH,
b622b24f
PP
665 const_params, {'id', 'timestamp'},
666 only_dyn=only_dyn))
4810b707 667
e8f0d548
PP
668 if dst.event_record_common_context_field_type is not None:
669 parts.append(self._proto_params_str(dst.event_record_common_context_field_type,
670 _RootFtPrefixes.ERCC, const_params,
b622b24f 671 only_dyn=only_dyn))
4810b707 672
e8f0d548
PP
673 if ert.specific_context_field_type is not None:
674 parts.append(self._proto_params_str(ert.specific_context_field_type,
a7e54146 675 _RootFtPrefixes.ERSC, const_params,
b622b24f 676 only_dyn=only_dyn))
4810b707 677
e8f0d548 678 if ert.payload_field_type is not None:
a7e54146 679 parts.append(self._proto_params_str(ert.payload_field_type, _RootFtPrefixes.ERP,
b622b24f 680 const_params, only_dyn=only_dyn))
e5aa0be3 681
d6483c83 682 return ''.join(parts)
4810b707 683
e8f0d548
PP
684 # Returns the event record common context serialization function
685 # prototype parameters for the data stream type `dst`.
686 def _serialize_er_common_ctx_func_params_str(self, dst: barectf_config.DataStreamType,
1624d186 687 const_params: bool) -> str:
e8f0d548
PP
688 return self._proto_params_str(dst.event_record_common_context_field_type,
689 _RootFtPrefixes.ERCC, 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:
e8f0d548
PP
701 # Creates and returns the operations for all the data stream and
702 # for all their event records.
703 def create_ds_ops() -> Mapping[barectf_config.DataStreamType, _DsOps]:
704 ds_ops = {}
d6483c83 705
e8f0d548
PP
706 for dst in self._trace_type.data_stream_types:
707 pkt_header_op = None
2394a4b4 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,
e8f0d548 716 'stream_id': self._serialize_write_dst_id_statements_templ,
d6483c83 717 }
e8f0d548 718 pkt_header_op = builder.build_for_root_ft(pkt_header_ft,
2394a4b4
PP
719 _RootFtPrefixes.PH,
720 spec_serialize_write_templates)
d6483c83 721
e8f0d548 722 # packet context operation
d6483c83 723 spec_serialize_write_templates = {
462e49b3 724 'timestamp_begin': self._serialize_write_timestamp_statements_templ,
d6483c83
PP
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,
af09c4fc 729 'packet_seq_num': self._serialize_write_seq_num_statements_templ,
d6483c83 730 }
e8f0d548
PP
731 pkt_ctx_op = builder.build_for_root_ft(dst._pkt_ctx_ft, _RootFtPrefixes.PC,
732 spec_serialize_write_templates)
d6483c83 733
e8f0d548 734 # event record header operation
2394a4b4 735 builder = _OpBuilder(self)
e8f0d548 736 er_header_op = None
d6483c83 737
e8f0d548 738 if dst._er_header_ft is not None:
d6483c83 739 spec_serialize_write_templates = {
462e49b3 740 'timestamp': self._serialize_write_timestamp_statements_templ,
e8f0d548 741 'id': self._serialize_write_ert_id_statements_templ,
d6483c83 742 }
e8f0d548
PP
743 er_header_op = builder.build_for_root_ft(dst._er_header_ft, _RootFtPrefixes.ERH,
744 spec_serialize_write_templates)
d6483c83 745
e8f0d548
PP
746 # event record common context operation
747 er_common_ctx_op = None
d6483c83 748
e8f0d548
PP
749 if dst.event_record_common_context_field_type is not None:
750 er_common_ctx_op = builder.build_for_root_ft(dst.event_record_common_context_field_type,
751 _RootFtPrefixes.ERCC)
d6483c83 752
e8f0d548
PP
753 # operations specific to each event record type
754 er_ops = {}
d6483c83 755
e8f0d548 756 for ert in dst.event_record_types:
d6483c83
PP
757 ev_builder = copy.copy(builder)
758
e8f0d548
PP
759 # specific context operation
760 spec_ctx_op = None
d6483c83 761
e8f0d548
PP
762 if ert.specific_context_field_type is not None:
763 spec_ctx_op = ev_builder.build_for_root_ft(ert.specific_context_field_type,
a7e54146 764 _RootFtPrefixes.ERSC)
d6483c83 765
e8f0d548
PP
766 # payload operation
767 payload_op = None
d6483c83 768
e8f0d548
PP
769 if ert.payload_field_type is not None:
770 payload_op = ev_builder.build_for_root_ft(ert.payload_field_type,
a7e54146 771 _RootFtPrefixes.ERP)
d6483c83 772
e8f0d548 773 er_ops[ert] = _ErOps(spec_ctx_op, payload_op)
d6483c83 774
e8f0d548
PP
775 ds_ops[dst] = _DsOps(pkt_header_op, pkt_ctx_op, er_header_op, er_common_ctx_op,
776 er_ops)
d6483c83 777
e8f0d548 778 return ds_ops
d6483c83
PP
779
780 # Returns the "write" operation for the packet context member
e8f0d548
PP
781 # named `member_name` within the data stream type `dst`.
782 def ds_op_pkt_ctx_op(dst: barectf_config.DataStreamType, member_name: str) -> _Op:
1624d186
PP
783 ret_op = None
784
e8f0d548 785 for op in ds_ops[dst].pkt_ctx_op.subops:
d6483c83 786 if op.top_name == member_name and type(op) is _WriteOp:
1624d186
PP
787 ret_op = op
788 break
789
790 assert ret_op is not None
791 return typing.cast(_Op, ret_op)
d6483c83 792
e8f0d548 793 ds_ops = create_ds_ops()
f42a1daf
PP
794 return self._create_file_template('barectf.c.j2').render(header_file_name=header_file_name,
795 bitfield_header_file_name=bitfield_header_file_name,
796 root_ft_prefixes=_RootFtPrefixes,
797 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES,
798 ds_ops=ds_ops,
799 ds_op_pkt_ctx_op=ds_op_pkt_ctx_op)
This page took 0.070268 seconds and 4 git commands to generate.