04cb23c445d00e94dc5a834d60d14105460f706c
[deliverable/barectf.git] / barectf / config_parse_v3.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
4 #
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:
12 #
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 #
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.
23
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
30 import collections
31 import uuid
32 from barectf.typing import Count, Alignment, VersionNumber
33 from typing import Optional, List, Dict, Any, TextIO, Set, Iterable, Callable, Tuple, Type
34 import typing
35
36
37 # A barectf 3 YAML configuration parser.
38 #
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.
43 #
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._ConfigNodeV3,
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,
64 }
65 self._parse()
66
67 # Validates the alignment `alignment`, raising a
68 # `_ConfigurationParseError` exception using `ctx_obj_name` if it's
69 # invalid.
70 @staticmethod
71 def _validate_alignment(alignment: Alignment, ctx_obj_name: str):
72 assert alignment >= 1
73
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}')
78
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.
82 @staticmethod
83 def _validate_iden(iden: str, ctx_obj_name: str, prop: str):
84 assert type(iden) is str
85 ctf_keywords = {
86 'align',
87 'callsite',
88 'clock',
89 'enum',
90 'env',
91 'event',
92 'floating_point',
93 'integer',
94 'stream',
95 'string',
96 'struct',
97 'trace',
98 'typealias',
99 'typedef',
100 'variant',
101 }
102
103 if iden in ctf_keywords:
104 msg = f'Invalid {prop} (not a valid identifier): `{iden}`'
105 raise _ConfigurationParseError(ctx_obj_name, msg)
106
107 @staticmethod
108 def _alignment_prop(ft_node: _MapNode, prop_name: str) -> Alignment:
109 alignment = ft_node.get(prop_name)
110
111 if alignment is not None:
112 _Parser._validate_alignment(alignment, '`prop_name` property')
113
114 return Alignment(alignment)
115
116 @property
117 def _trace_type_node(self) -> _MapNode:
118 return self.config_node['trace']['type']
119
120 @staticmethod
121 def _byte_order_from_node(node: str) -> barectf_config.ByteOrder:
122 return {
123 'big-endian': barectf_config.ByteOrder.BIG_ENDIAN,
124 'little-endian': barectf_config.ByteOrder.LITTLE_ENDIAN,
125 }[node]
126
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 alignment = self._alignment_prop(ft_node, 'alignment')
135
136 if alignment is None:
137 alignment = default_alignment
138
139 return ft_type(ft_node['size'], alignment, *args)
140
141 # Creates an integer field type having the type `ft_type` from the
142 # integer field type node `ft_node`, passing the additional `*args`
143 # to ft_type.__init__().
144 def _create_common_int_ft(self, ft_node: _MapNode,
145 ft_type: Type[barectf_config._IntegerFieldType], *args) -> barectf_config._IntegerFieldType:
146 preferred_display_base = {
147 'binary': barectf_config.DisplayBase.BINARY,
148 'octal': barectf_config.DisplayBase.OCTAL,
149 'decimal': barectf_config.DisplayBase.DECIMAL,
150 'hexadecimal': barectf_config.DisplayBase.HEXADECIMAL,
151 }[ft_node.get('preferred-display-base', 'decimal')]
152 return typing.cast(barectf_config._IntegerFieldType,
153 self._create_common_bit_array_ft(ft_node, ft_type, None,
154 preferred_display_base, *args))
155
156 # Creates an integer field type from the unsigned/signed integer
157 # field type node `ft_node`.
158 def _create_int_ft(self, ft_node: _MapNode) -> barectf_config._IntegerFieldType:
159 ft_type = {
160 'unsigned-integer': barectf_config.UnsignedIntegerFieldType,
161 'signed-integer': barectf_config.SignedIntegerFieldType,
162 }[ft_node['class']]
163 return self._create_common_int_ft(ft_node, ft_type)
164
165 # Creates an enumeration field type from the unsigned/signed
166 # enumeration field type node `ft_node`.
167 def _create_enum_ft(self, ft_node: _MapNode) -> barectf_config._EnumerationFieldType:
168 ft_type = {
169 'unsigned-enumeration': barectf_config.UnsignedEnumerationFieldType,
170 'signed-enumeration': barectf_config.SignedEnumerationFieldType,
171 }[ft_node['class']]
172 mappings = collections.OrderedDict()
173
174 for label, mapping_node in ft_node.get('mappings', {}).items():
175 ranges = set()
176
177 for range_node in mapping_node:
178 if type(range_node) is list:
179 ranges.add(barectf_config.EnumerationFieldTypeMappingRange(range_node[0],
180 range_node[1]))
181 else:
182 assert type(range_node) is int
183 ranges.add(barectf_config.EnumerationFieldTypeMappingRange(range_node,
184 range_node))
185
186 mappings[label] = barectf_config.EnumerationFieldTypeMapping(ranges)
187
188 return typing.cast(barectf_config._EnumerationFieldType,
189 self._create_common_int_ft(ft_node, ft_type,
190 barectf_config.EnumerationFieldTypeMappings(mappings)))
191
192 # Creates a real field type from the real field type node `ft_node`.
193 def _create_real_ft(self, ft_node: _MapNode) -> barectf_config.RealFieldType:
194 return typing.cast(barectf_config.RealFieldType,
195 self._create_common_bit_array_ft(ft_node, barectf_config.RealFieldType,
196 Alignment(8)))
197
198 # Creates a string field type from the string field type node
199 # `ft_node`.
200 def _create_string_ft(self, ft_node: _MapNode) -> barectf_config.StringFieldType:
201 return barectf_config.StringFieldType()
202
203 # Creates a static array field type from the static array field type
204 # node `ft_node`.
205 def _create_static_array_ft(self, ft_node: _MapNode) -> barectf_config.StaticArrayFieldType:
206 prop_name = 'element-field-type'
207
208 try:
209 element_ft = self._create_ft(ft_node[prop_name])
210 except _ConfigurationParseError as exc:
211 _append_error_ctx(exc, f'`{prop_name}` property')
212
213 return barectf_config.StaticArrayFieldType(ft_node['length'], element_ft)
214
215 # Creates structure field type members from the structure field type
216 # members node `members_node`.
217 #
218 # `prop_name` is the name of the property of which `members_node` is
219 # the value.
220 def _create_struct_ft_members(self, members_node: List[_MapNode], prop_name: str):
221 members = collections.OrderedDict()
222 member_names: Set[str] = set()
223
224 for member_node in members_node:
225 member_name, member_node = list(member_node.items())[0]
226
227 if member_name in member_names:
228 raise _ConfigurationParseError(f'`{prop_name}` property',
229 f'Duplicate member `{member_name}`')
230
231 self._validate_iden(member_name, f'`{prop_name}` property',
232 'structure field type member name')
233 member_names.add(member_name)
234 ft_prop_name = 'field-type'
235 ft_node = member_node[ft_prop_name]
236
237 try:
238 if ft_node['class'] in ['structure']:
239 raise _ConfigurationParseError(f'`{ft_prop_name}` property',
240 'Nested structure field types are not supported')
241
242 try:
243 member_ft = self._create_ft(ft_node)
244 except _ConfigurationParseError as exc:
245 exc._append_ctx(f'`{ft_prop_name}` property')
246 except _ConfigurationParseError as exc:
247 _append_error_ctx(exc, f'Structure field type member `{member_name}`')
248
249 members[member_name] = barectf_config.StructureFieldTypeMember(member_ft)
250
251 return barectf_config.StructureFieldTypeMembers(members)
252
253 # Creates a structure field type from the structure field type node
254 # `ft_node`.
255 def _create_struct_ft(self, ft_node: _MapNode) -> barectf_config.StructureFieldType:
256 minimum_alignment = self._alignment_prop(ft_node, 'minimum-alignment')
257
258 if minimum_alignment is None:
259 minimum_alignment = 1
260
261 members = None
262 prop_name = 'members'
263 members_node = ft_node.get(prop_name)
264
265 if members_node is not None:
266 members = self._create_struct_ft_members(members_node, prop_name)
267
268 return barectf_config.StructureFieldType(minimum_alignment, members)
269
270 # Creates a field type from the field type node `ft_node`.
271 def _create_ft(self, ft_node: _MapNode) -> barectf_config._FieldType:
272 return self._ft_cls_name_to_create_method[ft_node['class']](ft_node)
273
274 # Creates a field type from the field type node `parent_node[key]`
275 # if it exists.
276 def _try_create_ft(self, parent_node: _MapNode, key: str) -> _OptFt:
277 if key not in parent_node:
278 return None
279
280 try:
281 return self._create_ft(parent_node[key])
282 except _ConfigurationParseError as exc:
283 _append_error_ctx(exc, f'`{key}` property')
284
285 # satisfy static type checker (never reached)
286 raise
287
288 # Like _try_create_ft(), but casts the result's type to
289 # `barectf_config.StructureFieldType` to satisfy static type
290 # checkers.
291 def _try_create_struct_ft(self, parent_node: _MapNode, key: str) -> _OptStructFt:
292 return typing.cast(barectf_config.StructureFieldType,
293 self._try_create_ft(parent_node, key))
294
295 # Returns the total number of members in the structure field type
296 # node `ft_node` if it exists, otherwise 0.
297 @staticmethod
298 def _total_struct_ft_node_members(ft_node: Optional[_MapNode]) -> Count:
299 if ft_node is None:
300 return Count(0)
301
302 members_node = ft_node.get('members')
303
304 if members_node is None:
305 return Count(0)
306
307 return Count(len(members_node))
308
309 # Creates an event type from the event type node `ev_type_node`
310 # named `name`.
311 #
312 # `ev_member_count` is the total number of structure field type
313 # members within the event type so far (from the common part in its
314 # stream type). For example, if the stream type has a event header
315 # field type with `id` and `timestamp` members, then
316 # `ev_member_count` is 2.
317 def _create_ev_type(self, name: str, ev_type_node: _MapNode, ev_member_count: Count) -> barectf_config.EventType:
318 try:
319 self._validate_iden(name, '`name` property', 'event type name')
320
321 # make sure the event type is not empty
322 spec_ctx_ft_prop_name = 'specific-context-field-type'
323 payload_ft_prop_name = 'payload-field-type'
324 ev_member_count = Count(ev_member_count + self._total_struct_ft_node_members(ev_type_node.get(spec_ctx_ft_prop_name)))
325 ev_member_count = Count(ev_member_count + self._total_struct_ft_node_members(ev_type_node.get(payload_ft_prop_name)))
326
327 if ev_member_count == 0:
328 raise _ConfigurationParseError('Event type', 'Event type is empty (no members).')
329
330 # create event type
331 return barectf_config.EventType(name, ev_type_node.get('log-level'),
332 self._try_create_struct_ft(ev_type_node,
333 spec_ctx_ft_prop_name),
334 self._try_create_struct_ft(ev_type_node,
335 payload_ft_prop_name))
336 except _ConfigurationParseError as exc:
337 _append_error_ctx(exc, f'Event type `{name}`')
338
339 # satisfy static type checker (never reached)
340 raise
341
342 # Returns the effective feature field type for the field type
343 # node `parent_node[key]`, if any.
344 #
345 # Returns:
346 #
347 # If `parent_node[key]` is `False`:
348 # `None`.
349 #
350 # If `parent_node[key]` is `True`:
351 # `barectf_config.DEFAULT_FIELD_TYPE`.
352 #
353 # If `parent_node[key]` doesn't exist:
354 # `none` (parameter).
355 #
356 # Otherwise:
357 # A created field type.
358 def _feature_ft(self, parent_node: _MapNode, key: str, none: Any = None) -> Any:
359 if key not in parent_node:
360 # missing: default feature field type
361 return none
362
363 ft_node = parent_node[key]
364 assert ft_node is not None
365
366 if ft_node is True:
367 # default feature field type
368 return barectf_config.DEFAULT_FIELD_TYPE
369
370 if ft_node is False:
371 # disabled feature
372 return None
373
374 assert type(ft_node) is collections.OrderedDict
375 return self._create_ft(ft_node)
376
377 def _create_stream_type(self, name: str, stream_type_node: _MapNode) -> barectf_config.StreamType:
378 try:
379 # validate stream type's name
380 self._validate_iden(name, '`name` property', 'stream type name')
381
382 # get default clock type, if any
383 def_clk_type = None
384 prop_name = '$default-clock-type-name'
385 def_clk_type_name = stream_type_node.get(prop_name)
386
387 if def_clk_type_name is not None:
388 try:
389 def_clk_type = self._clk_type(def_clk_type_name, prop_name)
390 except _ConfigurationParseError as exc:
391 _append_error_ctx(exc, f'`{prop_name}` property')
392
393 # create feature field types
394 pkt_total_size_ft = barectf_config.DEFAULT_FIELD_TYPE
395 pkt_content_size_ft = barectf_config.DEFAULT_FIELD_TYPE
396 pkt_beginning_time_ft = None
397 pkt_end_time_ft = None
398 pkt_discarded_events_counter_ft = None
399 ev_type_id_ft = barectf_config.DEFAULT_FIELD_TYPE
400 ev_time_ft = None
401
402 if def_clk_type is not None:
403 # The stream type has a default clock type. Initialize
404 # the packet beginning time, packet end time, and event
405 # time field types to default field types.
406 #
407 # This means your stream type node only needs a default
408 # clock type name to enable those features
409 # automatically. Those features do not add any parameter
410 # to the tracing event functions.
411 pkt_beginning_time_ft = barectf_config.DEFAULT_FIELD_TYPE
412 pkt_end_time_ft = barectf_config.DEFAULT_FIELD_TYPE
413 ev_time_ft = barectf_config.DEFAULT_FIELD_TYPE
414
415 features_node = stream_type_node.get('$features')
416
417 if features_node is not None:
418 # create packet feature field types
419 pkt_node = features_node.get('packet')
420
421 if pkt_node is not None:
422 pkt_total_size_ft = self._feature_ft(pkt_node, 'total-size-field-type',
423 pkt_total_size_ft)
424 pkt_content_size_ft = self._feature_ft(pkt_node, 'content-size-field-type',
425 pkt_content_size_ft)
426 pkt_beginning_time_ft = self._feature_ft(pkt_node, 'beginning-time-field-type',
427 pkt_beginning_time_ft)
428 pkt_end_time_ft = self._feature_ft(pkt_node, 'end-time-field-type',
429 pkt_end_time_ft)
430 pkt_discarded_events_counter_ft = self._feature_ft(pkt_node,
431 'discarded-events-counter-field-type',
432 pkt_discarded_events_counter_ft)
433
434 # create event feature field types
435 ev_node = features_node.get('event')
436 type_id_ft_prop_name = 'type-id-field-type'
437
438 if ev_node is not None:
439 ev_type_id_ft = self._feature_ft(ev_node, type_id_ft_prop_name, ev_type_id_ft)
440 ev_time_ft = self._feature_ft(ev_node, 'time-field-type', ev_time_ft)
441
442 ev_types_prop_name = 'event-types'
443 ev_type_count = len(stream_type_node[ev_types_prop_name])
444
445 try:
446 if ev_type_id_ft is None and ev_type_count > 1:
447 raise _ConfigurationParseError(f'`{type_id_ft_prop_name}` property',
448 'Event type ID field type feature is required because stream type has more than one event type')
449
450 if isinstance(ev_type_id_ft, barectf_config._IntegerFieldType):
451 ev_type_id_int_ft = typing.cast(barectf_config._IntegerFieldType, ev_type_id_ft)
452
453 if ev_type_count > (1 << ev_type_id_int_ft.size):
454 raise _ConfigurationParseError(f'`{type_id_ft_prop_name}` property',
455 f'Field type\'s size ({ev_type_id_int_ft.size} bits) is too small to accomodate {ev_type_count} event types')
456 except _ConfigurationParseError as exc:
457 exc._append_ctx('`event` property')
458 _append_error_ctx(exc, '`$features` property')
459
460 pkt_features = barectf_config.StreamTypePacketFeatures(pkt_total_size_ft,
461 pkt_content_size_ft,
462 pkt_beginning_time_ft,
463 pkt_end_time_ft,
464 pkt_discarded_events_counter_ft)
465 ev_features = barectf_config.StreamTypeEventFeatures(ev_type_id_ft, ev_time_ft)
466 features = barectf_config.StreamTypeFeatures(pkt_features, ev_features)
467
468 # create packet context (structure) field type extra members
469 pkt_ctx_ft_extra_members = None
470 prop_name = 'packet-context-field-type-extra-members'
471 pkt_ctx_ft_extra_members_node = stream_type_node.get(prop_name)
472
473 if pkt_ctx_ft_extra_members_node is not None:
474 pkt_ctx_ft_extra_members = self._create_struct_ft_members(pkt_ctx_ft_extra_members_node,
475 prop_name)
476
477 # check for illegal packet context field type member names
478 reserved_member_names = {
479 'packet_size',
480 'content_size',
481 'timestamp_begin',
482 'timestamp_end',
483 'events_discarded',
484 'packet_seq_num',
485 }
486
487 for member_name in pkt_ctx_ft_extra_members:
488 if member_name in reserved_member_names:
489 raise _ConfigurationParseError(f'`{prop_name}` property',
490 f'Packet context field type member name `{member_name}` is reserved.')
491
492 # create event types
493 ev_header_common_ctx_member_count = Count(0)
494
495 if ev_features.type_id_field_type is not None:
496 ev_header_common_ctx_member_count = Count(ev_header_common_ctx_member_count + 1)
497
498 if ev_features.time_field_type is not None:
499 ev_header_common_ctx_member_count = Count(ev_header_common_ctx_member_count + 1)
500
501 ev_common_ctx_ft_prop_name = 'event-common-context-field-type'
502 ev_common_ctx_ft_node = stream_type_node.get(ev_common_ctx_ft_prop_name)
503 ev_header_common_ctx_member_count = Count(ev_header_common_ctx_member_count + self._total_struct_ft_node_members(ev_common_ctx_ft_node))
504 ev_types = set()
505
506 for ev_name, ev_type_node in stream_type_node[ev_types_prop_name].items():
507 ev_types.add(self._create_ev_type(ev_name, ev_type_node, ev_header_common_ctx_member_count))
508
509 # create stream type
510 return barectf_config.StreamType(name, ev_types, def_clk_type, features,
511 pkt_ctx_ft_extra_members,
512 self._try_create_struct_ft(stream_type_node,
513 ev_common_ctx_ft_prop_name))
514 except _ConfigurationParseError as exc:
515 _append_error_ctx(exc, f'Stream type `{name}`')
516
517 # satisfy static type checker (never reached)
518 raise
519
520 def _clk_type(self, name: str, prop_name: str) -> barectf_config.ClockType:
521 clk_type = self._clk_types.get(name)
522
523 if clk_type is None:
524 raise _ConfigurationParseError(f'`{prop_name}` property',
525 f'Clock type `{name}` does not exist')
526
527 return clk_type
528
529 def _create_clk_type(self, name: str, clk_type_node: _MapNode) -> barectf_config.ClockType:
530 self._validate_iden(name, '`name` property', 'clock type name')
531 clk_type_uuid = None
532 uuid_node = clk_type_node.get('uuid')
533
534 if uuid_node is not None:
535 clk_type_uuid = uuid.UUID(uuid_node)
536
537 offset_seconds = 0
538 offset_cycles = Count(0)
539 offset_node = clk_type_node.get('offset')
540
541 if offset_node is not None:
542 offset_seconds = offset_node.get('seconds', 0)
543 offset_cycles = offset_node.get('cycles', Count(0))
544
545 return barectf_config.ClockType(name, clk_type_node.get('frequency', int(1e9)),
546 clk_type_uuid, clk_type_node.get('description'),
547 clk_type_node.get('precision', 0),
548 barectf_config.ClockTypeOffset(offset_seconds, offset_cycles),
549 clk_type_node.get('origin-is-unix-epoch', False))
550
551 def _create_clk_types(self):
552 self._clk_types = {}
553
554 for clk_type_name, clk_type_node in self._trace_type_node.get('clock-types', {}).items():
555 self._clk_types[clk_type_name] = self._create_clk_type(clk_type_name, clk_type_node)
556
557 def _create_trace_type(self):
558 try:
559 # create clock types (_create_stream_type() needs them)
560 self._create_clk_types()
561
562 # get UUID
563 trace_type_uuid = None
564 uuid_node = self._trace_type_node.get('uuid')
565
566 if uuid_node is not None:
567 if uuid_node == 'auto':
568 trace_type_uuid = uuid.uuid1()
569 else:
570 trace_type_uuid = uuid.UUID(uuid_node)
571
572 # create feature field types
573 magic_ft = barectf_config.DEFAULT_FIELD_TYPE
574 uuid_ft = None
575 stream_type_id_ft = barectf_config.DEFAULT_FIELD_TYPE
576
577 if trace_type_uuid is not None:
578 # Trace type has a UUID: initialize UUID field type to
579 # a default field type.
580 uuid_ft = barectf_config.DEFAULT_FIELD_TYPE
581
582 features_node = self._trace_type_node.get('$features')
583 stream_type_id_ft_prop_name = 'stream-type-id-field-type'
584
585 if features_node is not None:
586 magic_ft = self._feature_ft(features_node, 'magic-field-type',
587 magic_ft)
588 uuid_ft = self._feature_ft(features_node, 'uuid-field-type', uuid_ft)
589 stream_type_id_ft = self._feature_ft(features_node, stream_type_id_ft_prop_name,
590 stream_type_id_ft)
591
592 stream_types_prop_name = 'stream-types'
593 stream_type_count = len(self._trace_type_node[stream_types_prop_name])
594
595 try:
596 if stream_type_id_ft is None and stream_type_count > 1:
597 raise _ConfigurationParseError(f'`{stream_type_id_ft_prop_name}` property',
598 'Stream type ID field type feature is required because trace type has more than one stream type')
599
600 if isinstance(stream_type_id_ft, barectf_config._FieldType) and stream_type_count > (1 << stream_type_id_ft.size):
601 raise _ConfigurationParseError(f'`{stream_type_id_ft_prop_name}` property',
602 f'Field type\'s size ({stream_type_id_ft.size} bits) is too small to accomodate {stream_type_count} stream types')
603 except _ConfigurationParseError as exc:
604 _append_error_ctx(exc, '`$features` property')
605
606 features = barectf_config.TraceTypeFeatures(magic_ft, uuid_ft, stream_type_id_ft)
607
608 # create stream types
609 stream_types = set()
610
611 for stream_name, stream_type_node in self._trace_type_node[stream_types_prop_name].items():
612 stream_types.add(self._create_stream_type(stream_name, stream_type_node))
613
614 # create trace type
615 return barectf_config.TraceType(stream_types, trace_type_uuid, features)
616 except _ConfigurationParseError as exc:
617 _append_error_ctx(exc, 'Trace type')
618
619 def _create_trace(self):
620 try:
621 trace_type = self._create_trace_type()
622 trace_node = self.config_node['trace']
623 env = None
624 env_node = trace_node.get('environment')
625
626 if env_node is not None:
627 # validate each environment variable name
628 for name in env_node:
629 self._validate_iden(name, '`environment` property',
630 'environment variable name')
631
632 # the node already has the expected structure
633 env = barectf_config.TraceEnvironment(env_node)
634
635 return barectf_config.Trace(trace_type, env)
636
637 except _ConfigurationParseError as exc:
638 _append_error_ctx(exc, 'Trace')
639
640 def _create_config(self):
641 # create trace first
642 trace = self._create_trace()
643
644 # find default stream type, if any
645 def_stream_type = None
646
647 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
648 prop_name = '$is-default'
649 is_default = stream_type_node.get(prop_name)
650
651 if is_default is True:
652 if def_stream_type is not None:
653 exc = _ConfigurationParseError(f'`{prop_name}` property',
654 f'Duplicate default stream type (`{def_stream_type.name}`)')
655 exc._append_ctx(f'Stream type `{stream_type_name}`')
656 _append_error_ctx(exc, 'Trace type')
657
658 def_stream_type = trace.type.stream_type(stream_type_name)
659
660 # create clock type C type mapping
661 clk_types_node = self._trace_type_node.get('clock-types')
662 clk_type_c_types = None
663
664 if clk_types_node is not None:
665 clk_type_c_types = collections.OrderedDict()
666
667 for stream_type in trace.type.stream_types:
668 if stream_type.default_clock_type is None:
669 continue
670
671 clk_type_node = clk_types_node[stream_type.default_clock_type.name]
672 c_type = clk_type_node.get('$c-type')
673
674 if c_type is not None:
675 clk_type_c_types[stream_type.default_clock_type] = c_type
676
677 # create options
678 iden_prefix_def = False
679 def_stream_type_name_def = False
680 opts_node = self.config_node.get('options')
681 iden_prefix = 'barectf_'
682 file_name_prefix = 'barectf'
683
684 if opts_node is not None:
685 code_gen_opts_node = opts_node.get('code-generation')
686
687 if code_gen_opts_node is not None:
688 prefix_node = code_gen_opts_node.get('prefix', 'barectf')
689
690 if type(prefix_node) is str:
691 # automatic prefixes
692 iden_prefix = f'{prefix_node}_'
693 file_name_prefix = prefix_node
694 else:
695 iden_prefix = prefix_node['identifier']
696 file_name_prefix = prefix_node['file-name']
697
698 header_opts = code_gen_opts_node.get('header')
699
700 if header_opts is not None:
701 iden_prefix_def = header_opts.get('identifier-prefix-definition', False)
702 def_stream_type_name_def = header_opts.get('default-stream-type-name-definition',
703 False)
704
705 header_opts = barectf_config.ConfigurationCodeGenerationHeaderOptions(iden_prefix_def,
706 def_stream_type_name_def)
707 cg_opts = barectf_config.ConfigurationCodeGenerationOptions(iden_prefix, file_name_prefix,
708 def_stream_type, header_opts,
709 clk_type_c_types)
710 opts = barectf_config.ConfigurationOptions(cg_opts)
711
712 # create configuration
713 self._config = barectf_config.Configuration(trace, self._target_byte_order, opts)
714
715 # Expands the field type aliases found in the trace type node.
716 #
717 # This method modifies the trace type node.
718 #
719 # When this method returns:
720 #
721 # * Any field type alias is replaced with its full field type
722 # node equivalent.
723 #
724 # * The `$field-type-aliases` property of the trace type node is
725 # removed.
726 def _expand_ft_aliases(self):
727 def resolve_ft_alias_from(parent_node: _MapNode, key: str):
728 if key not in parent_node:
729 return
730
731 if type(parent_node[key]) not in [collections.OrderedDict, str]:
732 return
733
734 self._resolve_ft_alias_from(ft_aliases_node, parent_node, key)
735
736 ft_aliases_node = self._trace_type_node['$field-type-aliases']
737
738 # Expand field type aliases within trace, stream, and event type
739 # nodes.
740 features_prop_name = '$features'
741
742 try:
743 features_node = self._trace_type_node.get(features_prop_name)
744
745 if features_node is not None:
746 try:
747 resolve_ft_alias_from(features_node, 'magic-field-type')
748 resolve_ft_alias_from(features_node, 'uuid-field-type')
749 resolve_ft_alias_from(features_node, 'stream-type-id-field-type')
750 except _ConfigurationParseError as exc:
751 _append_error_ctx(exc, f'`{features_prop_name}` property')
752 except _ConfigurationParseError as exc:
753 _append_error_ctx(exc, 'Trace type')
754
755 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
756 try:
757 features_node = stream_type_node.get(features_prop_name)
758
759 if features_node is not None:
760 try:
761 pkt_prop_name = 'packet'
762 pkt_node = features_node.get(pkt_prop_name)
763
764 if pkt_node is not None:
765 try:
766 resolve_ft_alias_from(pkt_node, 'total-size-field-type')
767 resolve_ft_alias_from(pkt_node, 'content-size-field-type')
768 resolve_ft_alias_from(pkt_node, 'beginning-time-field-type')
769 resolve_ft_alias_from(pkt_node, 'end-time-field-type')
770 resolve_ft_alias_from(pkt_node,
771 'discarded-events-counter-field-type')
772 except _ConfigurationParseError as exc:
773 _append_error_ctx(exc, f'`{pkt_prop_name}` property')
774
775 ev_prop_name = 'event'
776 ev_node = features_node.get(ev_prop_name)
777
778 if ev_node is not None:
779 try:
780 resolve_ft_alias_from(ev_node, 'type-id-field-type')
781 resolve_ft_alias_from(ev_node, 'time-field-type')
782 except _ConfigurationParseError as exc:
783 _append_error_ctx(exc, f'`{ev_prop_name}` property')
784 except _ConfigurationParseError as exc:
785 _append_error_ctx(exc, f'`{features_prop_name}` property')
786
787 pkt_ctx_ft_extra_members_prop_name = 'packet-context-field-type-extra-members'
788 pkt_ctx_ft_extra_members_node = stream_type_node.get(pkt_ctx_ft_extra_members_prop_name)
789
790 if pkt_ctx_ft_extra_members_node is not None:
791 try:
792 for member_node in pkt_ctx_ft_extra_members_node:
793 member_node = list(member_node.values())[0]
794 resolve_ft_alias_from(member_node, 'field-type')
795 except _ConfigurationParseError as exc:
796 _append_error_ctx(exc, f'`{pkt_ctx_ft_extra_members_prop_name}` property')
797
798 resolve_ft_alias_from(stream_type_node, 'event-common-context-field-type')
799
800 for ev_type_name, ev_type_node in stream_type_node['event-types'].items():
801 try:
802 resolve_ft_alias_from(ev_type_node, 'specific-context-field-type')
803 resolve_ft_alias_from(ev_type_node, 'payload-field-type')
804 except _ConfigurationParseError as exc:
805 _append_error_ctx(exc, f'Event type `{ev_type_name}`')
806 except _ConfigurationParseError as exc:
807 _append_error_ctx(exc, f'Stream type `{stream_type_name}`')
808
809 # remove the (now unneeded) `$field-type-aliases` property
810 del self._trace_type_node['$field-type-aliases']
811
812 # Applies field type inheritance to all field type nodes found in
813 # the trace type node.
814 #
815 # This method modifies the trace type node.
816 #
817 # When this method returns, no field type node has an `$inherit`
818 # property.
819 def _apply_fts_inheritance(self):
820 def apply_ft_inheritance(parent_node: _MapNode, key: str):
821 if key not in parent_node:
822 return
823
824 if type(parent_node[key]) is not collections.OrderedDict:
825 return
826
827 self._apply_ft_inheritance(parent_node, key)
828
829 features_prop_name = '$features'
830 features_node = self._trace_type_node.get(features_prop_name)
831
832 if features_node is not None:
833 apply_ft_inheritance(features_node, 'magic-field-type')
834 apply_ft_inheritance(features_node, 'uuid-field-type')
835 apply_ft_inheritance(features_node, 'stream-type-id-field-type')
836
837 for stream_type_node in self._trace_type_node['stream-types'].values():
838 features_node = stream_type_node.get(features_prop_name)
839
840 if features_node is not None:
841 pkt_node = features_node.get('packet')
842
843 if pkt_node is not None:
844 apply_ft_inheritance(pkt_node, 'total-size-field-type')
845 apply_ft_inheritance(pkt_node, 'content-size-field-type')
846 apply_ft_inheritance(pkt_node, 'beginning-time-field-type')
847 apply_ft_inheritance(pkt_node, 'end-time-field-type')
848 apply_ft_inheritance(pkt_node, 'discarded-events-counter-field-type')
849
850 ev_node = features_node.get('event')
851
852 if ev_node is not None:
853 apply_ft_inheritance(ev_node, 'type-id-field-type')
854 apply_ft_inheritance(ev_node, 'time-field-type')
855
856 pkt_ctx_ft_extra_members_node = stream_type_node.get('packet-context-field-type-extra-members')
857
858 if pkt_ctx_ft_extra_members_node is not None:
859 for member_node in pkt_ctx_ft_extra_members_node:
860 member_node = list(member_node.values())[0]
861 apply_ft_inheritance(member_node, 'field-type')
862
863 apply_ft_inheritance(stream_type_node, 'event-common-context-field-type')
864
865 for ev_type_node in stream_type_node['event-types'].values():
866 apply_ft_inheritance(ev_type_node, 'specific-context-field-type')
867 apply_ft_inheritance(ev_type_node, 'payload-field-type')
868
869 # Normalizes structure field type member nodes.
870 #
871 # A structure field type member node can look like this:
872 #
873 # - msg: custom-string
874 #
875 # which is the equivalent of this:
876 #
877 # - msg:
878 # field-type: custom-string
879 #
880 # This method normalizes form 1 to use form 2.
881 def _normalize_struct_ft_member_nodes(self):
882 def normalize_members_node(members_node: List[_MapNode]):
883 ft_prop_name = 'field-type'
884
885 for member_node in members_node:
886 member_name, val_node = list(member_node.items())[0]
887
888 if type(val_node) is str:
889 member_node[member_name] = collections.OrderedDict({
890 ft_prop_name: val_node
891 })
892
893 normalize_struct_ft_member_nodes(member_node[member_name], ft_prop_name)
894
895 def normalize_struct_ft_member_nodes(parent_node: _MapNode, key: str):
896 if type(parent_node) is not collections.OrderedDict:
897 return
898
899 ft_node = parent_node.get(key)
900
901 if type(ft_node) is not collections.OrderedDict:
902 return
903
904 ft_node = typing.cast(collections.OrderedDict, ft_node)
905 members_nodes = ft_node.get('members')
906
907 if members_nodes is not None:
908 normalize_members_node(members_nodes)
909
910 prop_name = '$field-type-aliases'
911 ft_aliases_node = self._trace_type_node.get(prop_name)
912
913 if ft_aliases_node is not None:
914 for alias in ft_aliases_node:
915 normalize_struct_ft_member_nodes(ft_aliases_node, alias)
916
917 features_prop_name = '$features'
918 features_node = self._trace_type_node.get(features_prop_name)
919
920 if features_node is not None:
921 normalize_struct_ft_member_nodes(features_node, 'magic-field-type')
922 normalize_struct_ft_member_nodes(features_node, 'uuid-field-type')
923 normalize_struct_ft_member_nodes(features_node, 'stream-type-id-field-type')
924
925 for stream_type_node in self._trace_type_node['stream-types'].values():
926 features_node = stream_type_node.get(features_prop_name)
927
928 if features_node is not None:
929 pkt_node = features_node.get('packet')
930
931 if pkt_node is not None:
932 normalize_struct_ft_member_nodes(pkt_node, 'total-size-field-type')
933 normalize_struct_ft_member_nodes(pkt_node, 'content-size-field-type')
934 normalize_struct_ft_member_nodes(pkt_node, 'beginning-time-field-type')
935 normalize_struct_ft_member_nodes(pkt_node, 'end-time-field-type')
936 normalize_struct_ft_member_nodes(pkt_node,
937 'discarded-events-counter-field-type')
938
939 ev_node = features_node.get('event')
940
941 if ev_node is not None:
942 normalize_struct_ft_member_nodes(ev_node, 'type-id-field-type')
943 normalize_struct_ft_member_nodes(ev_node, 'time-field-type')
944
945 pkt_ctx_ft_extra_members_node = stream_type_node.get('packet-context-field-type-extra-members')
946
947 if pkt_ctx_ft_extra_members_node is not None:
948 normalize_members_node(pkt_ctx_ft_extra_members_node)
949
950 normalize_struct_ft_member_nodes(stream_type_node, 'event-common-context-field-type')
951
952 for ev_type_node in stream_type_node['event-types'].values():
953 normalize_struct_ft_member_nodes(ev_type_node, 'specific-context-field-type')
954 normalize_struct_ft_member_nodes(ev_type_node, 'payload-field-type')
955
956 # Calls _expand_ft_aliases() and _apply_fts_inheritance() if the
957 # trace type node has a `$field-type-aliases` property.
958 def _expand_fts(self):
959 # Make sure that the current configuration node is valid
960 # considering field types are not expanded yet.
961 self._schema_validator.validate(self.config_node,
962 'config/3/config-pre-field-type-expansion')
963
964 prop_name = '$field-type-aliases'
965 ft_aliases_node = self._trace_type_node.get(prop_name)
966
967 if ft_aliases_node is None:
968 # If there's no `'$field-type-aliases'` node, then there's
969 # no field type aliases and therefore no possible
970 # inheritance.
971 if prop_name in self._trace_type_node:
972 del self._trace_type_node[prop_name]
973
974 return
975
976 # normalize structure field type member nodes
977 self._normalize_struct_ft_member_nodes()
978
979 # first, expand field type aliases
980 self._expand_ft_aliases()
981
982 # next, apply inheritance to create effective field type nodes
983 self._apply_fts_inheritance()
984
985 # Substitute the event type node log level aliases with their
986 # numeric equivalents.
987 #
988 # Removes the `$log-level-aliases` property of the trace type node.
989 def _sub_log_level_aliases(self):
990 # Make sure that the current configuration node is valid
991 # considering log level aliases are not substituted yet.
992 self._schema_validator.validate(self.config_node,
993 'config/3/config-pre-log-level-alias-sub')
994
995 log_level_aliases_prop_name = '$log-level-aliases'
996 log_level_aliases_node = self._trace_type_node.get(log_level_aliases_prop_name)
997
998 if log_level_aliases_prop_name in self._trace_type_node:
999 del self._trace_type_node[log_level_aliases_prop_name]
1000
1001 if log_level_aliases_node is None:
1002 # no log level aliases
1003 return
1004
1005 # substitute log level aliases
1006 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
1007 try:
1008 for ev_type_name, ev_type_node in stream_type_node['event-types'].items():
1009 try:
1010 prop_name = 'log-level'
1011 ll_node = ev_type_node.get(prop_name)
1012
1013 if ll_node is None:
1014 continue
1015
1016 if type(ll_node) is str:
1017 if ll_node not in log_level_aliases_node:
1018 raise _ConfigurationParseError(f'`{prop_name}` property',
1019 f'Log level alias `{ll_node}` does not exist')
1020
1021 ev_type_node[prop_name] = log_level_aliases_node[ll_node]
1022 except _ConfigurationParseError as exc:
1023 _append_error_ctx(exc, f'Event type `{ev_type_name}`')
1024 except _ConfigurationParseError as exc:
1025 _append_error_ctx(exc, f'Stream type `{stream_type_name}`')
1026
1027 # Generator of parent node and key pairs for all the nodes,
1028 # recursively, of `node`.
1029 #
1030 # It is safe to delete a yielded node during the iteration.
1031 @staticmethod
1032 def _props(node: Any) -> Iterable[Tuple[Any, str]]:
1033 if type(node) is collections.OrderedDict:
1034 for key in list(node):
1035 yield from _Parser._props(node[key])
1036 yield node, key
1037 elif type(node) is list:
1038 for item_node in node:
1039 yield from _Parser._props(item_node)
1040
1041 def _trace_type_props(self) -> Iterable[Tuple[Any, str]]:
1042 yield from _Parser._props(self.config_node['trace']['type'])
1043
1044 # Normalize the properties of the configuration node.
1045 #
1046 # This method, for each property of the trace type node:
1047 #
1048 # 1. Removes it if it's `None` (means default).
1049 #
1050 # 2. Chooses a specific `class` property value.
1051 #
1052 # 3. Chooses a specific `byte-order`/`target-byte-order` property
1053 # value.
1054 #
1055 # 4. Chooses a specific `preferred-display-base` property value.
1056 #
1057 # This method also applies 1. to the trace node's `environment`
1058 # property.
1059 def _normalize_props(self):
1060 def normalize_byte_order_prop(parent_node: _MapNode, key: str):
1061 node = parent_node[key]
1062
1063 if node in ['be', 'big']:
1064 parent_node[key] = 'big-endian'
1065 elif node in ['le', 'little']:
1066 parent_node[key] = 'little-endian'
1067
1068 trace_node = self.config_node['trace']
1069 normalize_byte_order_prop(self.config_node, 'target-byte-order')
1070
1071 for parent_node, key in self._trace_type_props():
1072 node = parent_node[key]
1073
1074 if node is None:
1075 # a `None` property is equivalent to not having it
1076 del parent_node[key]
1077 continue
1078
1079 if key == 'class' and type(node) is str:
1080 # field type class aliases
1081 if node in ['uint', 'unsigned-int']:
1082 parent_node[key] = 'unsigned-integer'
1083 elif node in ['sint', 'signed-int']:
1084 parent_node[key] = 'signed-integer'
1085 elif node in ['uenum', 'unsigned-enum']:
1086 parent_node[key] = 'unsigned-enumeration'
1087 elif node in ['senum', 'signed-enum']:
1088 parent_node[key] = 'signed-enumeration'
1089 elif node == 'str':
1090 parent_node[key] = 'string'
1091 elif node == 'struct':
1092 parent_node[key] = 'structure'
1093 elif key == 'preferred-display-base' and type(node) is str:
1094 # display base aliases
1095 if node == 'bin':
1096 parent_node[key] = 'binary'
1097 elif node == 'oct':
1098 parent_node[key] = 'octal'
1099 elif node == 'dec':
1100 parent_node[key] = 'decimal'
1101 elif node == 'hex':
1102 parent_node[key] = 'hexadecimal'
1103
1104 prop_name = 'environment'
1105
1106 if prop_name in trace_node:
1107 node = trace_node[prop_name]
1108
1109 if node is None:
1110 del trace_node[prop_name]
1111
1112 # Sets the parser's target byte order.
1113 def _set_target_byte_order(self):
1114 self._target_byte_order_node = self.config_node['target-byte-order']
1115 self._target_byte_order = self._byte_order_from_node(self._target_byte_order_node)
1116
1117 # Processes the inclusions of the event type node `ev_type_node`,
1118 # returning the effective node.
1119 def _process_ev_type_node_include(self, ev_type_node: _MapNode) -> _MapNode:
1120 # Make sure the event type node is valid for the inclusion
1121 # processing stage.
1122 self._schema_validator.validate(ev_type_node, 'config/3/event-type-pre-include')
1123
1124 # process inclusions
1125 return self._process_node_include(ev_type_node, self._process_ev_type_node_include)
1126
1127 # Processes the inclusions of the stream type node
1128 # `stream_type_node`, returning the effective node.
1129 def _process_stream_type_node_include(self, stream_type_node: _MapNode) -> _MapNode:
1130 def process_children_include(stream_type_node: _MapNode):
1131 prop_name = 'event-types'
1132
1133 if prop_name in stream_type_node:
1134 ev_types_node = stream_type_node[prop_name]
1135
1136 for key in list(ev_types_node):
1137 ev_types_node[key] = self._process_ev_type_node_include(ev_types_node[key])
1138
1139 # Make sure the stream type node is valid for the inclusion
1140 # processing stage.
1141 self._schema_validator.validate(stream_type_node, 'config/3/stream-type-pre-include')
1142
1143 # process inclusions
1144 return self._process_node_include(stream_type_node, self._process_stream_type_node_include,
1145 process_children_include)
1146
1147 # Processes the inclusions of the clock type node `clk_type_node`,
1148 # returning the effective node.
1149 def _process_clk_type_node_include(self, clk_type_node: _MapNode) -> _MapNode:
1150 # Make sure the clock type node is valid for the inclusion
1151 # processing stage.
1152 self._schema_validator.validate(clk_type_node, 'config/3/clock-type-pre-include')
1153
1154 # process inclusions
1155 return self._process_node_include(clk_type_node, self._process_clk_type_node_include)
1156
1157 # Processes the inclusions of the trace type node `trace_type_node`,
1158 # returning the effective node.
1159 def _process_trace_type_node_include(self, trace_type_node: _MapNode) -> _MapNode:
1160 def process_children_include(trace_type_node: _MapNode):
1161 prop_name = 'clock-types'
1162
1163 if prop_name in trace_type_node:
1164 clk_types_node = trace_type_node[prop_name]
1165
1166 for key in list(clk_types_node):
1167 clk_types_node[key] = self._process_clk_type_node_include(clk_types_node[key])
1168
1169 prop_name = 'stream-types'
1170
1171 if prop_name in trace_type_node:
1172 stream_types_node = trace_type_node[prop_name]
1173
1174 for key in list(stream_types_node):
1175 stream_types_node[key] = self._process_stream_type_node_include(stream_types_node[key])
1176
1177 # Make sure the trace type node is valid for the inclusion
1178 # processing stage.
1179 self._schema_validator.validate(trace_type_node, 'config/3/trace-type-pre-include')
1180
1181 # process inclusions
1182 return self._process_node_include(trace_type_node, self._process_trace_type_node_include,
1183 process_children_include)
1184
1185 # Processes the inclusions of the trace node `trace_node`, returning
1186 # the effective node.
1187 def _process_trace_node_include(self, trace_node: _MapNode) -> _MapNode:
1188 def process_children_include(trace_node: _MapNode):
1189 prop_name = 'type'
1190 trace_node[prop_name] = self._process_trace_type_node_include(trace_node[prop_name])
1191
1192 # Make sure the trace node is valid for the inclusion processing
1193 # stage.
1194 self._schema_validator.validate(trace_node, 'config/3/trace-pre-include')
1195
1196 # process inclusions
1197 return self._process_node_include(trace_node, self._process_trace_node_include,
1198 process_children_include)
1199
1200 # Processes the inclusions of the configuration node, modifying it
1201 # during the process.
1202 def _process_config_includes(self):
1203 # Process inclusions in this order:
1204 #
1205 # 1. Clock type node and event type nodes (the order between
1206 # those is not important).
1207 #
1208 # 2. Stream type nodes.
1209 #
1210 # 3. Trace type node.
1211 #
1212 # 4. Trace node.
1213 #
1214 # This is because:
1215 #
1216 # * A trace node can include a trace type node, clock type
1217 # nodes, stream type nodes, and event type nodes.
1218 #
1219 # * A trace type node can include clock type nodes, stream type
1220 # nodes, and event type nodes.
1221 #
1222 # * A stream type node can include event type nodes.
1223 #
1224 # First, make sure the configuration node itself is valid for
1225 # the inclusion processing stage.
1226 self._schema_validator.validate(self.config_node, 'config/3/config-pre-include')
1227
1228 # Process trace node inclusions.
1229 #
1230 # self._process_trace_node_include() returns a new (or the same)
1231 # trace node without any `$include` property in it, recursively.
1232 self.config_node['trace'] = self._process_trace_node_include(self.config_node['trace'])
1233
1234 def _parse(self):
1235 # process configuration node inclusions
1236 self._process_config_includes()
1237
1238 # Expand field type nodes.
1239 #
1240 # This process:
1241 #
1242 # 1. Replaces field type aliases with "effective" field type
1243 # nodes, recursively.
1244 #
1245 # After this step, the `$field-type-aliases` property of the
1246 # trace type node is gone.
1247 #
1248 # 2. Applies inheritance, following the `$inherit` properties.
1249 #
1250 # After this step, field type nodes do not contain `$inherit`
1251 # properties.
1252 #
1253 # This is done blindly, in that the process _doesn't_ validate
1254 # field type nodes at this point.
1255 self._expand_fts()
1256
1257 # Substitute log level aliases.
1258 #
1259 # This process:
1260 #
1261 # 1. Replaces log level aliases in event type nodes with their
1262 # numeric equivalents as found in the `$log-level-aliases`
1263 # property of the trace type node.
1264 #
1265 # 2. Removes the `$log-level-aliases` property from the trace
1266 # type node.
1267 self._sub_log_level_aliases()
1268
1269 # At this point, the configuration node must be valid as an
1270 # effective configuration node.
1271 self._schema_validator.validate(self.config_node, 'config/3/config')
1272
1273 # Normalize properties.
1274 #
1275 # This process removes `None` properties and chooses specific
1276 # enumerators when aliases exist (for example, `big-endian`
1277 # instead of `be`).
1278 #
1279 # The goal of this is that, if the user then gets this parser's
1280 # `config_node` property, it has a normal and very readable
1281 # form.
1282 #
1283 # It also makes _create_config() easier to implement because it
1284 # doesn't need to check for `None` nodes or enumerator aliases.
1285 self._normalize_props()
1286
1287 # Set the target byte order.
1288 self._set_target_byte_order()
1289
1290 # Create a barectf configuration object from the configuration
1291 # node.
1292 self._create_config()
1293
1294 @property
1295 def config(self) -> barectf_config.Configuration:
1296 return self._config
1297
1298 @property
1299 def config_node(self) -> _MapNode:
1300 return typing.cast(barectf_config_parse_common._ConfigNodeV3, self._root_node).config_node
This page took 0.055496 seconds and 3 git commands to generate.