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
+ self
._total
_struct
_ft
_node
_members
(ev_type_node
.get(spec_ctx_ft_prop_name
)))
326 ev_member_count
= Count(ev_member_count
+ self
._total
_struct
_ft
_node
_members
(ev_type_node
.get(payload_ft_prop_name
)))
328 if ev_member_count
== 0:
329 raise _ConfigurationParseError('Event type', 'Event type is empty (no members).')
332 return barectf_config
.EventType(name
, ev_type_node
.get('log-level'),
333 self
._try
_create
_struct
_ft
(ev_type_node
,
334 spec_ctx_ft_prop_name
),
335 self
._try
_create
_struct
_ft
(ev_type_node
,
336 payload_ft_prop_name
))
337 except _ConfigurationParseError
as exc
:
338 _append_error_ctx(exc
, f
'Event type `{name}`')
340 # satisfy static type checker (never reached)
343 # Returns the effective feature field type for the field type
344 # node `parent_node[key]`, if any.
348 # If `parent_node[key]` is `False`:
351 # If `parent_node[key]` is `True`:
352 # `barectf_config.DEFAULT_FIELD_TYPE`.
354 # If `parent_node[key]` doesn't exist:
355 # `none` (parameter).
358 # A created field type.
359 def _feature_ft(self
, parent_node
: _MapNode
, key
: str, none
: Any
= None) -> Any
:
360 if key
not in parent_node
:
361 # missing: default feature field type
364 ft_node
= parent_node
[key
]
365 assert ft_node
is not None
368 # default feature field type
369 return barectf_config
.DEFAULT_FIELD_TYPE
375 assert type(ft_node
) is collections
.OrderedDict
376 return self
._create
_ft
(ft_node
)
378 def _create_stream_type(self
, name
: str, stream_type_node
: _MapNode
) -> barectf_config
.StreamType
:
380 # validate stream type's name
381 self
._validate
_iden
(name
, '`name` property', 'stream type name')
383 # get default clock type, if any
385 prop_name
= '$default-clock-type-name'
386 def_clk_type_name
= stream_type_node
.get(prop_name
)
388 if def_clk_type_name
is not None:
390 def_clk_type
= self
._clk
_type
(def_clk_type_name
, prop_name
)
391 except _ConfigurationParseError
as exc
:
392 _append_error_ctx(exc
, f
'`{prop_name}` property')
394 # create feature field types
395 pkt_total_size_ft
= barectf_config
.DEFAULT_FIELD_TYPE
396 pkt_content_size_ft
= barectf_config
.DEFAULT_FIELD_TYPE
397 pkt_beginning_time_ft
= None
398 pkt_end_time_ft
= None
399 pkt_discarded_events_counter_ft
= None
400 ev_type_id_ft
= barectf_config
.DEFAULT_FIELD_TYPE
403 if def_clk_type
is not None:
404 # The stream type has a default clock type. Initialize
405 # the packet beginning time, packet end time, and event
406 # time field types to default field types.
408 # This means your stream type node only needs a default
409 # clock type name to enable those features
410 # automatically. Those features do not add any parameter
411 # to the tracing event functions.
412 pkt_beginning_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
413 pkt_end_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
414 ev_time_ft
= barectf_config
.DEFAULT_FIELD_TYPE
416 features_node
= stream_type_node
.get('$features')
418 if features_node
is not None:
419 # create packet feature field types
420 pkt_node
= features_node
.get('packet')
422 if pkt_node
is not None:
423 pkt_total_size_ft
= self
._feature
_ft
(pkt_node
, 'total-size-field-type',
425 pkt_content_size_ft
= self
._feature
_ft
(pkt_node
, 'content-size-field-type',
427 pkt_beginning_time_ft
= self
._feature
_ft
(pkt_node
, 'beginning-time-field-type',
428 pkt_beginning_time_ft
)
429 pkt_end_time_ft
= self
._feature
_ft
(pkt_node
, 'end-time-field-type',
431 pkt_discarded_events_counter_ft
= self
._feature
_ft
(pkt_node
,
432 'discarded-events-counter-field-type',
433 pkt_discarded_events_counter_ft
)
435 # create event feature field types
436 ev_node
= features_node
.get('event')
437 type_id_ft_prop_name
= 'type-id-field-type'
439 if ev_node
is not None:
440 ev_type_id_ft
= self
._feature
_ft
(ev_node
, type_id_ft_prop_name
, ev_type_id_ft
)
441 ev_time_ft
= self
._feature
_ft
(ev_node
, 'time-field-type', ev_time_ft
)
443 ev_types_prop_name
= 'event-types'
444 ev_type_count
= len(stream_type_node
[ev_types_prop_name
])
447 if ev_type_id_ft
is None and ev_type_count
> 1:
448 raise _ConfigurationParseError(f
'`{type_id_ft_prop_name}` property',
449 'Event type ID field type feature is required because stream type has more than one event type')
451 if isinstance(ev_type_id_ft
, barectf_config
._IntegerFieldType
):
452 ev_type_id_int_ft
= typing
.cast(barectf_config
._IntegerFieldType
, ev_type_id_ft
)
454 if ev_type_count
> (1 << ev_type_id_int_ft
.size
):
455 raise _ConfigurationParseError(f
'`{type_id_ft_prop_name}` property',
456 f
'Field type\'s size ({ev_type_id_int_ft.size} bits) is too small to accomodate {ev_type_count} event types')
457 except _ConfigurationParseError
as exc
:
458 exc
._append
_ctx
('`event` property')
459 _append_error_ctx(exc
, '`$features` property')
461 pkt_features
= barectf_config
.StreamTypePacketFeatures(pkt_total_size_ft
,
463 pkt_beginning_time_ft
,
465 pkt_discarded_events_counter_ft
)
466 ev_features
= barectf_config
.StreamTypeEventFeatures(ev_type_id_ft
, ev_time_ft
)
467 features
= barectf_config
.StreamTypeFeatures(pkt_features
, ev_features
)
469 # create packet context (structure) field type extra members
470 pkt_ctx_ft_extra_members
= None
471 prop_name
= 'packet-context-field-type-extra-members'
472 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(prop_name
)
474 if pkt_ctx_ft_extra_members_node
is not None:
475 pkt_ctx_ft_extra_members
= self
._create
_struct
_ft
_members
(pkt_ctx_ft_extra_members_node
,
478 # check for illegal packet context field type member names
479 reserved_member_names
= {
488 for member_name
in pkt_ctx_ft_extra_members
:
489 if member_name
in reserved_member_names
:
490 raise _ConfigurationParseError(f
'`{prop_name}` property',
491 f
'Packet context field type member name `{member_name}` is reserved.')
494 ev_header_common_ctx_member_count
= Count(0)
496 if ev_features
.type_id_field_type
is not None:
497 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+ 1)
499 if ev_features
.time_field_type
is not None:
500 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+ 1)
502 ev_common_ctx_ft_prop_name
= 'event-common-context-field-type'
503 ev_common_ctx_ft_node
= stream_type_node
.get(ev_common_ctx_ft_prop_name
)
504 ev_header_common_ctx_member_count
= Count(ev_header_common_ctx_member_count
+ self
._total
_struct
_ft
_node
_members
(ev_common_ctx_ft_node
))
507 for ev_name
, ev_type_node
in stream_type_node
[ev_types_prop_name
].items():
508 ev_types
.add(self
._create
_ev
_type
(ev_name
, ev_type_node
, ev_header_common_ctx_member_count
))
511 return barectf_config
.StreamType(name
, ev_types
, def_clk_type
, features
,
512 pkt_ctx_ft_extra_members
,
513 self
._try
_create
_struct
_ft
(stream_type_node
,
514 ev_common_ctx_ft_prop_name
))
515 except _ConfigurationParseError
as exc
:
516 _append_error_ctx(exc
, f
'Stream type `{name}`')
518 # satisfy static type checker (never reached)
521 def _clk_type(self
, name
: str, prop_name
: str) -> barectf_config
.ClockType
:
522 clk_type
= self
._clk
_types
.get(name
)
525 raise _ConfigurationParseError(f
'`{prop_name}` property',
526 f
'Clock type `{name}` does not exist')
530 def _create_clk_type(self
, name
: str, clk_type_node
: _MapNode
) -> barectf_config
.ClockType
:
531 self
._validate
_iden
(name
, '`name` property', 'clock type name')
533 uuid_node
= clk_type_node
.get('uuid')
535 if uuid_node
is not None:
536 clk_type_uuid
= uuid
.UUID(uuid_node
)
539 offset_cycles
= Count(0)
540 offset_node
= clk_type_node
.get('offset')
542 if offset_node
is not None:
543 offset_seconds
= offset_node
.get('seconds', 0)
544 offset_cycles
= offset_node
.get('cycles', Count(0))
546 return barectf_config
.ClockType(name
, clk_type_node
.get('frequency', int(1e9
)),
547 clk_type_uuid
, clk_type_node
.get('description'),
548 clk_type_node
.get('precision', 0),
549 barectf_config
.ClockTypeOffset(offset_seconds
, offset_cycles
),
550 clk_type_node
.get('origin-is-unix-epoch', False))
552 def _create_clk_types(self
):
555 for clk_type_name
, clk_type_node
in self
._trace
_type
_node
.get('clock-types', {}).items():
556 self
._clk
_types
[clk_type_name
] = self
._create
_clk
_type
(clk_type_name
, clk_type_node
)
558 def _create_trace_type(self
):
560 # create clock types (_create_stream_type() needs them)
561 self
._create
_clk
_types
()
564 trace_type_uuid
= None
565 uuid_node
= self
._trace
_type
_node
.get('uuid')
567 if uuid_node
is not None:
568 if uuid_node
== 'auto':
569 trace_type_uuid
= uuid
.uuid1()
571 trace_type_uuid
= uuid
.UUID(uuid_node
)
573 # create feature field types
574 magic_ft
= barectf_config
.DEFAULT_FIELD_TYPE
576 stream_type_id_ft
= barectf_config
.DEFAULT_FIELD_TYPE
578 if trace_type_uuid
is not None:
579 # Trace type has a UUID: initialize UUID field type to
580 # a default field type.
581 uuid_ft
= barectf_config
.DEFAULT_FIELD_TYPE
583 features_node
= self
._trace
_type
_node
.get('$features')
584 stream_type_id_ft_prop_name
= 'stream-type-id-field-type'
586 if features_node
is not None:
587 magic_ft
= self
._feature
_ft
(features_node
, 'magic-field-type',
589 uuid_ft
= self
._feature
_ft
(features_node
, 'uuid-field-type', uuid_ft
)
590 stream_type_id_ft
= self
._feature
_ft
(features_node
, stream_type_id_ft_prop_name
,
593 stream_types_prop_name
= 'stream-types'
594 stream_type_count
= len(self
._trace
_type
_node
[stream_types_prop_name
])
597 if stream_type_id_ft
is None and stream_type_count
> 1:
598 raise _ConfigurationParseError(f
'`{stream_type_id_ft_prop_name}` property',
599 'Stream type ID field type feature is required because trace type has more than one stream type')
601 if isinstance(stream_type_id_ft
, barectf_config
._FieldType
) and stream_type_count
> (1 << stream_type_id_ft
.size
):
602 raise _ConfigurationParseError(f
'`{stream_type_id_ft_prop_name}` property',
603 f
'Field type\'s size ({stream_type_id_ft.size} bits) is too small to accomodate {stream_type_count} stream types')
604 except _ConfigurationParseError
as exc
:
605 _append_error_ctx(exc
, '`$features` property')
607 features
= barectf_config
.TraceTypeFeatures(magic_ft
, uuid_ft
, stream_type_id_ft
)
609 # create stream types
612 for stream_name
, stream_type_node
in self
._trace
_type
_node
[stream_types_prop_name
].items():
613 stream_types
.add(self
._create
_stream
_type
(stream_name
, stream_type_node
))
616 return barectf_config
.TraceType(stream_types
, self
._default
_byte
_order
,
617 trace_type_uuid
, features
)
618 except _ConfigurationParseError
as exc
:
619 _append_error_ctx(exc
, 'Trace type')
621 def _create_trace(self
):
623 trace_type
= self
._create
_trace
_type
()
624 trace_node
= self
.config_node
['trace']
626 env_node
= trace_node
.get('environment')
628 if env_node
is not None:
629 # validate each environment variable name
630 for name
in env_node
:
631 self
._validate
_iden
(name
, '`environment` property',
632 'environment variable name')
634 # the node already has the expected structure
635 env
= barectf_config
.TraceEnvironment(env_node
)
637 return barectf_config
.Trace(trace_type
, env
)
639 except _ConfigurationParseError
as exc
:
640 _append_error_ctx(exc
, 'Trace')
642 def _create_config(self
):
644 trace
= self
._create
_trace
()
646 # find default stream type, if any
647 def_stream_type
= None
649 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
650 prop_name
= '$is-default'
651 is_default
= stream_type_node
.get(prop_name
)
653 if is_default
is True:
654 if def_stream_type
is not None:
655 exc
= _ConfigurationParseError(f
'`{prop_name}` property',
656 f
'Duplicate default stream type (`{def_stream_type.name}`)')
657 exc
._append
_ctx
(f
'Stream type `{stream_type_name}`')
658 _append_error_ctx(exc
, 'Trace type')
660 def_stream_type
= trace
.type.stream_type(stream_type_name
)
662 # create clock type C type mapping
663 clk_types_node
= self
._trace
_type
_node
.get('clock-types')
664 clk_type_c_types
= None
666 if clk_types_node
is not None:
667 clk_type_c_types
= collections
.OrderedDict()
669 for stream_type
in trace
.type.stream_types
:
670 if stream_type
.default_clock_type
is None:
673 clk_type_node
= clk_types_node
[stream_type
.default_clock_type
.name
]
674 c_type
= clk_type_node
.get('$c-type')
676 if c_type
is not None:
677 clk_type_c_types
[stream_type
.default_clock_type
] = c_type
680 iden_prefix_def
= False
681 def_stream_type_name_def
= False
682 opts_node
= self
.config_node
.get('options')
683 iden_prefix
= 'barectf_'
684 file_name_prefix
= 'barectf'
686 if opts_node
is not None:
687 code_gen_opts_node
= opts_node
.get('code-generation')
689 if code_gen_opts_node
is not None:
690 prefix_node
= code_gen_opts_node
.get('prefix', 'barectf')
692 if type(prefix_node
) is str:
694 iden_prefix
= f
'{prefix_node}_'
695 file_name_prefix
= prefix_node
697 iden_prefix
= prefix_node
['identifier']
698 file_name_prefix
= prefix_node
['file-name']
700 header_opts
= code_gen_opts_node
.get('header')
702 if header_opts
is not None:
703 iden_prefix_def
= header_opts
.get('identifier-prefix-definition', False)
704 def_stream_type_name_def
= header_opts
.get('default-stream-type-name-definition',
707 header_opts
= barectf_config
.ConfigurationCodeGenerationHeaderOptions(iden_prefix_def
,
708 def_stream_type_name_def
)
709 cg_opts
= barectf_config
.ConfigurationCodeGenerationOptions(iden_prefix
, file_name_prefix
,
710 def_stream_type
, header_opts
,
712 opts
= barectf_config
.ConfigurationOptions(cg_opts
)
714 # create configuration
715 self
._config
= barectf_config
.Configuration(trace
, opts
)
717 # Expands the field type aliases found in the trace type node.
719 # This method modifies the trace type node.
721 # When this method returns:
723 # * Any field type alias is replaced with its full field type
726 # * The `$field-type-aliases` property of the trace type node is
728 def _expand_ft_aliases(self
):
729 def resolve_ft_alias_from(parent_node
: _MapNode
, key
: str):
730 if key
not in parent_node
:
733 if type(parent_node
[key
]) not in [collections
.OrderedDict
, str]:
736 self
._resolve
_ft
_alias
_from
(ft_aliases_node
, parent_node
, key
)
738 ft_aliases_node
= self
._trace
_type
_node
['$field-type-aliases']
740 # Expand field type aliases within trace, stream, and event type
742 features_prop_name
= '$features'
745 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
747 if features_node
is not None:
749 resolve_ft_alias_from(features_node
, 'magic-field-type')
750 resolve_ft_alias_from(features_node
, 'uuid-field-type')
751 resolve_ft_alias_from(features_node
, 'stream-type-id-field-type')
752 except _ConfigurationParseError
as exc
:
753 _append_error_ctx(exc
, f
'`{features_prop_name}` property')
754 except _ConfigurationParseError
as exc
:
755 _append_error_ctx(exc
, 'Trace type')
757 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
759 features_node
= stream_type_node
.get(features_prop_name
)
761 if features_node
is not None:
763 pkt_prop_name
= 'packet'
764 pkt_node
= features_node
.get(pkt_prop_name
)
766 if pkt_node
is not None:
768 resolve_ft_alias_from(pkt_node
, 'total-size-field-type')
769 resolve_ft_alias_from(pkt_node
, 'content-size-field-type')
770 resolve_ft_alias_from(pkt_node
, 'beginning-time-field-type')
771 resolve_ft_alias_from(pkt_node
, 'end-time-field-type')
772 resolve_ft_alias_from(pkt_node
,
773 'discarded-events-counter-field-type')
774 except _ConfigurationParseError
as exc
:
775 _append_error_ctx(exc
, f
'`{pkt_prop_name}` property')
777 ev_prop_name
= 'event'
778 ev_node
= features_node
.get(ev_prop_name
)
780 if ev_node
is not None:
782 resolve_ft_alias_from(ev_node
, 'type-id-field-type')
783 resolve_ft_alias_from(ev_node
, 'time-field-type')
784 except _ConfigurationParseError
as exc
:
785 _append_error_ctx(exc
, f
'`{ev_prop_name}` property')
786 except _ConfigurationParseError
as exc
:
787 _append_error_ctx(exc
, f
'`{features_prop_name}` property')
789 pkt_ctx_ft_extra_members_prop_name
= 'packet-context-field-type-extra-members'
790 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(pkt_ctx_ft_extra_members_prop_name
)
792 if pkt_ctx_ft_extra_members_node
is not None:
794 for member_node
in pkt_ctx_ft_extra_members_node
:
795 member_node
= list(member_node
.values())[0]
796 resolve_ft_alias_from(member_node
, 'field-type')
797 except _ConfigurationParseError
as exc
:
798 _append_error_ctx(exc
, f
'`{pkt_ctx_ft_extra_members_prop_name}` property')
800 resolve_ft_alias_from(stream_type_node
, 'event-common-context-field-type')
802 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
804 resolve_ft_alias_from(ev_type_node
, 'specific-context-field-type')
805 resolve_ft_alias_from(ev_type_node
, 'payload-field-type')
806 except _ConfigurationParseError
as exc
:
807 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
808 except _ConfigurationParseError
as exc
:
809 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
811 # remove the (now unneeded) `$field-type-aliases` property
812 del self
._trace
_type
_node
['$field-type-aliases']
814 # Applies field type inheritance to all field type nodes found in
815 # the trace type node.
817 # This method modifies the trace type node.
819 # When this method returns, no field type node has an `$inherit`
821 def _apply_fts_inheritance(self
):
822 def apply_ft_inheritance(parent_node
: _MapNode
, key
: str):
823 if key
not in parent_node
:
826 if type(parent_node
[key
]) is not collections
.OrderedDict
:
829 self
._apply
_ft
_inheritance
(parent_node
, key
)
831 features_prop_name
= '$features'
832 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
834 if features_node
is not None:
835 apply_ft_inheritance(features_node
, 'magic-field-type')
836 apply_ft_inheritance(features_node
, 'uuid-field-type')
837 apply_ft_inheritance(features_node
, 'stream-type-id-field-type')
839 for stream_type_node
in self
._trace
_type
_node
['stream-types'].values():
840 features_node
= stream_type_node
.get(features_prop_name
)
842 if features_node
is not None:
843 pkt_node
= features_node
.get('packet')
845 if pkt_node
is not None:
846 apply_ft_inheritance(pkt_node
, 'total-size-field-type')
847 apply_ft_inheritance(pkt_node
, 'content-size-field-type')
848 apply_ft_inheritance(pkt_node
, 'beginning-time-field-type')
849 apply_ft_inheritance(pkt_node
, 'end-time-field-type')
850 apply_ft_inheritance(pkt_node
, 'discarded-events-counter-field-type')
852 ev_node
= features_node
.get('event')
854 if ev_node
is not None:
855 apply_ft_inheritance(ev_node
, 'type-id-field-type')
856 apply_ft_inheritance(ev_node
, 'time-field-type')
858 pkt_ctx_ft_extra_members_node
= stream_type_node
.get('packet-context-field-type-extra-members')
860 if pkt_ctx_ft_extra_members_node
is not None:
861 for member_node
in pkt_ctx_ft_extra_members_node
:
862 member_node
= list(member_node
.values())[0]
863 apply_ft_inheritance(member_node
, 'field-type')
865 apply_ft_inheritance(stream_type_node
, 'event-common-context-field-type')
867 for ev_type_node
in stream_type_node
['event-types'].values():
868 apply_ft_inheritance(ev_type_node
, 'specific-context-field-type')
869 apply_ft_inheritance(ev_type_node
, 'payload-field-type')
871 # Normalizes structure field type member nodes.
873 # A structure field type member node can look like this:
875 # - msg: custom-string
877 # which is the equivalent of this:
880 # field-type: custom-string
882 # This method normalizes form 1 to use form 2.
883 def _normalize_struct_ft_member_nodes(self
):
884 def normalize_members_node(members_node
: List
[_MapNode
]):
885 ft_prop_name
= 'field-type'
887 for member_node
in members_node
:
888 member_name
, val_node
= list(member_node
.items())[0]
890 if type(val_node
) is str:
891 member_node
[member_name
] = collections
.OrderedDict({
892 ft_prop_name
: val_node
895 normalize_struct_ft_member_nodes(member_node
[member_name
], ft_prop_name
)
897 def normalize_struct_ft_member_nodes(parent_node
: _MapNode
, key
: str):
898 if type(parent_node
) is not collections
.OrderedDict
:
901 ft_node
= parent_node
.get(key
)
903 if type(ft_node
) is not collections
.OrderedDict
:
906 ft_node
= typing
.cast(collections
.OrderedDict
, ft_node
)
907 members_nodes
= ft_node
.get('members')
909 if members_nodes
is not None:
910 normalize_members_node(members_nodes
)
912 prop_name
= '$field-type-aliases'
913 ft_aliases_node
= self
._trace
_type
_node
.get(prop_name
)
915 if ft_aliases_node
is not None:
916 for alias
in ft_aliases_node
:
917 normalize_struct_ft_member_nodes(ft_aliases_node
, alias
)
919 features_prop_name
= '$features'
920 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
922 if features_node
is not None:
923 normalize_struct_ft_member_nodes(features_node
, 'magic-field-type')
924 normalize_struct_ft_member_nodes(features_node
, 'uuid-field-type')
925 normalize_struct_ft_member_nodes(features_node
, 'stream-type-id-field-type')
927 for stream_type_node
in self
._trace
_type
_node
['stream-types'].values():
928 features_node
= stream_type_node
.get(features_prop_name
)
930 if features_node
is not None:
931 pkt_node
= features_node
.get('packet')
933 if pkt_node
is not None:
934 normalize_struct_ft_member_nodes(pkt_node
, 'total-size-field-type')
935 normalize_struct_ft_member_nodes(pkt_node
, 'content-size-field-type')
936 normalize_struct_ft_member_nodes(pkt_node
, 'beginning-time-field-type')
937 normalize_struct_ft_member_nodes(pkt_node
, 'end-time-field-type')
938 normalize_struct_ft_member_nodes(pkt_node
,
939 'discarded-events-counter-field-type')
941 ev_node
= features_node
.get('event')
943 if ev_node
is not None:
944 normalize_struct_ft_member_nodes(ev_node
, 'type-id-field-type')
945 normalize_struct_ft_member_nodes(ev_node
, 'time-field-type')
947 pkt_ctx_ft_extra_members_node
= stream_type_node
.get('packet-context-field-type-extra-members')
949 if pkt_ctx_ft_extra_members_node
is not None:
950 normalize_members_node(pkt_ctx_ft_extra_members_node
)
952 normalize_struct_ft_member_nodes(stream_type_node
, 'event-common-context-field-type')
954 for ev_type_node
in stream_type_node
['event-types'].values():
955 normalize_struct_ft_member_nodes(ev_type_node
, 'specific-context-field-type')
956 normalize_struct_ft_member_nodes(ev_type_node
, 'payload-field-type')
958 # Calls _expand_ft_aliases() and _apply_fts_inheritance() if the
959 # trace type node has a `$field-type-aliases` property.
960 def _expand_fts(self
):
961 # Make sure that the current configuration node is valid
962 # considering field types are not expanded yet.
963 self
._schema
_validator
.validate(self
.config_node
,
964 'config/3/config-pre-field-type-expansion')
966 prop_name
= '$field-type-aliases'
967 ft_aliases_node
= self
._trace
_type
_node
.get(prop_name
)
969 if ft_aliases_node
is None:
970 # If there's no `'$field-type-aliases'` node, then there's
971 # no field type aliases and therefore no possible
973 if prop_name
in self
._trace
_type
_node
:
974 del self
._trace
_type
_node
[prop_name
]
978 # normalize structure field type member nodes
979 self
._normalize
_struct
_ft
_member
_nodes
()
981 # first, expand field type aliases
982 self
._expand
_ft
_aliases
()
984 # next, apply inheritance to create effective field type nodes
985 self
._apply
_fts
_inheritance
()
987 # Substitute the event type node log level aliases with their
988 # numeric equivalents.
990 # Removes the `$log-level-aliases` property of the trace type node.
991 def _sub_log_level_aliases(self
):
992 # Make sure that the current configuration node is valid
993 # considering log level aliases are not substituted yet.
994 self
._schema
_validator
.validate(self
.config_node
,
995 'config/3/config-pre-log-level-alias-sub')
997 log_level_aliases_prop_name
= '$log-level-aliases'
998 log_level_aliases_node
= self
._trace
_type
_node
.get(log_level_aliases_prop_name
)
1000 if log_level_aliases_prop_name
in self
._trace
_type
_node
:
1001 del self
._trace
_type
_node
[log_level_aliases_prop_name
]
1003 if log_level_aliases_node
is None:
1004 # no log level aliases
1007 # substitute log level aliases
1008 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
1010 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
1012 prop_name
= 'log-level'
1013 ll_node
= ev_type_node
.get(prop_name
)
1018 if type(ll_node
) is str:
1019 if ll_node
not in log_level_aliases_node
:
1020 raise _ConfigurationParseError(f
'`{prop_name}` property',
1021 f
'Log level alias `{ll_node}` does not exist')
1023 ev_type_node
[prop_name
] = log_level_aliases_node
[ll_node
]
1024 except _ConfigurationParseError
as exc
:
1025 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
1026 except _ConfigurationParseError
as exc
:
1027 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
1029 # Generator of parent node and key pairs for all the nodes,
1030 # recursively, of `node`.
1032 # It is safe to delete a yielded node during the iteration.
1034 def _props(node
: Any
) -> Iterable
[Tuple
[Any
, str]]:
1035 if type(node
) is collections
.OrderedDict
:
1036 for key
in list(node
):
1037 yield from _Parser
._props
(node
[key
])
1039 elif type(node
) is list:
1040 for item_node
in node
:
1041 yield from _Parser
._props
(item_node
)
1043 def _trace_type_props(self
) -> Iterable
[Tuple
[Any
, str]]:
1044 yield from _Parser
._props
(self
.config_node
['trace']['type'])
1046 # Normalize the properties of the configuration node.
1048 # This method, for each property of the trace type node:
1050 # 1. Removes it if it's `None` (means default).
1052 # 2. Chooses a specific `class` property value.
1054 # 3. Chooses a specific `byte-order`/`$default-byte-order` property
1057 # 4. Chooses a specific `preferred-display-base` property value.
1059 # This method also applies 1. to the trace node's `environment`
1061 def _normalize_props(self
):
1062 def normalize_byte_order_prop(parent_node
: _MapNode
, key
: str):
1063 node
= parent_node
[key
]
1065 if node
in ['be', 'big']:
1066 parent_node
[key
] = 'big-endian'
1067 elif node
in ['le', 'little']:
1068 parent_node
[key
] = 'little-endian'
1070 trace_node
= self
.config_node
['trace']
1071 trace_type_node
= trace_node
['type']
1072 prop_name
= '$default-byte-order'
1074 if prop_name
in trace_type_node
and type(trace_type_node
[prop_name
]) is str:
1075 normalize_byte_order_prop(trace_type_node
, prop_name
)
1077 for parent_node
, key
in self
._trace
_type
_props
():
1078 node
= parent_node
[key
]
1081 # a `None` property is equivalent to not having it
1082 del parent_node
[key
]
1085 if key
== 'class' and type(node
) is str:
1086 # field type class aliases
1087 if node
in ['uint', 'unsigned-int']:
1088 parent_node
[key
] = 'unsigned-integer'
1089 elif node
in ['sint', 'signed-int']:
1090 parent_node
[key
] = 'signed-integer'
1091 elif node
in ['uenum', 'unsigned-enum']:
1092 parent_node
[key
] = 'unsigned-enumeration'
1093 elif node
in ['senum', 'signed-enum']:
1094 parent_node
[key
] = 'signed-enumeration'
1096 parent_node
[key
] = 'string'
1097 elif node
== 'struct':
1098 parent_node
[key
] = 'structure'
1099 elif key
== 'byte-order' and type(node
) is str:
1100 # byte order aliases
1101 normalize_byte_order_prop(parent_node
, key
)
1102 elif key
== 'preferred-display-base' and type(node
) is str:
1103 # display base aliases
1105 parent_node
[key
] = 'binary'
1107 parent_node
[key
] = 'octal'
1109 parent_node
[key
] = 'decimal'
1111 parent_node
[key
] = 'hexadecimal'
1113 prop_name
= 'environment'
1115 if prop_name
in trace_node
:
1116 node
= trace_node
[prop_name
]
1119 del trace_node
[prop_name
]
1121 # Substitutes missing/`None` `byte-order` properties with the trace
1122 # type node's default byte order (`$default-byte-order` property),
1124 def _sub_ft_nodes_byte_order(self
):
1125 ba_ft_class_names
= {
1128 'unsigned-enumeration',
1129 'signed-enumeration',
1133 def set_ft_node_byte_order_prop(parent_node
: _MapNode
, key
: str):
1134 if key
not in parent_node
:
1137 ft_node
= parent_node
[key
]
1139 if type(ft_node
) is not collections
.OrderedDict
:
1142 if ft_node
['class'] in ba_ft_class_names
:
1143 prop_name
= 'byte-order'
1144 byte_order_node
= ft_node
.get(prop_name
)
1146 if byte_order_node
is None:
1147 if default_byte_order_node
is None:
1148 raise _ConfigurationParseError(f
'`{key}` property`',
1149 '`byte-order` property is not set or null, but trace type has no `$default-byte-order` property')
1151 ft_node
[prop_name
] = default_byte_order_node
1153 members_node
= ft_node
.get('members')
1155 if members_node
is not None:
1156 set_struct_ft_node_members_byte_order_prop(members_node
)
1158 set_ft_node_byte_order_prop(ft_node
, 'element-field-type')
1160 def set_struct_ft_node_members_byte_order_prop(members_node
: List
[_MapNode
]):
1161 for member_node
in members_node
:
1162 member_name
, member_node
= list(member_node
.items())[0]
1165 set_ft_node_byte_order_prop(member_node
, 'field-type')
1166 except _ConfigurationParseError
as exc
:
1167 _append_error_ctx(exc
, f
'Structure field type member `{member_name}`')
1169 default_byte_order_node
= self
._trace
_type
_node
.get('$default-byte-order')
1171 self
._default
_byte
_order
= None
1173 if default_byte_order_node
is not None:
1174 self
._default
_byte
_order
= self
._byte
_order
_from
_node
(default_byte_order_node
)
1176 features_prop_name
= '$features'
1177 features_node
= self
._trace
_type
_node
.get(features_prop_name
)
1179 if features_node
is not None:
1181 set_ft_node_byte_order_prop(features_node
, 'magic-field-type')
1182 set_ft_node_byte_order_prop(features_node
, 'uuid-field-type')
1183 set_ft_node_byte_order_prop(features_node
, 'stream-type-id-field-type')
1184 except _ConfigurationParseError
as exc
:
1185 exc
._append
_ctx
(exc
, f
'`{features_prop_name}` property')
1186 _append_error_ctx(exc
, 'Trace type')
1188 for stream_type_name
, stream_type_node
in self
._trace
_type
_node
['stream-types'].items():
1190 features_node
= stream_type_node
.get(features_prop_name
)
1192 if features_node
is not None:
1193 pkt_node
= features_node
.get('packet')
1195 if pkt_node
is not None:
1196 set_ft_node_byte_order_prop(pkt_node
, 'total-size-field-type')
1197 set_ft_node_byte_order_prop(pkt_node
, 'content-size-field-type')
1198 set_ft_node_byte_order_prop(pkt_node
, 'beginning-time-field-type')
1199 set_ft_node_byte_order_prop(pkt_node
, 'end-time-field-type')
1200 set_ft_node_byte_order_prop(pkt_node
,
1201 'discarded-events-counter-field-type')
1203 ev_node
= features_node
.get('event')
1205 if ev_node
is not None:
1206 set_ft_node_byte_order_prop(ev_node
, 'type-id-field-type')
1207 set_ft_node_byte_order_prop(ev_node
, 'time-field-type')
1209 prop_name
= 'packet-context-field-type-extra-members'
1210 pkt_ctx_ft_extra_members_node
= stream_type_node
.get(prop_name
)
1212 if pkt_ctx_ft_extra_members_node
is not None:
1214 set_struct_ft_node_members_byte_order_prop(pkt_ctx_ft_extra_members_node
)
1215 except _ConfigurationParseError
as exc
:
1216 _append_error_ctx(exc
, f
'`{pkt_ctx_ft_extra_members_node}` property')
1218 set_ft_node_byte_order_prop(stream_type_node
, 'event-common-context-field-type')
1220 for ev_type_name
, ev_type_node
in stream_type_node
['event-types'].items():
1222 set_ft_node_byte_order_prop(ev_type_node
, 'specific-context-field-type')
1223 set_ft_node_byte_order_prop(ev_type_node
, 'payload-field-type')
1224 except _ConfigurationParseError
as exc
:
1225 _append_error_ctx(exc
, f
'Event type `{ev_type_name}`')
1226 except _ConfigurationParseError
as exc
:
1227 _append_error_ctx(exc
, f
'Stream type `{stream_type_name}`')
1229 # Processes the inclusions of the event type node `ev_type_node`,
1230 # returning the effective node.
1231 def _process_ev_type_node_include(self
, ev_type_node
: _MapNode
) -> _MapNode
:
1232 # Make sure the event type node is valid for the inclusion
1234 self
._schema
_validator
.validate(ev_type_node
, 'config/3/event-type-pre-include')
1236 # process inclusions
1237 return self
._process
_node
_include
(ev_type_node
, self
._process
_ev
_type
_node
_include
)
1239 # Processes the inclusions of the stream type node
1240 # `stream_type_node`, returning the effective node.
1241 def _process_stream_type_node_include(self
, stream_type_node
: _MapNode
) -> _MapNode
:
1242 def process_children_include(stream_type_node
: _MapNode
):
1243 prop_name
= 'event-types'
1245 if prop_name
in stream_type_node
:
1246 ev_types_node
= stream_type_node
[prop_name
]
1248 for key
in list(ev_types_node
):
1249 ev_types_node
[key
] = self
._process
_ev
_type
_node
_include
(ev_types_node
[key
])
1251 # Make sure the stream type node is valid for the inclusion
1253 self
._schema
_validator
.validate(stream_type_node
, 'config/3/stream-type-pre-include')
1255 # process inclusions
1256 return self
._process
_node
_include
(stream_type_node
, self
._process
_stream
_type
_node
_include
,
1257 process_children_include
)
1259 # Processes the inclusions of the clock type node `clk_type_node`,
1260 # returning the effective node.
1261 def _process_clk_type_node_include(self
, clk_type_node
: _MapNode
) -> _MapNode
:
1262 # Make sure the clock type node is valid for the inclusion
1264 self
._schema
_validator
.validate(clk_type_node
, 'config/3/clock-type-pre-include')
1266 # process inclusions
1267 return self
._process
_node
_include
(clk_type_node
, self
._process
_clk
_type
_node
_include
)
1269 # Processes the inclusions of the trace type node `trace_type_node`,
1270 # returning the effective node.
1271 def _process_trace_type_node_include(self
, trace_type_node
: _MapNode
) -> _MapNode
:
1272 def process_children_include(trace_type_node
: _MapNode
):
1273 prop_name
= 'clock-types'
1275 if prop_name
in trace_type_node
:
1276 clk_types_node
= trace_type_node
[prop_name
]
1278 for key
in list(clk_types_node
):
1279 clk_types_node
[key
] = self
._process
_clk
_type
_node
_include
(clk_types_node
[key
])
1281 prop_name
= 'stream-types'
1283 if prop_name
in trace_type_node
:
1284 stream_types_node
= trace_type_node
[prop_name
]
1286 for key
in list(stream_types_node
):
1287 stream_types_node
[key
] = self
._process
_stream
_type
_node
_include
(stream_types_node
[key
])
1289 # Make sure the trace type node is valid for the inclusion
1291 self
._schema
_validator
.validate(trace_type_node
, 'config/3/trace-type-pre-include')
1293 # process inclusions
1294 return self
._process
_node
_include
(trace_type_node
, self
._process
_trace
_type
_node
_include
,
1295 process_children_include
)
1297 # Processes the inclusions of the trace node `trace_node`, returning
1298 # the effective node.
1299 def _process_trace_node_include(self
, trace_node
: _MapNode
) -> _MapNode
:
1300 def process_children_include(trace_node
: _MapNode
):
1302 trace_node
[prop_name
] = self
._process
_trace
_type
_node
_include
(trace_node
[prop_name
])
1304 # Make sure the trace node is valid for the inclusion processing
1306 self
._schema
_validator
.validate(trace_node
, 'config/3/trace-pre-include')
1308 # process inclusions
1309 return self
._process
_node
_include
(trace_node
, self
._process
_trace
_node
_include
,
1310 process_children_include
)
1312 # Processes the inclusions of the configuration node, modifying it
1313 # during the process.
1314 def _process_config_includes(self
):
1315 # Process inclusions in this order:
1317 # 1. Clock type node and event type nodes (the order between
1318 # those is not important).
1320 # 2. Stream type nodes.
1322 # 3. Trace type node.
1328 # * A trace node can include a trace type node, clock type
1329 # nodes, stream type nodes, and event type nodes.
1331 # * A trace type node can include clock type nodes, stream type
1332 # nodes, and event type nodes.
1334 # * A stream type node can include event type nodes.
1336 # First, make sure the configuration node itself is valid for
1337 # the inclusion processing stage.
1338 self
._schema
_validator
.validate(self
.config_node
, 'config/3/config-pre-include')
1340 # Process trace node inclusions.
1342 # self._process_trace_node_include() returns a new (or the same)
1343 # trace node without any `$include` property in it, recursively.
1344 self
.config_node
['trace'] = self
._process
_trace
_node
_include
(self
.config_node
['trace'])
1347 # process configuration node inclusions
1348 self
._process
_config
_includes
()
1350 # Expand field type nodes.
1354 # 1. Replaces field type aliases with "effective" field type
1355 # nodes, recursively.
1357 # After this step, the `$field-type-aliases` property of the
1358 # trace type node is gone.
1360 # 2. Applies inheritance, following the `$inherit` properties.
1362 # After this step, field type nodes do not contain `$inherit`
1365 # This is done blindly, in that the process _doesn't_ validate
1366 # field type nodes at this point.
1369 # Substitute log level aliases.
1373 # 1. Replaces log level aliases in event type nodes with their
1374 # numeric equivalents as found in the `$log-level-aliases`
1375 # property of the trace type node.
1377 # 2. Removes the `$log-level-aliases` property from the trace
1379 self
._sub
_log
_level
_aliases
()
1381 # At this point, the configuration node must be valid as an
1382 # effective configuration node.
1383 self
._schema
_validator
.validate(self
.config_node
, 'config/3/config')
1385 # Normalize properties.
1387 # This process removes `None` properties and chooses specific
1388 # enumerators when aliases exist (for example, `big-endian`
1391 # The goal of this is that, if the user then gets this parser's
1392 # `config_node` property, it has a normal and very readable
1395 # It also makes _create_config() easier to implement because it
1396 # doesn't need to check for `None` nodes or enumerator aliases.
1397 self
._normalize
_props
()
1399 # Set `byte-order` properties of bit array field type nodes
1402 # This process also removes the `$default-byte-order` property
1403 # from the trace type node.
1404 self
._sub
_ft
_nodes
_byte
_order
()
1406 # Create a barectf configuration object from the configuration
1408 self
._create
_config
()
1411 def config(self
) -> barectf_config
.Configuration
:
1415 def config_node(self
) -> _MapNode
:
1416 return typing
.cast(barectf_config_parse_common
._ConfigNodeV
3, self
._root
_node
).config_node