1 # The MIT License (MIT)
3 # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
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:
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
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.
24 import barectf
.config_parse_common
as barectf_config_parse_common
25 from barectf
.config_parse_common
import _ConfigurationParseError
26 from barectf
.config_parse_common
import _append_error_ctx
27 from barectf
.config_parse_common
import _MapNode
28 import barectf
.config
as barectf_config
29 from barectf
.config
import _OptFt
, _OptStructFt
32 from barectf
.typing
import Count
, Alignment
, VersionNumber
33 from typing
import Optional
, List
, Dict
, Any
, TextIO
, Set
, Iterable
, Callable
, Tuple
, Type
37 # A barectf 3 YAML configuration parser.
39 # When you build such a parser, it parses the configuration node `node`
40 # (already loaded from the file having the path `path`) and creates a
41 # corresponding `barectf.Configuration` object which you can get with
42 # the `config` property.
44 # See the comments of _parse() for more implementation details about the
45 # parsing stages and general strategy.
46 class _Parser(barectf_config_parse_common
._Parser
):
47 # Builds a barectf 3 YAML configuration parser and parses the root
48 # configuration node `node` (already loaded from the file-like
49 # object `root_file`).
50 def __init__(self
, root_file
: TextIO
, node
: barectf_config_parse_common
._ConfigNodeV
3,
51 with_pkg_include_dir
: bool, inclusion_dirs
: Optional
[List
[str]],
52 ignore_include_not_found
: bool):
53 super().__init
__(root_file
, node
, with_pkg_include_dir
, inclusion_dirs
,
54 ignore_include_not_found
, VersionNumber(3))
55 self
._ft
_cls
_name
_to
_create
_method
: Dict
[str, Callable
[[_MapNode
], barectf_config
._FieldType
]] = {
56 'unsigned-integer': self
._create
_int
_ft
,
57 'signed-integer': self
._create
_int
_ft
,
58 'unsigned-enumeration': self
._create
_enum
_ft
,
59 'signed-enumeration': self
._create
_enum
_ft
,
60 'real': self
._create
_real
_ft
,
61 'string': self
._create
_string
_ft
,
62 'static-array': self
._create
_static
_array
_ft
,
63 'structure': self
._create
_struct
_ft
,
67 # Validates the alignment `alignment`, raising a
68 # `_ConfigurationParseError` exception using `ctx_obj_name` if it's
71 def _validate_alignment(alignment
: Alignment
, ctx_obj_name
: str):
74 # check for power of two
75 if (alignment
& (alignment
- 1)) != 0:
76 raise _ConfigurationParseError(ctx_obj_name
,
77 f
'Invalid alignment (not a power of two): {alignment}')
79 # Validates the TSDL identifier `iden`, raising a
80 # `_ConfigurationParseError` exception using `ctx_obj_name` and
81 # `prop` to format the message if it's invalid.
83 def _validate_iden(iden
: str, ctx_obj_name
: str, prop
: str):
84 assert type(iden
) is str
103 if iden
in ctf_keywords
:
104 msg
= f
'Invalid {prop} (not a valid identifier): `{iden}`'
105 raise _ConfigurationParseError(ctx_obj_name
, msg
)
108 def _alignment_prop(ft_node
: _MapNode
, prop_name
: str) -> Alignment
:
109 alignment
= ft_node
.get(prop_name
)
111 if alignment
is not None:
112 _Parser
._validate
_alignment
(alignment
, '`prop_name` property')
114 return Alignment(alignment
)
117 def _trace_type_node(self
) -> _MapNode
:
118 return self
.config_node
['trace']['type']
121 def _byte_order_from_node(node
: str) -> barectf_config
.ByteOrder
:
123 'big-endian': barectf_config
.ByteOrder
.BIG_ENDIAN
,
124 'little-endian': barectf_config
.ByteOrder
.LITTLE_ENDIAN
,
127 # Creates a bit array field type having the type `ft_type` from the
128 # bit array field type node `ft_node`, passing the additional
129 # `*args` to ft_type.__init__().
130 def _create_common_bit_array_ft(self
, ft_node
: _MapNode
,
131 ft_type
: Type
[barectf_config
._BitArrayFieldType
],
132 default_alignment
: Optional
[Alignment
],
133 *args
) -> barectf_config
._BitArrayFieldType
:
134 byte_order
= self
._byte
_order
_from
_node
(ft_node
['byte-order'])
135 alignment
= self
._alignment
_prop
(ft_node
, 'alignment')
137 if alignment
is None:
138 alignment
= default_alignment
140 return ft_type(ft_node
['size'], byte_order
, alignment
, *args
)
142 # Creates an integer field type having the type `ft_type` from the
143 # integer field type node `ft_node`, passing the additional `*args`
144 # to ft_type.__init__().
145 def _create_common_int_ft(self
, ft_node
: _MapNode
,
146 ft_type
: Type
[barectf_config
._IntegerFieldType
], *args
) -> barectf_config
._IntegerFieldType
:
147 preferred_display_base
= {
148 'binary': barectf_config
.DisplayBase
.BINARY
,
149 'octal': barectf_config
.DisplayBase
.OCTAL
,
150 'decimal': barectf_config
.DisplayBase
.DECIMAL
,
151 'hexadecimal': barectf_config
.DisplayBase
.HEXADECIMAL
,
152 }[ft_node
.get('preferred-display-base', 'decimal')]
153 return typing
.cast(barectf_config
._IntegerFieldType
,
154 self
._create
_common
_bit
_array
_ft
(ft_node
, ft_type
, None,
155 preferred_display_base
, *args
))
157 # Creates an integer field type from the unsigned/signed integer
158 # field type node `ft_node`.
159 def _create_int_ft(self
, ft_node
: _MapNode
) -> barectf_config
._IntegerFieldType
:
161 'unsigned-integer': barectf_config
.UnsignedIntegerFieldType
,
162 'signed-integer': barectf_config
.SignedIntegerFieldType
,
164 return self
._create
_common
_int
_ft
(ft_node
, ft_type
)
166 # Creates an enumeration field type from the unsigned/signed
167 # enumeration field type node `ft_node`.
168 def _create_enum_ft(self
, ft_node
: _MapNode
) -> barectf_config
._EnumerationFieldType
:
170 'unsigned-enumeration': barectf_config
.UnsignedEnumerationFieldType
,
171 'signed-enumeration': barectf_config
.SignedEnumerationFieldType
,
173 mappings
= collections
.OrderedDict()
175 for label
, mapping_node
in ft_node
.get('mappings', {}).items():
178 for range_node
in mapping_node
:
179 if type(range_node
) is list:
180 ranges
.add(barectf_config
.EnumerationFieldTypeMappingRange(range_node
[0],
183 assert type(range_node
) is int
184 ranges
.add(barectf_config
.EnumerationFieldTypeMappingRange(range_node
,
187 mappings
[label
] = barectf_config
.EnumerationFieldTypeMapping(ranges
)
189 return typing
.cast(barectf_config
._EnumerationFieldType
,
190 self
._create
_common
_int
_ft
(ft_node
, ft_type
,
191 barectf_config
.EnumerationFieldTypeMappings(mappings
)))
193 # Creates a real field type from the real field type node `ft_node`.
194 def _create_real_ft(self
, ft_node
: _MapNode
) -> barectf_config
.RealFieldType
:
195 return typing
.cast(barectf_config
.RealFieldType
,
196 self
._create
_common
_bit
_array
_ft
(ft_node
, barectf_config
.RealFieldType
,
199 # Creates a string field type from the string field type node
201 def _create_string_ft(self
, ft_node
: _MapNode
) -> barectf_config
.StringFieldType
:
202 return barectf_config
.StringFieldType()
204 # Creates a static array field type from the static array field type
206 def _create_static_array_ft(self
, ft_node
: _MapNode
) -> barectf_config
.StaticArrayFieldType
:
207 prop_name
= 'element-field-type'
210 element_ft
= self
._create
_ft
(ft_node
[prop_name
])
211 except _ConfigurationParseError
as exc
:
212 _append_error_ctx(exc
, f
'`{prop_name}` property')
214 return barectf_config
.StaticArrayFieldType(ft_node
['length'], element_ft
)
216 # Creates structure field type members from the structure field type
217 # members node `members_node`.
219 # `prop_name` is the name of the property of which `members_node` is
221 def _create_struct_ft_members(self
, members_node
: List
[_MapNode
], prop_name
: str):
222 members
= collections
.OrderedDict()
223 member_names
: Set
[str] = set()
225 for member_node
in members_node
:
226 member_name
, member_node
= list(member_node
.items())[0]
228 if member_name
in member_names
:
229 raise _ConfigurationParseError(f
'`{prop_name}` property',
230 f
'Duplicate member `{member_name}`')
232 self
._validate
_iden
(member_name
, f
'`{prop_name}` property',
233 'structure field type member name')
234 member_names
.add(member_name
)
235 ft_prop_name
= 'field-type'
236 ft_node
= member_node
[ft_prop_name
]
239 if ft_node
['class'] in ['structure', 'static-array']:
240 raise _ConfigurationParseError(f
'`{ft_prop_name}` property',
241 'Nested structure and static array field types are not supported')
244 member_ft
= self
._create
_ft
(ft_node
)
245 except _ConfigurationParseError
as exc
:
246 exc
._append
_ctx
(f
'`{ft_prop_name}` property')
247 except _ConfigurationParseError
as exc
:
248 _append_error_ctx(exc
, f
'Structure field type member `{member_name}`')
250 members
[member_name
] = barectf_config
.StructureFieldTypeMember(member_ft
)
252 return barectf_config
.StructureFieldTypeMembers(members
)
254 # Creates a structure field type from the structure field type node
256 def _create_struct_ft(self
, ft_node
: _MapNode
) -> barectf_config
.StructureFieldType
:
257 minimum_alignment
= self
._alignment
_prop
(ft_node
, 'minimum-alignment')
259 if minimum_alignment
is None:
260 minimum_alignment
= 1
263 prop_name
= 'members'
264 members_node
= ft_node
.get(prop_name
)
266 if members_node
is not None:
267 members
= self
._create
_struct
_ft
_members
(members_node
, prop_name
)
269 return barectf_config
.StructureFieldType(minimum_alignment
, members
)
271 # Creates a field type from the field type node `ft_node`.
272 def _create_ft(self
, ft_node
: _MapNode
) -> barectf_config
._FieldType
:
273 return self
._ft
_cls
_name
_to
_create
_method
[ft_node
['class']](ft_node
)
275 # Creates a field type from the field type node `parent_node[key]`
277 def _try_create_ft(self
, parent_node
: _MapNode
, key
: str) -> _OptFt
:
278 if key
not in parent_node
:
282 return self
._create
_ft
(parent_node
[key
])
283 except _ConfigurationParseError
as exc
:
284 _append_error_ctx(exc
, f
'`{key}` property')
286 # satisfy static type checker (never reached)
289 # Like _try_create_ft(), but casts the result's type to
290 # `barectf_config.StructureFieldType` to satisfy static type
292 def _try_create_struct_ft(self
, parent_node
: _MapNode
, key
: str) -> _OptStructFt
:
293 return typing
.cast(barectf_config
.StructureFieldType
,
294 self
._try
_create
_ft
(parent_node
, key
))
296 # Returns the total number of members in the structure field type
297 # node `ft_node` if it exists, otherwise 0.
299 def _total_struct_ft_node_members(ft_node
: Optional
[_MapNode
]) -> Count
:
303 members_node
= ft_node
.get('members')
305 if members_node
is None:
308 return Count(len(members_node
))
310 # Creates an event type from the event type node `ev_type_node`
313 # `ev_member_count` is the total number of structure field type
314 # members within the event type so far (from the common part in its
315 # stream type). For example, if the stream type has a event header
316 # field type with `id` and `timestamp` members, then
317 # `ev_member_count` is 2.
318 def _create_ev_type(self
, name
: str, ev_type_node
: _MapNode
, ev_member_count
: Count
) -> barectf_config
.EventType
:
320 self
._validate
_iden
(name
, '`name` property', 'event type name')
322 # make sure the event type is not empty
323 spec_ctx_ft_prop_name
= 'specific-context-field-type'
324 payload_ft_prop_name
= 'payload-field-type'
325 ev_member_count
= Count(ev_member_count
+
326 self
._total
_struct
_ft
_node
_members
(ev_type_node
.get(spec_ctx_ft_prop_name
)))
327 ev_member_count
= Count(ev_member_count
+
328 self
._total
_struct
_ft
_node
_members
(ev_type_node
.get(payload_ft_prop_name
)))
330 if ev_member_count
== 0:
331 raise _ConfigurationParseError('Event type', 'Event type is empty (no members).')
334 return barectf_config
.EventType(name
, ev_type_node
.get('log-level'),
335 self
._try
_create
_struct
_ft
(ev_type_node
,
336 spec_ctx_ft_prop_name
),
337 self
._try
_create
_struct
_ft
(ev_type_node
,
338 payload_ft_prop_name
))
339 except _ConfigurationParseError
as exc
:
340 _append_error_ctx(exc
, f
'Event type `{name}`')
342 # satisfy static type checker (never reached)
345 # Returns the effective feature field type for the field type
346 # node `parent_node[key]`, if any.
350 # If `parent_node[key]` is `False`:
353 # If `parent_node[key]` is `True`:
354 # `barectf_config.DEFAULT_FIELD_TYPE`.
356 # If `parent_node[key]` doesn't exist:
357 # `none` (parameter).
360 # A created field type.
361 def _feature_ft(self
, parent_node
: _MapNode
, key
: str, none
: Any
= None) -> Any
:
362 if key
not in parent_node
:
363 # missing: default feature field type
366 ft_node
= parent_node
[key
]
367 assert ft_node
is not None
370 # default feature field type
371 return barectf_config
.DEFAULT_FIELD_TYPE
377 assert type(ft_node
) is collections
.OrderedDict
378 return self
._create
_ft
(ft_node
)
380 def _create_stream_type(self
, name
: str, stream_type_node
: _MapNode
) -> barectf_config
.StreamType
:
382 # validate stream type's name
383 self
._validate
_iden
(name
, '`name` property', 'stream type name')
385 # get default clock type, if any
387 prop_name
= '$default-clock-type-name'
388 def_clk_type_name
= stream_type_node
.get(prop_name
)
390 if def_clk_type_name
is not None:
392 def_clk_type
= self
._clk
_type
(def_clk_type_name
, prop_name
)
393 except _ConfigurationParseError
as exc
:
394 _append_error_ctx(exc
, f
'`{prop_name}` property')
396 # create feature field types
397 pkt_total_size_ft
= barectf_config
.DEFAULT_FIELD_TYPE
398 pkt_content_size_ft
= barectf_config
.DEFAULT_FIELD_TYPE
399 pkt_beginning_time_ft
= None
400 pkt_end_time_ft
= None
401 pkt_discarded_events_counter_ft
= None
402 ev_type_id_ft
= barectf_config
.DEFAULT_FIELD_TYPE
405 if def_clk_type
is not None:
406 # The stream type has a default clock type. Initialize
407 # the packet beginning time, packet end time, and event
408 # time field types to default field types.
410 # This means your stream type node only needs a default
411 # clock type name to enable those features
412 # automatically. Those features do not add any parameter
413 # to the tracing event functions.
414 pkt_beginning_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
415 pkt_end_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
416 ev_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
418 features_node
= stream_type_node
.get('$features')
420 if features_node
is not None:
421 # create packet feature field types
422 pkt_node
= features_node
.get('packet')
424 if pkt_node
is not None:
425 pkt_total_size_ft
= self
._feature
_ft
(pkt_node
, 'total-size-field-type',
427 pkt_content_size_ft
= self
._feature
_ft
(pkt_node
, 'content-size-field-type',
429 pkt_beginning_time_ft
= self
._feature
_ft
(pkt_node
, 'beginning-time-field-type',
430 pkt_beginning_time_ft
)
431 pkt_end_time_ft
= self
._feature
_ft
(pkt_node
, 'end-time-field-type',
433 pkt_discarded_events_counter_ft
= self
._feature
_ft
(pkt_node
,
434 'discarded-events-counter-field-type',
435 pkt_discarded_events_counter_ft
)
437 # create event feature field types
438 ev_node
= features_node
.get('event')
439 type_id_ft_prop_name
= 'type-id-field-type'
441 if ev_node
is not None:
442 ev_type_id_ft
= self
._feature
_ft
(ev_node
, type_id_ft_prop_name
, ev_type_id_ft
)
443 ev_time_ft
= self
._feature
_ft
(ev_node
, 'time-field-type', ev_time_ft
)
445 ev_types_prop_name
= 'event-types'
446 ev_type_count
= len(stream_type_node
[ev_types_prop_name
])
449 if ev_type_id_ft
is None and ev_type_count
> 1:
450 raise _ConfigurationParseError(f
'`{type_id_ft_prop_name}` property',
451 'Event type ID field type feature is required because stream type has more than one event type')
453 if isinstance(ev_type_id_ft
, barectf_config
._IntegerFieldType
):
454 ev_type_id_int_ft
= typing
.cast(barectf_config
._IntegerFieldType
, ev_type_id_ft
)
456 if ev_type_count
> (1 << ev_type_id_int_ft
.size
):
457 raise _ConfigurationParseError(f
'`{type_id_ft_prop_name}` property',
458 f
'Field type\'s size ({ev_type_id_int_ft.size} bits) is too small to accomodate {ev_type_count} event types')
459 except _ConfigurationParseError
as exc
:
460 exc
._append
_ctx
('`event` property')
461 _append_error_ctx(exc
, '`$features` property')
463 pkt_features
= barectf_config
.StreamTypePacketFeatures(pkt_total_size_ft
,
465 pkt_beginning_time_ft
,
467 pkt_discarded_events_counter_ft
)
468 ev_features
= barectf_config
.StreamTypeEventFeatures(ev_type_id_ft
, ev_time_ft
)
469 features
= barectf_config
.StreamTypeFeatures(pkt_features
, ev_features
)
471 # create packet context (structure) field type extra members
472 pkt_ctx_ft_extra_members
= None
473 prop_name
= 'packet-context-field-type-extra-members'
474 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(prop_name
)
476 if pkt_ctx_ft_extra_members_node
is not None:
477 pkt_ctx_ft_extra_members
= self
._create
_struct
_ft
_members
(pkt_ctx_ft_extra_members_node
,
480 # check for illegal packet context field type member names
481 reserved_member_names
= {
490 for member_name
in pkt_ctx_ft_extra_members
:
491 if member_name
in reserved_member_names
:
492 raise _ConfigurationParseError(f
'`{prop_name}` property',
493 f
'Packet context field type member name `{member_name}` is reserved.')
496 ev_header_common_ctx_member_count
= Count(0)
498 if ev_features
.type_id_field_type
is not None:
499 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+ 1)
501 if ev_features
.time_field_type
is not None:
502 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+ 1)
504 ev_common_ctx_ft_prop_name
= 'event-common-context-field-type'
505 ev_common_ctx_ft_node
= stream_type_node
.get(ev_common_ctx_ft_prop_name
)
506 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+
507 self
._total
_struct
_ft
_node
_members
(ev_common_ctx_ft_node
))
510 for ev_name
, ev_type_node
in stream_type_node
[ev_types_prop_name
].items():
511 ev_types
.add(self
._create
_ev
_type
(ev_name
, ev_type_node
, ev_header_common_ctx_member_count
))
514 return barectf_config
.StreamType(name
, ev_types
, def_clk_type
, features
,
515 pkt_ctx_ft_extra_members
,
516 self
._try
_create
_struct
_ft
(stream_type_node
,
517 ev_common_ctx_ft_prop_name
))
518 except _ConfigurationParseError
as exc
:
519 _append_error_ctx(exc
, f
'Stream type `{name}`')
521 # satisfy static type checker (never reached)
524 def _clk_type(self
, name
: str, prop_name
: str) -> barectf_config
.ClockType
:
525 clk_type
= self
._clk
_types
.get(name
)
528 raise _ConfigurationParseError(f
'`{prop_name}` property',
529 f
'Clock type `{name}` does not exist')
533 def _create_clk_type(self
, name
: str, clk_type_node
: _MapNode
) -> barectf_config
.ClockType
:
534 self
._validate
_iden
(name
, '`name` property', 'clock type name')
536 uuid_node
= clk_type_node
.get('uuid')
538 if uuid_node
is not None:
539 clk_type_uuid
= uuid
.UUID(uuid_node
)
542 offset_cycles
= Count(0)
543 offset_node
= clk_type_node
.get('offset')
545 if offset_node
is not None:
546 offset_seconds
= offset_node
.get('seconds', 0)
547 offset_cycles
= offset_node
.get('cycles', Count(0))
549 return barectf_config
.ClockType(name
, clk_type_node
.get('frequency', int(1e9
)),
550 clk_type_uuid
, clk_type_node
.get('description'),
551 clk_type_node
.get('precision', 0),
552 barectf_config
.ClockTypeOffset(offset_seconds
, offset_cycles
),
553 clk_type_node
.get('origin-is-unix-epoch', False))
555 def _create_clk_types(self
):
558 for clk_type_name
, clk_type_node
in self
._trace
_type
_node
.get('clock-types', {}).items():
559 self
._clk
_types
[clk_type_name
] = self
._create
_clk
_type
(clk_type_name
, clk_type_node
)
561 def _create_trace_type(self
):
563 # create clock types (_create_stream_type() needs them)
564 self
._create
_clk
_types
()
567 trace_type_uuid
= None
568 uuid_node
= self
._trace
_type
_node
.get('uuid')
570 if uuid_node
is not None:
571 if uuid_node
== 'auto':
572 trace_type_uuid
= uuid
.uuid1()
574 trace_type_uuid
= uuid
.UUID(uuid_node
)
576 # create feature field types
577 magic_ft
= barectf_config
.DEFAULT_FIELD_TYPE
579 stream_type_id_ft
= barectf_config
.DEFAULT_FIELD_TYPE
581 if trace_type_uuid
is not None:
582 # Trace type has a UUID: initialize UUID field type to
583 # a default field type.
584 uuid_ft
= barectf_config
.DEFAULT_FIELD_TYPE
586 features_node
= self
._trace
_type
_node
.get('$features')
587 stream_type_id_ft_prop_name
= 'stream-type-id-field-type'
589 if features_node
is not None:
590 magic_ft
= self
._feature
_ft
(features_node
, 'magic-field-type',
592 uuid_ft
= self
._feature
_ft
(features_node
, 'uuid-field-type', uuid_ft
)
593 stream_type_id_ft
= self
._feature
_ft
(features_node
, stream_type_id_ft_prop_name
,
596 stream_types_prop_name
= 'stream-types'
597 stream_type_count
= len(self
._trace
_type
_node
[stream_types_prop_name
])
600 if stream_type_id_ft
is None and stream_type_count
> 1:
601 raise _ConfigurationParseError(f
'`{stream_type_id_ft_prop_name}` property',
602 'Stream type ID field type feature is required because trace type has more than one stream type')
604 if isinstance(stream_type_id_ft
, barectf_config
._FieldType
) and stream_type_count
> (1 << stream_type_id_ft
.size
):
605 raise _ConfigurationParseError(f
'`{stream_type_id_ft_prop_name}` property',
606 f
'Field type\'s size ({stream_type_id_ft.size} bits) is too small to accomodate {stream_type_count} stream types')
607 except _ConfigurationParseError
as exc
:
608 _append_error_ctx(exc
, '`$features` property')
610 features
= barectf_config
.TraceTypeFeatures(magic_ft
, uuid_ft
, stream_type_id_ft
)
612 # create stream types
615 for stream_name
, stream_type_node
in self
._trace
_type
_node
[stream_types_prop_name
].items():
616 stream_types
.add(self
._create
_stream
_type
(stream_name
, stream_type_node
))
619 return barectf_config
.TraceType(stream_types
, self
._default
_byte
_order
,
620 trace_type_uuid
, features
)
621 except _ConfigurationParseError
as exc
:
622 _append_error_ctx(exc
, 'Trace type')
624 def _create_trace(self
):
626 trace_type
= self
._create
_trace
_type
()
627 trace_node
= self
.config_node
['trace']
629 env_node
= trace_node
.get('environment')
631 if env_node
is not None:
632 # validate each environment variable name
633 for name
in env_node
:
634 self
._validate
_iden
(name
, '`environment` property',
635 'environment variable name')
637 # the node already has the expected structure
638 env
= barectf_config
.TraceEnvironment(env_node
)
640 return barectf_config
.Trace(trace_type
, env
)
642 except _ConfigurationParseError
as exc
:
643 _append_error_ctx(exc
, 'Trace')
645 def _create_config(self
):
647 trace
= self
._create
_trace
()
649 # find default stream type, if any
650 def_stream_type
= None
652 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
653 prop_name
= '$is-default'
654 is_default
= stream_type_node
.get(prop_name
)
656 if is_default
is True:
657 if def_stream_type
is not None:
658 exc
= _ConfigurationParseError(f
'`{prop_name}` property',
659 f
'Duplicate default stream type (`{def_stream_type.name}`)')
660 exc
._append
_ctx
(f
'Stream type `{stream_type_name}`')
661 _append_error_ctx(exc
, 'Trace type')
663 def_stream_type
= trace
.type.stream_type(stream_type_name
)
665 # create clock type C type mapping
666 clk_types_node
= self
._trace
_type
_node
.get('clock-types')
667 clk_type_c_types
= None
669 if clk_types_node
is not None:
670 clk_type_c_types
= collections
.OrderedDict()
672 for stream_type
in trace
.type.stream_types
:
673 if stream_type
.default_clock_type
is None:
676 clk_type_node
= clk_types_node
[stream_type
.default_clock_type
.name
]
677 c_type
= clk_type_node
.get('$c-type')
679 if c_type
is not None:
680 clk_type_c_types
[stream_type
.default_clock_type
] = c_type
683 iden_prefix_def
= False
684 def_stream_type_name_def
= False
685 opts_node
= self
.config_node
.get('options')
686 iden_prefix
= 'barectf_'
687 file_name_prefix
= 'barectf'
689 if opts_node
is not None:
690 code_gen_opts_node
= opts_node
.get('code-generation')
692 if code_gen_opts_node
is not None:
693 prefix_node
= code_gen_opts_node
.get('prefix', 'barectf')
695 if type(prefix_node
) is str:
697 iden_prefix
= f
'{prefix_node}_'
698 file_name_prefix
= prefix_node
700 iden_prefix
= prefix_node
['identifier']
701 file_name_prefix
= prefix_node
['file-name']
703 header_opts
= code_gen_opts_node
.get('header')
705 if header_opts
is not None:
706 iden_prefix_def
= header_opts
.get('identifier-prefix-definition', False)
707 def_stream_type_name_def
= header_opts
.get('default-stream-type-name-definition',
710 header_opts
= barectf_config
.ConfigurationCodeGenerationHeaderOptions(iden_prefix_def
,
711 def_stream_type_name_def
)
712 cg_opts
= barectf_config
.ConfigurationCodeGenerationOptions(iden_prefix
, file_name_prefix
,
713 def_stream_type
, header_opts
,
715 opts
= barectf_config
.ConfigurationOptions(cg_opts
)
717 # create configuration
718 self
._config
= barectf_config
.Configuration(trace
, opts
)
720 # Expands the field type aliases found in the trace type node.
722 # This method modifies the trace type node.
724 # When this method returns:
726 # * Any field type alias is replaced with its full field type
729 # * The `$field-type-aliases` property of the trace type node is
731 def _expand_ft_aliases(self
):
732 def resolve_ft_alias_from(parent_node
: _MapNode
, key
: str):
733 if key
not in parent_node
:
736 if type(parent_node
[key
]) not in [collections
.OrderedDict
, str]:
739 self
._resolve
_ft
_alias
_from
(ft_aliases_node
, parent_node
, key
)
741 ft_aliases_node
= self
._trace
_type
_node
['$field-type-aliases']
743 # Expand field type aliases within trace, stream, and event type
745 features_prop_name
= '$features'
748 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
750 if features_node
is not None:
752 resolve_ft_alias_from(features_node
, 'magic-field-type')
753 resolve_ft_alias_from(features_node
, 'uuid-field-type')
754 resolve_ft_alias_from(features_node
, 'stream-type-id-field-type')
755 except _ConfigurationParseError
as exc
:
756 _append_error_ctx(exc
, f
'`{features_prop_name}` property')
757 except _ConfigurationParseError
as exc
:
758 _append_error_ctx(exc
, 'Trace type')
760 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
762 features_node
= stream_type_node
.get(features_prop_name
)
764 if features_node
is not None:
766 pkt_prop_name
= 'packet'
767 pkt_node
= features_node
.get(pkt_prop_name
)
769 if pkt_node
is not None:
771 resolve_ft_alias_from(pkt_node
, 'total-size-field-type')
772 resolve_ft_alias_from(pkt_node
, 'content-size-field-type')
773 resolve_ft_alias_from(pkt_node
, 'beginning-time-field-type')
774 resolve_ft_alias_from(pkt_node
, 'end-time-field-type')
775 resolve_ft_alias_from(pkt_node
,
776 'discarded-events-counter-field-type')
777 except _ConfigurationParseError
as exc
:
778 _append_error_ctx(exc
, f
'`{pkt_prop_name}` property')
780 ev_prop_name
= 'event'
781 ev_node
= features_node
.get(ev_prop_name
)
783 if ev_node
is not None:
785 resolve_ft_alias_from(ev_node
, 'type-id-field-type')
786 resolve_ft_alias_from(ev_node
, 'time-field-type')
787 except _ConfigurationParseError
as exc
:
788 _append_error_ctx(exc
, f
'`{ev_prop_name}` property')
789 except _ConfigurationParseError
as exc
:
790 _append_error_ctx(exc
, f
'`{features_prop_name}` property')
792 pkt_ctx_ft_extra_members_prop_name
= 'packet-context-field-type-extra-members'
793 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(pkt_ctx_ft_extra_members_prop_name
)
795 if pkt_ctx_ft_extra_members_node
is not None:
797 for member_node
in pkt_ctx_ft_extra_members_node
:
798 member_node
= list(member_node
.values())[0]
799 resolve_ft_alias_from(member_node
, 'field-type')
800 except _ConfigurationParseError
as exc
:
801 _append_error_ctx(exc
, f
'`{pkt_ctx_ft_extra_members_prop_name}` property')
803 resolve_ft_alias_from(stream_type_node
, 'event-common-context-field-type')
805 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
807 resolve_ft_alias_from(ev_type_node
, 'specific-context-field-type')
808 resolve_ft_alias_from(ev_type_node
, 'payload-field-type')
809 except _ConfigurationParseError
as exc
:
810 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
811 except _ConfigurationParseError
as exc
:
812 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
814 # remove the (now unneeded) `$field-type-aliases` property
815 del self
._trace
_type
_node
['$field-type-aliases']
817 # Applies field type inheritance to all field type nodes found in
818 # the trace type node.
820 # This method modifies the trace type node.
822 # When this method returns, no field type node has an `$inherit`
824 def _apply_fts_inheritance(self
):
825 def apply_ft_inheritance(parent_node
: _MapNode
, key
: str):
826 if key
not in parent_node
:
829 if type(parent_node
[key
]) is not collections
.OrderedDict
:
832 self
._apply
_ft
_inheritance
(parent_node
, key
)
834 features_prop_name
= '$features'
835 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
837 if features_node
is not None:
838 apply_ft_inheritance(features_node
, 'magic-field-type')
839 apply_ft_inheritance(features_node
, 'uuid-field-type')
840 apply_ft_inheritance(features_node
, 'stream-type-id-field-type')
842 for stream_type_node
in self
._trace
_type
_node
['stream-types'].values():
843 features_node
= stream_type_node
.get(features_prop_name
)
845 if features_node
is not None:
846 pkt_node
= features_node
.get('packet')
848 if pkt_node
is not None:
849 apply_ft_inheritance(pkt_node
, 'total-size-field-type')
850 apply_ft_inheritance(pkt_node
, 'content-size-field-type')
851 apply_ft_inheritance(pkt_node
, 'beginning-time-field-type')
852 apply_ft_inheritance(pkt_node
, 'end-time-field-type')
853 apply_ft_inheritance(pkt_node
, 'discarded-events-counter-field-type')
855 ev_node
= features_node
.get('event')
857 if ev_node
is not None:
858 apply_ft_inheritance(ev_node
, 'type-id-field-type')
859 apply_ft_inheritance(ev_node
, 'time-field-type')
861 pkt_ctx_ft_extra_members_node
= stream_type_node
.get('packet-context-field-type-extra-members')
863 if pkt_ctx_ft_extra_members_node
is not None:
864 for member_node
in pkt_ctx_ft_extra_members_node
:
865 member_node
= list(member_node
.values())[0]
866 apply_ft_inheritance(member_node
, 'field-type')
868 apply_ft_inheritance(stream_type_node
, 'event-common-context-field-type')
870 for ev_type_node
in stream_type_node
['event-types'].values():
871 apply_ft_inheritance(ev_type_node
, 'specific-context-field-type')
872 apply_ft_inheritance(ev_type_node
, 'payload-field-type')
874 # Normalizes structure field type member nodes.
876 # A structure field type member node can look like this:
878 # - msg: custom-string
880 # which is the equivalent of this:
883 # field-type: custom-string
885 # This method normalizes form 1 to use form 2.
886 def _normalize_struct_ft_member_nodes(self
):
887 def normalize_members_node(members_node
: List
[_MapNode
]):
888 ft_prop_name
= 'field-type'
890 for member_node
in members_node
:
891 member_name
, val_node
= list(member_node
.items())[0]
893 if type(val_node
) is str:
894 member_node
[member_name
] = collections
.OrderedDict({
895 ft_prop_name
: val_node
898 normalize_struct_ft_member_nodes(member_node
[member_name
], ft_prop_name
)
900 def normalize_struct_ft_member_nodes(parent_node
: _MapNode
, key
: str):
901 if type(parent_node
) is not collections
.OrderedDict
:
904 ft_node
= parent_node
.get(key
)
906 if type(ft_node
) is not collections
.OrderedDict
:
909 ft_node
= typing
.cast(collections
.OrderedDict
, ft_node
)
910 members_nodes
= ft_node
.get('members')
912 if members_nodes
is not None:
913 normalize_members_node(members_nodes
)
915 prop_name
= '$field-type-aliases'
916 ft_aliases_node
= self
._trace
_type
_node
.get(prop_name
)
918 if ft_aliases_node
is not None:
919 for alias
in ft_aliases_node
:
920 normalize_struct_ft_member_nodes(ft_aliases_node
, alias
)
922 features_prop_name
= '$features'
923 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
925 if features_node
is not None:
926 normalize_struct_ft_member_nodes(features_node
, 'magic-field-type')
927 normalize_struct_ft_member_nodes(features_node
, 'uuid-field-type')
928 normalize_struct_ft_member_nodes(features_node
, 'stream-type-id-field-type')
930 for stream_type_node
in self
._trace
_type
_node
['stream-types'].values():
931 features_node
= stream_type_node
.get(features_prop_name
)
933 if features_node
is not None:
934 pkt_node
= features_node
.get('packet')
936 if pkt_node
is not None:
937 normalize_struct_ft_member_nodes(pkt_node
, 'total-size-field-type')
938 normalize_struct_ft_member_nodes(pkt_node
, 'content-size-field-type')
939 normalize_struct_ft_member_nodes(pkt_node
, 'beginning-time-field-type')
940 normalize_struct_ft_member_nodes(pkt_node
, 'end-time-field-type')
941 normalize_struct_ft_member_nodes(pkt_node
,
942 'discarded-events-counter-field-type')
944 ev_node
= features_node
.get('event')
946 if ev_node
is not None:
947 normalize_struct_ft_member_nodes(ev_node
, 'type-id-field-type')
948 normalize_struct_ft_member_nodes(ev_node
, 'time-field-type')
950 pkt_ctx_ft_extra_members_node
= stream_type_node
.get('packet-context-field-type-extra-members')
952 if pkt_ctx_ft_extra_members_node
is not None:
953 normalize_members_node(pkt_ctx_ft_extra_members_node
)
955 normalize_struct_ft_member_nodes(stream_type_node
, 'event-common-context-field-type')
957 for ev_type_node
in stream_type_node
['event-types'].values():
958 normalize_struct_ft_member_nodes(ev_type_node
, 'specific-context-field-type')
959 normalize_struct_ft_member_nodes(ev_type_node
, 'payload-field-type')
961 # Calls _expand_ft_aliases() and _apply_fts_inheritance() if the
962 # trace type node has a `$field-type-aliases` property.
963 def _expand_fts(self
):
964 # Make sure that the current configuration node is valid
965 # considering field types are not expanded yet.
966 self
._schema
_validator
.validate(self
.config_node
,
967 '3/config/config-pre-field-type-expansion')
969 prop_name
= '$field-type-aliases'
970 ft_aliases_node
= self
._trace
_type
_node
.get(prop_name
)
972 if ft_aliases_node
is None:
973 # If there's no `'$field-type-aliases'` node, then there's
974 # no field type aliases and therefore no possible
976 if prop_name
in self
._trace
_type
_node
:
977 del self
._trace
_type
_node
[prop_name
]
981 # normalize structure field type member nodes
982 self
._normalize
_struct
_ft
_member
_nodes
()
984 # first, expand field type aliases
985 self
._expand
_ft
_aliases
()
987 # next, apply inheritance to create effective field type nodes
988 self
._apply
_fts
_inheritance
()
990 # Substitute the event type node log level aliases with their
991 # numeric equivalents.
993 # Removes the `$log-level-aliases` property of the trace type node.
994 def _sub_log_level_aliases(self
):
995 # Make sure that the current configuration node is valid
996 # considering log level aliases are not substituted yet.
997 self
._schema
_validator
.validate(self
.config_node
,
998 '3/config/config-pre-log-level-alias-sub')
1000 log_level_aliases_prop_name
= '$log-level-aliases'
1001 log_level_aliases_node
= self
._trace
_type
_node
.get(log_level_aliases_prop_name
)
1003 if log_level_aliases_prop_name
in self
._trace
_type
_node
:
1004 del self
._trace
_type
_node
[log_level_aliases_prop_name
]
1006 if log_level_aliases_node
is None:
1007 # no log level aliases
1010 # substitute log level aliases
1011 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
1013 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
1015 prop_name
= 'log-level'
1016 ll_node
= ev_type_node
.get(prop_name
)
1021 if type(ll_node
) is str:
1022 if ll_node
not in log_level_aliases_node
:
1023 raise _ConfigurationParseError(f
'`{prop_name}` property',
1024 f
'Log level alias `{ll_node}` does not exist')
1026 ev_type_node
[prop_name
] = log_level_aliases_node
[ll_node
]
1027 except _ConfigurationParseError
as exc
:
1028 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
1029 except _ConfigurationParseError
as exc
:
1030 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
1032 # Generator of parent node and key pairs for all the nodes,
1033 # recursively, of `node`.
1035 # It is safe to delete a yielded node during the iteration.
1037 def _props(node
: Any
) -> Iterable
[Tuple
[Any
, str]]:
1038 if type(node
) is collections
.OrderedDict
:
1039 for key
in list(node
):
1040 yield from _Parser
._props
(node
[key
])
1042 elif type(node
) is list:
1043 for item_node
in node
:
1044 yield from _Parser
._props
(item_node
)
1046 def _trace_type_props(self
) -> Iterable
[Tuple
[Any
, str]]:
1047 yield from _Parser
._props
(self
.config_node
['trace']['type'])
1049 # Normalize the properties of the configuration node.
1051 # This method, for each property of the trace type node:
1053 # 1. Removes it if it's `None` (means default).
1055 # 2. Chooses a specific `class` property value.
1057 # 3. Chooses a specific `byte-order`/`$default-byte-order` property
1060 # 4. Chooses a specific `preferred-display-base` property value.
1062 # This method also applies 1. to the trace node's `environment`
1064 def _normalize_props(self
):
1065 def normalize_byte_order_prop(parent_node
: _MapNode
, key
: str):
1066 node
= parent_node
[key
]
1068 if node
in ['be', 'big']:
1069 parent_node
[key
] = 'big-endian'
1070 elif node
in ['le', 'little']:
1071 parent_node
[key
] = 'little-endian'
1073 trace_node
= self
.config_node
['trace']
1074 trace_type_node
= trace_node
['type']
1075 prop_name
= '$default-byte-order'
1077 if prop_name
in trace_type_node
and type(trace_type_node
[prop_name
]) is str:
1078 normalize_byte_order_prop(trace_type_node
, prop_name
)
1080 for parent_node
, key
in self
._trace
_type
_props
():
1081 node
= parent_node
[key
]
1084 # a `None` property is equivalent to not having it
1085 del parent_node
[key
]
1088 if key
== 'class' and type(node
) is str:
1089 # field type class aliases
1090 if node
in ['uint', 'unsigned-int']:
1091 parent_node
[key
] = 'unsigned-integer'
1092 elif node
in ['sint', 'signed-int']:
1093 parent_node
[key
] = 'signed-integer'
1094 elif node
in ['uenum', 'unsigned-enum']:
1095 parent_node
[key
] = 'unsigned-enumeration'
1096 elif node
in ['senum', 'signed-enum']:
1097 parent_node
[key
] = 'signed-enumeration'
1099 parent_node
[key
] = 'string'
1100 elif node
== 'struct':
1101 parent_node
[key
] = 'structure'
1102 elif key
== 'byte-order' and type(node
) is str:
1103 # byte order aliases
1104 normalize_byte_order_prop(parent_node
, key
)
1105 elif key
== 'preferred-display-base' and type(node
) is str:
1106 # display base aliases
1108 parent_node
[key
] = 'binary'
1110 parent_node
[key
] = 'octal'
1112 parent_node
[key
] = 'decimal'
1114 parent_node
[key
] = 'hexadecimal'
1116 prop_name
= 'environment'
1118 if prop_name
in trace_node
:
1119 node
= trace_node
[prop_name
]
1122 del trace_node
[prop_name
]
1124 # Substitutes missing/`None` `byte-order` properties with the trace
1125 # type node's default byte order (`$default-byte-order` property),
1127 def _sub_ft_nodes_byte_order(self
):
1128 ba_ft_class_names
= {
1131 'unsigned-enumeration',
1132 'signed-enumeration',
1136 def set_ft_node_byte_order_prop(parent_node
: _MapNode
, key
: str):
1137 if key
not in parent_node
:
1140 ft_node
= parent_node
[key
]
1142 if type(ft_node
) is not collections
.OrderedDict
:
1145 if ft_node
['class'] in ba_ft_class_names
:
1146 prop_name
= 'byte-order'
1147 byte_order_node
= ft_node
.get(prop_name
)
1149 if byte_order_node
is None:
1150 if default_byte_order_node
is None:
1151 raise _ConfigurationParseError(f
'`{key}` property`',
1152 '`byte-order` property is not set or null, but trace type has no `$default-byte-order` property')
1154 ft_node
[prop_name
] = default_byte_order_node
1156 members_node
= ft_node
.get('members')
1158 if members_node
is not None:
1159 set_struct_ft_node_members_byte_order_prop(members_node
)
1161 set_ft_node_byte_order_prop(ft_node
, 'element-field-type')
1163 def set_struct_ft_node_members_byte_order_prop(members_node
: List
[_MapNode
]):
1164 for member_node
in members_node
:
1165 member_name
, member_node
= list(member_node
.items())[0]
1168 set_ft_node_byte_order_prop(member_node
, 'field-type')
1169 except _ConfigurationParseError
as exc
:
1170 _append_error_ctx(exc
, f
'Structure field type member `{member_name}`')
1172 default_byte_order_node
= self
._trace
_type
_node
.get('$default-byte-order')
1174 self
._default
_byte
_order
= None
1176 if default_byte_order_node
is not None:
1177 self
._default
_byte
_order
= self
._byte
_order
_from
_node
(default_byte_order_node
)
1179 features_prop_name
= '$features'
1180 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
1182 if features_node
is not None:
1184 set_ft_node_byte_order_prop(features_node
, 'magic-field-type')
1185 set_ft_node_byte_order_prop(features_node
, 'uuid-field-type')
1186 set_ft_node_byte_order_prop(features_node
, 'stream-type-id-field-type')
1187 except _ConfigurationParseError
as exc
:
1188 exc
._append
_ctx
(exc
, f
'`{features_prop_name}` property')
1189 _append_error_ctx(exc
, 'Trace type')
1191 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
1193 features_node
= stream_type_node
.get(features_prop_name
)
1195 if features_node
is not None:
1196 pkt_node
= features_node
.get('packet')
1198 if pkt_node
is not None:
1199 set_ft_node_byte_order_prop(pkt_node
, 'total-size-field-type')
1200 set_ft_node_byte_order_prop(pkt_node
, 'content-size-field-type')
1201 set_ft_node_byte_order_prop(pkt_node
, 'beginning-time-field-type')
1202 set_ft_node_byte_order_prop(pkt_node
, 'end-time-field-type')
1203 set_ft_node_byte_order_prop(pkt_node
,
1204 'discarded-events-counter-field-type')
1206 ev_node
= features_node
.get('event')
1208 if ev_node
is not None:
1209 set_ft_node_byte_order_prop(ev_node
, 'type-id-field-type')
1210 set_ft_node_byte_order_prop(ev_node
, 'time-field-type')
1212 prop_name
= 'packet-context-field-type-extra-members'
1213 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(prop_name
)
1215 if pkt_ctx_ft_extra_members_node
is not None:
1217 set_struct_ft_node_members_byte_order_prop(pkt_ctx_ft_extra_members_node
)
1218 except _ConfigurationParseError
as exc
:
1219 _append_error_ctx(exc
, f
'`{pkt_ctx_ft_extra_members_node}` property')
1221 set_ft_node_byte_order_prop(stream_type_node
, 'event-common-context-field-type')
1223 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
1225 set_ft_node_byte_order_prop(ev_type_node
, 'specific-context-field-type')
1226 set_ft_node_byte_order_prop(ev_type_node
, 'payload-field-type')
1227 except _ConfigurationParseError
as exc
:
1228 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
1229 except _ConfigurationParseError
as exc
:
1230 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
1232 # Processes the inclusions of the event type node `ev_type_node`,
1233 # returning the effective node.
1234 def _process_ev_type_node_include(self
, ev_type_node
: _MapNode
) -> _MapNode
:
1235 # Make sure the event type node is valid for the inclusion
1237 self
._schema
_validator
.validate(ev_type_node
, '3/config/event-type-pre-include')
1239 # process inclusions
1240 return self
._process
_node
_include
(ev_type_node
, self
._process
_ev
_type
_node
_include
)
1242 # Processes the inclusions of the stream type node
1243 # `stream_type_node`, returning the effective node.
1244 def _process_stream_type_node_include(self
, stream_type_node
: _MapNode
) -> _MapNode
:
1245 def process_children_include(stream_type_node
: _MapNode
):
1246 prop_name
= 'event-types'
1248 if prop_name
in stream_type_node
:
1249 ev_types_node
= stream_type_node
[prop_name
]
1251 for key
in list(ev_types_node
):
1252 ev_types_node
[key
] = self
._process
_ev
_type
_node
_include
(ev_types_node
[key
])
1254 # Make sure the stream type node is valid for the inclusion
1256 self
._schema
_validator
.validate(stream_type_node
, '3/config/stream-type-pre-include')
1258 # process inclusions
1259 return self
._process
_node
_include
(stream_type_node
, self
._process
_stream
_type
_node
_include
,
1260 process_children_include
)
1262 # Processes the inclusions of the clock type node `clk_type_node`,
1263 # returning the effective node.
1264 def _process_clk_type_node_include(self
, clk_type_node
: _MapNode
) -> _MapNode
:
1265 # Make sure the clock type node is valid for the inclusion
1267 self
._schema
_validator
.validate(clk_type_node
, '3/config/clock-type-pre-include')
1269 # process inclusions
1270 return self
._process
_node
_include
(clk_type_node
, self
._process
_clk
_type
_node
_include
)
1272 # Processes the inclusions of the trace type node `trace_type_node`,
1273 # returning the effective node.
1274 def _process_trace_type_node_include(self
, trace_type_node
: _MapNode
) -> _MapNode
:
1275 def process_children_include(trace_type_node
: _MapNode
):
1276 prop_name
= 'clock-types'
1278 if prop_name
in trace_type_node
:
1279 clk_types_node
= trace_type_node
[prop_name
]
1281 for key
in list(clk_types_node
):
1282 clk_types_node
[key
] = self
._process
_clk
_type
_node
_include
(clk_types_node
[key
])
1284 prop_name
= 'stream-types'
1286 if prop_name
in trace_type_node
:
1287 stream_types_node
= trace_type_node
[prop_name
]
1289 for key
in list(stream_types_node
):
1290 stream_types_node
[key
] = self
._process
_stream
_type
_node
_include
(stream_types_node
[key
])
1292 # Make sure the trace type node is valid for the inclusion
1294 self
._schema
_validator
.validate(trace_type_node
, '3/config/trace-type-pre-include')
1296 # process inclusions
1297 return self
._process
_node
_include
(trace_type_node
, self
._process
_trace
_type
_node
_include
,
1298 process_children_include
)
1300 # Processes the inclusions of the trace node `trace_node`, returning
1301 # the effective node.
1302 def _process_trace_node_include(self
, trace_node
: _MapNode
) -> _MapNode
:
1303 def process_children_include(trace_node
: _MapNode
):
1305 trace_node
[prop_name
] = self
._process
_trace
_type
_node
_include
(trace_node
[prop_name
])
1307 # Make sure the trace node is valid for the inclusion processing
1309 self
._schema
_validator
.validate(trace_node
, '3/config/trace-pre-include')
1311 # process inclusions
1312 return self
._process
_node
_include
(trace_node
, self
._process
_trace
_node
_include
,
1313 process_children_include
)
1315 # Processes the inclusions of the configuration node, modifying it
1316 # during the process.
1317 def _process_config_includes(self
):
1318 # Process inclusions in this order:
1320 # 1. Clock type node and event type nodes (the order between
1321 # those is not important).
1323 # 2. Stream type nodes.
1325 # 3. Trace type node.
1331 # * A trace node can include a trace type node, clock type
1332 # nodes, stream type nodes, and event type nodes.
1334 # * A trace type node can include clock type nodes, stream type
1335 # nodes, and event type nodes.
1337 # * A stream type node can include event type nodes.
1339 # First, make sure the configuration node itself is valid for
1340 # the inclusion processing stage.
1341 self
._schema
_validator
.validate(self
.config_node
, '3/config/config-pre-include')
1343 # Process trace node inclusions.
1345 # self._process_trace_node_include() returns a new (or the same)
1346 # trace node without any `$include` property in it, recursively.
1347 self
.config_node
['trace'] = self
._process
_trace
_node
_include
(self
.config_node
['trace'])
1350 # process configuration node inclusions
1351 self
._process
_config
_includes
()
1353 # Expand field type nodes.
1357 # 1. Replaces field type aliases with "effective" field type
1358 # nodes, recursively.
1360 # After this step, the `$field-type-aliases` property of the
1361 # trace type node is gone.
1363 # 2. Applies inheritance, following the `$inherit` properties.
1365 # After this step, field type nodes do not contain `$inherit`
1368 # This is done blindly, in that the process _doesn't_ validate
1369 # field type nodes at this point.
1372 # Substitute log level aliases.
1376 # 1. Replaces log level aliases in event type nodes with their
1377 # numeric equivalents as found in the `$log-level-aliases`
1378 # property of the trace type node.
1380 # 2. Removes the `$log-level-aliases` property from the trace
1382 self
._sub
_log
_level
_aliases
()
1384 # At this point, the configuration node must be valid as an
1385 # effective configuration node.
1386 self
._schema
_validator
.validate(self
.config_node
, '3/config/config')
1388 # Normalize properties.
1390 # This process removes `None` properties and chooses specific
1391 # enumerators when aliases exist (for example, `big-endian`
1394 # The goal of this is that, if the user then gets this parser's
1395 # `config_node` property, it has a normal and very readable
1398 # It also makes _create_config() easier to implement because it
1399 # doesn't need to check for `None` nodes or enumerator aliases.
1400 self
._normalize
_props
()
1402 # Set `byte-order` properties of bit array field type nodes
1405 # This process also removes the `$default-byte-order` property
1406 # from the trace type node.
1407 self
._sub
_ft
_nodes
_byte
_order
()
1409 # Create a barectf configuration object from the configuration
1411 self
._create
_config
()
1414 def config(self
) -> barectf_config
.Configuration
:
1418 def config_node(self
) -> _MapNode
:
1419 return typing
.cast(barectf_config_parse_common
._ConfigNodeV
3, self
._root
_node
).config_node