Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
4a90140d | 3 | # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com> |
e5aa0be3 | 4 | # |
1378f213 PP |
5 | # Permission is hereby granted, free of charge, to any person obtaining |
6 | # a copy of this software and associated documentation files (the | |
7 | # "Software"), to deal in the Software without restriction, including | |
8 | # without limitation the rights to use, copy, modify, merge, publish, | |
9 | # distribute, sublicense, and/or sell copies of the Software, and to | |
10 | # permit persons to whom the Software is furnished to do so, subject to | |
11 | # the following conditions: | |
e5aa0be3 | 12 | # |
1378f213 PP |
13 | # The above copyright notice and this permission notice shall be |
14 | # included in all copies or substantial portions of the Software. | |
e5aa0be3 | 15 | # |
1378f213 PP |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
21 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
22 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
e5aa0be3 PP |
23 | |
24 | from barectf import metadata | |
25 | from barectf import codegen | |
26 | import datetime | |
27 | import barectf | |
28 | ||
29 | ||
30 | _bo_to_string_map = { | |
31 | metadata.ByteOrder.LE: 'le', | |
32 | metadata.ByteOrder.BE: 'be', | |
33 | } | |
34 | ||
35 | ||
36 | _encoding_to_string_map = { | |
37 | metadata.Encoding.NONE: 'none', | |
38 | metadata.Encoding.ASCII: 'ASCII', | |
39 | metadata.Encoding.UTF8: 'UTF8', | |
40 | } | |
41 | ||
42 | ||
43 | def _bo_to_string(bo): | |
44 | return _bo_to_string_map[bo] | |
45 | ||
46 | ||
47 | def _encoding_to_string(encoding): | |
48 | return _encoding_to_string_map[encoding] | |
49 | ||
50 | ||
51 | def _bool_to_string(b): | |
52 | return 'true' if b else 'false' | |
53 | ||
54 | ||
55 | def _gen_integer(t, cg): | |
56 | cg.add_line('integer {') | |
57 | cg.indent() | |
58 | cg.add_line('size = {};'.format(t.size)) | |
59 | cg.add_line('align = {};'.format(t.align)) | |
60 | cg.add_line('signed = {};'.format(_bool_to_string(t.signed))) | |
61 | cg.add_line('byte_order = {};'.format(_bo_to_string(t.byte_order))) | |
62 | cg.add_line('base = {};'.format(t.base)) | |
63 | cg.add_line('encoding = {};'.format(_encoding_to_string(t.encoding))) | |
64 | ||
65 | if t.property_mappings: | |
66 | clock_name = t.property_mappings[0].object.name | |
67 | cg.add_line('map = clock.{}.value;'.format(clock_name)) | |
68 | ||
69 | cg.unindent() | |
70 | cg.add_line('}') | |
71 | ||
72 | ||
73 | def _gen_float(t, cg): | |
74 | cg.add_line('floating_point {') | |
75 | cg.indent() | |
76 | cg.add_line('exp_dig = {};'.format(t.exp_size)) | |
77 | cg.add_line('mant_dig = {};'.format(t.mant_size)) | |
78 | cg.add_line('align = {};'.format(t.align)) | |
79 | cg.add_line('byte_order = {};'.format(_bo_to_string(t.byte_order))) | |
80 | cg.unindent() | |
81 | cg.add_line('}') | |
82 | ||
83 | ||
84 | def _gen_enum(t, cg): | |
85 | cg.add_line('enum : ') | |
86 | cg.add_glue() | |
87 | _gen_type(t.value_type, cg) | |
88 | cg.append_to_last_line(' {') | |
89 | cg.indent() | |
90 | ||
91 | for label, (mn, mx) in t.members.items(): | |
92 | if mn == mx: | |
93 | rg = str(mn) | |
94 | else: | |
95 | rg = '{} ... {}'.format(mn, mx) | |
96 | ||
97 | line = '"{}" = {},'.format(label, rg) | |
98 | cg.add_line(line) | |
99 | ||
100 | cg.unindent() | |
101 | cg.add_line('}') | |
102 | ||
103 | ||
104 | def _gen_string(t, cg): | |
105 | cg.add_line('string {') | |
106 | cg.indent() | |
107 | cg.add_line('encoding = {};'.format(_encoding_to_string(t.encoding))) | |
108 | cg.unindent() | |
109 | cg.add_line('}') | |
110 | ||
111 | ||
112 | def _find_deepest_array_element_type(t): | |
113 | if type(t) is metadata.Array: | |
114 | return _find_deepest_array_element_type(t.element_type) | |
115 | ||
116 | return t | |
117 | ||
118 | ||
119 | def _fill_array_lengths(t, lengths): | |
120 | if type(t) is metadata.Array: | |
121 | lengths.append(t.length) | |
122 | _fill_array_lengths(t.element_type, lengths) | |
123 | ||
124 | ||
419ada44 | 125 | def _gen_struct_entry(name, t, cg): |
e5aa0be3 PP |
126 | real_t = _find_deepest_array_element_type(t) |
127 | _gen_type(real_t, cg) | |
128 | cg.append_to_last_line(' {}'.format(name)) | |
129 | ||
130 | # array | |
131 | lengths = [] | |
132 | _fill_array_lengths(t, lengths) | |
133 | ||
134 | if lengths: | |
135 | for length in reversed(lengths): | |
136 | cg.append_to_last_line('[{}]'.format(length)) | |
137 | ||
138 | cg.append_to_last_line(';') | |
139 | ||
140 | ||
141 | def _gen_struct(t, cg): | |
142 | cg.add_line('struct {') | |
143 | cg.indent() | |
144 | ||
145 | for field_name, field_type in t.fields.items(): | |
419ada44 | 146 | _gen_struct_entry(field_name, field_type, cg) |
e5aa0be3 PP |
147 | |
148 | cg.unindent() | |
149 | ||
150 | if not t.fields: | |
151 | cg.add_glue() | |
152 | ||
153 | cg.add_line('}} align({})'.format(t.min_align)) | |
154 | ||
155 | ||
e5aa0be3 PP |
156 | _type_to_gen_type_func = { |
157 | metadata.Integer: _gen_integer, | |
158 | metadata.FloatingPoint: _gen_float, | |
159 | metadata.Enum: _gen_enum, | |
160 | metadata.String: _gen_string, | |
161 | metadata.Struct: _gen_struct, | |
e5aa0be3 PP |
162 | } |
163 | ||
164 | ||
165 | def _gen_type(t, cg): | |
166 | _type_to_gen_type_func[type(t)](t, cg) | |
167 | ||
168 | ||
169 | def _gen_entity(name, t, cg): | |
170 | cg.add_line('{} := '.format(name)) | |
171 | cg.add_glue() | |
172 | _gen_type(t, cg) | |
173 | cg.append_to_last_line(';') | |
174 | ||
175 | ||
176 | def _gen_start_block(name, cg): | |
177 | cg.add_line('{} {{'.format(name)) | |
178 | cg.indent() | |
179 | ||
180 | ||
181 | def _gen_end_block(cg): | |
182 | cg.unindent() | |
183 | cg.add_line('};') | |
184 | cg.add_empty_line() | |
185 | ||
186 | ||
187 | def _gen_trace_block(meta, cg): | |
188 | trace = meta.trace | |
189 | ||
190 | _gen_start_block('trace', cg) | |
191 | cg.add_line('major = 1;') | |
192 | cg.add_line('minor = 8;') | |
193 | line = 'byte_order = {};'.format(_bo_to_string(trace.byte_order)) | |
194 | cg.add_line(line) | |
195 | ||
196 | if trace.uuid is not None: | |
197 | line = 'uuid = "{}";'.format(trace.uuid) | |
198 | cg.add_line(line) | |
199 | ||
200 | if trace.packet_header_type is not None: | |
201 | _gen_entity('packet.header', trace.packet_header_type, cg) | |
202 | ||
203 | _gen_end_block(cg) | |
204 | ||
205 | ||
206 | def _escape_literal_string(s): | |
207 | esc = s.replace('\\', '\\\\') | |
208 | esc = esc.replace('\n', '\\n') | |
209 | esc = esc.replace('\r', '\\r') | |
210 | esc = esc.replace('\t', '\\t') | |
211 | esc = esc.replace('"', '\\"') | |
212 | ||
213 | return esc | |
214 | ||
215 | ||
216 | def _gen_env_block(meta, cg): | |
217 | env = meta.env | |
218 | ||
219 | if not env: | |
220 | return | |
221 | ||
222 | _gen_start_block('env', cg) | |
223 | ||
224 | for name, value in env.items(): | |
225 | if type(value) is int: | |
226 | value_string = str(value) | |
227 | else: | |
228 | value_string = '"{}"'.format(_escape_literal_string(value)) | |
229 | ||
230 | cg.add_line('{} = {};'.format(name, value_string)) | |
231 | ||
232 | _gen_end_block(cg) | |
233 | ||
234 | ||
235 | def _gen_clock_block(clock, cg): | |
236 | _gen_start_block('clock', cg) | |
237 | cg.add_line('name = {};'.format(clock.name)) | |
238 | ||
239 | if clock.description is not None: | |
240 | desc = _escape_literal_string(clock.description) | |
241 | cg.add_line('description = "{}";'.format(desc)) | |
242 | ||
243 | if clock.uuid is not None: | |
244 | cg.add_line('uuid = "{}";'.format(clock.uuid)) | |
245 | ||
246 | cg.add_line('freq = {};'.format(clock.freq)) | |
247 | cg.add_line('offset_s = {};'.format(clock.offset_seconds)) | |
248 | cg.add_line('offset = {};'.format(clock.offset_cycles)) | |
249 | cg.add_line('precision = {};'.format(clock.error_cycles)) | |
250 | cg.add_line('absolute = {};'.format(_bool_to_string(clock.absolute))) | |
251 | _gen_end_block(cg) | |
252 | ||
253 | ||
254 | def _gen_clock_blocks(meta, cg): | |
255 | clocks = meta.clocks | |
256 | ||
257 | for clock in clocks.values(): | |
258 | _gen_clock_block(clock, cg) | |
259 | ||
260 | ||
202fbe77 | 261 | def _gen_stream_block(meta, stream, cg): |
e5aa0be3 PP |
262 | cg.add_cc_line(stream.name.replace('/', '')) |
263 | _gen_start_block('stream', cg) | |
202fbe77 PP |
264 | |
265 | if meta.trace.packet_header_type is not None: | |
266 | if 'stream_id' in meta.trace.packet_header_type.fields: | |
267 | cg.add_line('id = {};'.format(stream.id)) | |
e5aa0be3 PP |
268 | |
269 | if stream.packet_context_type is not None: | |
270 | _gen_entity('packet.context', stream.packet_context_type, cg) | |
271 | ||
272 | if stream.event_header_type is not None: | |
273 | _gen_entity('event.header', stream.event_header_type, cg) | |
274 | ||
275 | if stream.event_context_type is not None: | |
276 | _gen_entity('event.context', stream.event_context_type, cg) | |
277 | ||
278 | _gen_end_block(cg) | |
279 | ||
280 | ||
202fbe77 | 281 | def _gen_event_block(meta, stream, ev, cg): |
e5aa0be3 PP |
282 | _gen_start_block('event', cg) |
283 | cg.add_line('name = "{}";'.format(ev.name)) | |
284 | cg.add_line('id = {};'.format(ev.id)) | |
202fbe77 PP |
285 | |
286 | if meta.trace.packet_header_type is not None: | |
287 | if 'stream_id' in meta.trace.packet_header_type.fields: | |
288 | cg.add_line('stream_id = {};'.format(stream.id)) | |
289 | ||
e5aa0be3 PP |
290 | cg.append_cc_to_last_line(stream.name.replace('/', '')) |
291 | ||
292 | if ev.log_level is not None: | |
721eb4df PP |
293 | add_fmt = '' |
294 | ||
295 | if ev.log_level.name is not None: | |
296 | name = ev.log_level.name.replace('*/', '') | |
297 | add_fmt = ' /* {} */'.format(name) | |
298 | ||
299 | fmt = 'loglevel = {};' + add_fmt | |
300 | cg.add_line(fmt.format(ev.log_level.value)) | |
e5aa0be3 PP |
301 | |
302 | if ev.context_type is not None: | |
303 | _gen_entity('context', ev.context_type, cg) | |
304 | ||
305 | if ev.payload_type is not None: | |
306 | _gen_entity('fields', ev.payload_type, cg) | |
13eaac62 | 307 | else: |
7f4429f2 | 308 | fake_payload = metadata.Struct(8) |
13eaac62 | 309 | _gen_entity('fields', fake_payload, cg) |
e5aa0be3 PP |
310 | |
311 | _gen_end_block(cg) | |
312 | ||
313 | ||
314 | def _gen_streams_events_blocks(meta, cg): | |
315 | for stream in meta.streams.values(): | |
202fbe77 | 316 | _gen_stream_block(meta, stream, cg) |
e5aa0be3 PP |
317 | |
318 | for ev in stream.events.values(): | |
202fbe77 | 319 | _gen_event_block(meta, stream, ev, cg) |
e5aa0be3 PP |
320 | |
321 | ||
322 | def from_metadata(meta): | |
323 | cg = codegen.CodeGenerator('\t') | |
324 | ||
325 | # version/magic | |
326 | cg.add_line('/* CTF 1.8 */') | |
327 | cg.add_empty_line() | |
cfb53ba6 PP |
328 | cg.add_line('''/* |
329 | * The MIT License (MIT) | |
330 | * | |
1378f213 | 331 | * Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com> |
cfb53ba6 PP |
332 | * |
333 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
334 | * of this software and associated documentation files (the "Software"), to deal | |
335 | * in the Software without restriction, including without limitation the rights | |
336 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
337 | * copies of the Software, and to permit persons to whom the Software is | |
338 | * furnished to do so, subject to the following conditions: | |
339 | * | |
340 | * The above copyright notice and this permission notice shall be included in | |
341 | * all copies or substantial portions of the Software. | |
342 | * | |
343 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
344 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
345 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
346 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
347 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
348 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
349 | * THE SOFTWARE. | |
350 | * | |
351 | * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
352 | *''') | |
e5aa0be3 PP |
353 | v = barectf.__version__ |
354 | line = ' * The following TSDL code was generated by barectf v{}'.format(v) | |
355 | cg.add_line(line) | |
356 | now = datetime.datetime.now() | |
357 | line = ' * on {}.'.format(now) | |
358 | cg.add_line(line) | |
359 | cg.add_line(' *') | |
a3ebf585 | 360 | cg.add_line(' * For more details, see <http://barectf.org>.') |
e5aa0be3 PP |
361 | cg.add_line(' */') |
362 | cg.add_empty_line() | |
363 | ||
364 | # trace block | |
365 | _gen_trace_block(meta, cg) | |
366 | ||
367 | # environment | |
368 | _gen_env_block(meta, cg) | |
369 | ||
370 | # clocks | |
371 | _gen_clock_blocks(meta, cg) | |
372 | ||
373 | # streams and contained events | |
374 | _gen_streams_events_blocks(meta, cg) | |
375 | ||
376 | return cg.code |