# The MIT License (MIT)
#
-# Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+# Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from barectf import metadata
-from barectf import codegen
-import datetime
-import barectf
-
-
-_bo_to_string_map = {
- metadata.ByteOrder.LE: 'le',
- metadata.ByteOrder.BE: 'be',
-}
-
-
-_encoding_to_string_map = {
- metadata.Encoding.NONE: 'none',
- metadata.Encoding.ASCII: 'ASCII',
- metadata.Encoding.UTF8: 'UTF8',
-}
-
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-def _bo_to_string(bo):
- return _bo_to_string_map[bo]
+import barectf.config as barectf_config
+import barectf.template as barectf_template
+from typing import List, Optional, Union
+import typing
-def _encoding_to_string(encoding):
- return _encoding_to_string_map[encoding]
+def _filt_disp_base_int(disp_base: barectf_config.DisplayBase) -> int:
+ return {
+ barectf_config.DisplayBase.BINARY: 2,
+ barectf_config.DisplayBase.OCTAL: 8,
+ barectf_config.DisplayBase.DECIMAL: 10,
+ barectf_config.DisplayBase.HEXADECIMAL: 16,
+ }[disp_base]
-def _bool_to_string(b):
- return 'true' if b else 'false'
+def _filt_int_ft_str(ft: barectf_config._FieldType) -> str:
+ return _INT_FT_TEMPL.render(ft=ft,
+ is_signed=isinstance(ft, barectf_config.SignedIntegerFieldType))
-def _gen_integer(t, cg):
- cg.add_line('integer {')
- cg.indent()
- cg.add_line('size = {};'.format(t.size))
- cg.add_line('align = {};'.format(t.align))
- cg.add_line('signed = {};'.format(_bool_to_string(t.signed)))
- cg.add_line('byte_order = {};'.format(_bo_to_string(t.byte_order)))
- cg.add_line('base = {};'.format(t.base))
- cg.add_line('encoding = {};'.format(_encoding_to_string(t.encoding)))
+def _gen_enum_ft(ft: barectf_config._FieldType) -> str:
+ return _ENUM_FT_TEMPL.render(ft=ft)
- if t.property_mappings:
- clock_name = t.property_mappings[0].object.name
- cg.add_line('map = clock.{}.value;'.format(clock_name))
- cg.unindent()
- cg.add_line('}')
+def _gen_real_ft(ft: barectf_config._FieldType) -> str:
+ return _REAL_FT_TEMPL.render(ft=ft)
-def _gen_float(t, cg):
- cg.add_line('floating_point {')
- cg.indent()
- cg.add_line('exp_dig = {};'.format(t.exp_size))
- cg.add_line('mant_dig = {};'.format(t.mant_size))
- cg.add_line('align = {};'.format(t.align))
- cg.add_line('byte_order = {};'.format(_bo_to_string(t.byte_order)))
- cg.unindent()
- cg.add_line('}')
+def _gen_str_ft(ft: barectf_config._FieldType) -> str:
+ return _STR_FT_TEMPL.render(ft=ft)
-def _gen_enum(t, cg):
- cg.add_line('enum : ')
- cg.add_glue()
- _gen_type(t.value_type, cg)
- cg.append_to_last_line(' {')
- cg.indent()
+def _filt_ft_lengths(ft: barectf_config._FieldType) -> List[Union[str, int]]:
+ lengths: List[Union[str, int]] = []
- for label, (mn, mx) in t.members.items():
- if mn == mx:
- rg = str(mn)
+ while isinstance(ft, barectf_config._ArrayFieldType):
+ if type(ft) is barectf_config.StaticArrayFieldType:
+ ft = typing.cast(barectf_config.StaticArrayFieldType, ft)
+ lengths.append(ft.length)
else:
- rg = '{} ... {}'.format(mn, mx)
-
- line = '"{}" = {},'.format(label, rg)
- cg.add_line(line)
-
- cg.unindent()
- cg.add_line('}')
-
-
-def _gen_string(t, cg):
- cg.add_line('string {')
- cg.indent()
- cg.add_line('encoding = {};'.format(_encoding_to_string(t.encoding)))
- cg.unindent()
- cg.add_line('}')
-
-
-def _find_deepest_array_element_type(t):
- if type(t) is metadata.Array:
- return _find_deepest_array_element_type(t.element_type)
-
- return t
-
-
-def _fill_array_lengths(t, lengths):
- if type(t) is metadata.Array:
- lengths.append(t.length)
- _fill_array_lengths(t.element_type, lengths)
-
-
-def _gen_struct_variant_entry(name, t, cg):
- real_t = _find_deepest_array_element_type(t)
- _gen_type(real_t, cg)
- cg.append_to_last_line(' {}'.format(name))
-
- # array
- lengths = []
- _fill_array_lengths(t, lengths)
-
- if lengths:
- for length in reversed(lengths):
- cg.append_to_last_line('[{}]'.format(length))
+ assert type(ft) is barectf_config.DynamicArrayFieldType
+ ft = typing.cast(barectf_config.DynamicArrayFieldType, ft)
+ lengths.append(typing.cast(str, ft._length_ft_member_name))
- cg.append_to_last_line(';')
+ ft = ft.element_field_type
+ return lengths
-def _gen_struct(t, cg):
- cg.add_line('struct {')
- cg.indent()
- for field_name, field_type in t.fields.items():
- _gen_struct_variant_entry(field_name, field_type, cg)
+def _filt_deepest_ft(ft: barectf_config._FieldType) -> barectf_config._FieldType:
+ while isinstance(ft, barectf_config._ArrayFieldType):
+ ft = ft.element_field_type
- cg.unindent()
+ return ft
- if not t.fields:
- cg.add_glue()
- cg.add_line('}} align({})'.format(t.min_align))
+def _gen_struct_ft(ft: barectf_config._FieldType) -> str:
+ return _STRUCT_FT_TEMPL.render(ft=ft)
-def _gen_variant(t, cg):
- cg.add_line('variant <{}> {{'.format(t.tag))
- cg.indent()
-
- for type_name, type_type in t.types.items():
- _gen_struct_variant_entry(type_name, type_type, cg)
-
- cg.unindent()
-
- if not t.types:
- cg.add_glue()
-
- cg.add_line('}')
-
-
-_type_to_gen_type_func = {
- metadata.Integer: _gen_integer,
- metadata.FloatingPoint: _gen_float,
- metadata.Enum: _gen_enum,
- metadata.String: _gen_string,
- metadata.Struct: _gen_struct,
- metadata.Variant: _gen_variant,
+_FT_CLS_TO_GEN_FT_FUNC = {
+ barectf_config.UnsignedIntegerFieldType: _filt_int_ft_str,
+ barectf_config.SignedIntegerFieldType: _filt_int_ft_str,
+ barectf_config.UnsignedEnumerationFieldType: _gen_enum_ft,
+ barectf_config.SignedEnumerationFieldType: _gen_enum_ft,
+ barectf_config.RealFieldType: _gen_real_ft,
+ barectf_config.StringFieldType: _gen_str_ft,
+ barectf_config.StructureFieldType: _gen_struct_ft,
}
-def _gen_type(t, cg):
- _type_to_gen_type_func[type(t)](t, cg)
-
-
-def _gen_entity(name, t, cg):
- cg.add_line('{} := '.format(name))
- cg.add_glue()
- _gen_type(t, cg)
- cg.append_to_last_line(';')
-
-
-def _gen_start_block(name, cg):
- cg.add_line('{} {{'.format(name))
- cg.indent()
-
-
-def _gen_end_block(cg):
- cg.unindent()
- cg.add_line('};')
- cg.add_empty_line()
-
-
-def _gen_trace_block(meta, cg):
- trace = meta.trace
-
- _gen_start_block('trace', cg)
- cg.add_line('major = 1;')
- cg.add_line('minor = 8;')
- line = 'byte_order = {};'.format(_bo_to_string(trace.byte_order))
- cg.add_line(line)
-
- if trace.uuid is not None:
- line = 'uuid = "{}";'.format(trace.uuid)
- cg.add_line(line)
-
- if trace.packet_header_type is not None:
- _gen_entity('packet.header', trace.packet_header_type, cg)
-
- _gen_end_block(cg)
+def _filt_ft_str(ft: barectf_config._FieldType) -> str:
+ return _FT_CLS_TO_GEN_FT_FUNC[type(ft)](ft)
-def _escape_literal_string(s):
- esc = s.replace('\\', '\\\\')
- esc = esc.replace('\n', '\\n')
- esc = esc.replace('\r', '\\r')
- esc = esc.replace('\t', '\\t')
- esc = esc.replace('"', '\\"')
-
- return esc
-
-
-def _gen_env_block(meta, cg):
- env = meta.env
-
- if not env:
- return
-
- _gen_start_block('env', cg)
-
- for name, value in env.items():
- if type(value) is int:
- value_string = str(value)
- else:
- value_string = '"{}"'.format(_escape_literal_string(value))
-
- cg.add_line('{} = {};'.format(name, value_string))
-
- _gen_end_block(cg)
-
-
-def _gen_clock_block(clock, cg):
- _gen_start_block('clock', cg)
- cg.add_line('name = {};'.format(clock.name))
-
- if clock.description is not None:
- desc = _escape_literal_string(clock.description)
- cg.add_line('description = "{}";'.format(desc))
-
- if clock.uuid is not None:
- cg.add_line('uuid = "{}";'.format(clock.uuid))
-
- cg.add_line('freq = {};'.format(clock.freq))
- cg.add_line('offset_s = {};'.format(clock.offset_seconds))
- cg.add_line('offset = {};'.format(clock.offset_cycles))
- cg.add_line('precision = {};'.format(clock.error_cycles))
- cg.add_line('absolute = {};'.format(_bool_to_string(clock.absolute)))
- _gen_end_block(cg)
-
-
-def _gen_clock_blocks(meta, cg):
- clocks = meta.clocks
-
- for clock in clocks.values():
- _gen_clock_block(clock, cg)
-
-
-def _gen_stream_block(stream, cg):
- cg.add_cc_line(stream.name.replace('/', ''))
- _gen_start_block('stream', cg)
- cg.add_line('id = {};'.format(stream.id))
-
- if stream.packet_context_type is not None:
- _gen_entity('packet.context', stream.packet_context_type, cg)
-
- if stream.event_header_type is not None:
- _gen_entity('event.header', stream.event_header_type, cg)
-
- if stream.event_context_type is not None:
- _gen_entity('event.context', stream.event_context_type, cg)
-
- _gen_end_block(cg)
-
-
-def _gen_event_block(stream, ev, cg):
- _gen_start_block('event', cg)
- cg.add_line('name = "{}";'.format(ev.name))
- cg.add_line('id = {};'.format(ev.id))
- cg.add_line('stream_id = {};'.format(stream.id))
- cg.append_cc_to_last_line(stream.name.replace('/', ''))
-
- if ev.log_level is not None:
- cg.add_line('loglevel = {};'.format(ev.log_level))
-
- if ev.context_type is not None:
- _gen_entity('context', ev.context_type, cg)
-
- if ev.payload_type is not None:
- _gen_entity('fields', ev.payload_type, cg)
-
- _gen_end_block(cg)
-
-
-def _gen_streams_events_blocks(meta, cg):
- for stream in meta.streams.values():
- _gen_stream_block(stream, cg)
-
- for ev in stream.events.values():
- _gen_event_block(stream, ev, cg)
-
-
-def from_metadata(meta):
- cg = codegen.CodeGenerator('\t')
+_TEMPL_FILTERS = {
+ 'disp_base_int': _filt_disp_base_int,
+ 'int_ft_str': _filt_int_ft_str,
+ 'ft_str': _filt_ft_str,
+ 'ft_lengths': _filt_ft_lengths,
+ 'deepest_ft': _filt_deepest_ft,
+}
- # version/magic
- cg.add_line('/* CTF 1.8 */')
- cg.add_empty_line()
- cg.add_line('/*')
- v = barectf.__version__
- line = ' * The following TSDL code was generated by barectf v{}'.format(v)
- cg.add_line(line)
- now = datetime.datetime.now()
- line = ' * on {}.'.format(now)
- cg.add_line(line)
- cg.add_line(' *')
- cg.add_line(' * For more details, see <https://github.com/efficios/barectf>.')
- cg.add_line(' */')
- cg.add_empty_line()
- # trace block
- _gen_trace_block(meta, cg)
+def _create_template(name: str, is_file_template: bool = False,
+ cfg: Optional[barectf_config.Configuration] = None) -> barectf_template._Template:
+ return barectf_template._Template(f'metadata/{name}', is_file_template, cfg,
+ typing.cast(barectf_template._Filters, _TEMPL_FILTERS))
- # environment
- _gen_env_block(meta, cg)
- # clocks
- _gen_clock_blocks(meta, cg)
+_ENUM_FT_TEMPL = _create_template('enum-ft.j2')
+_INT_FT_TEMPL = _create_template('int-ft.j2')
+_REAL_FT_TEMPL = _create_template('real-ft.j2')
+_STR_FT_TEMPL = _create_template('str-ft.j2')
+_STRUCT_FT_TEMPL = _create_template('struct-ft.j2')
- # streams and contained events
- _gen_streams_events_blocks(meta, cg)
- return cg.code
+def _from_config(cfg: barectf_config.Configuration) -> str:
+ return _create_template('metadata.j2', True, cfg).render()