1 # Copyright (C) 2014-2016 Intel Corporation. All Rights Reserved.
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the "Software"),
5 # to deal in the Software without restriction, including without limitation
6 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 # and/or sell copies of the Software, and to permit persons to whom the
8 # Software is furnished to do so, subject to the following conditions:
10 # The above copyright notice and this permission notice (including the next
11 # paragraph) shall be included in all copies or substantial portions of the
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 from __future__
import print_function
27 from gen_common
import *
29 def parse_event_fields(lines
, idx
, event_dict
):
31 Parses lines from a proto file that contain an event definition and stores it in event_dict
36 # record all fields in event definition.
37 # note: we don't check if there's a leading brace.
38 while not end_of_event
and idx
< len(lines
):
39 line
= lines
[idx
].rstrip()
42 # ex 1: uint32_t numSampleCLZExecuted; // number of sample_cl_z instructions executed
43 # ex 2: char reason[256]; // size of reason
44 match
= re
.match(r
'^(\s*)([\w\*]+)(\s+)([\w]+)(\[\d+\])*;\s*(\/\/.*)*$', line
)
49 # group 5 [array size]
54 "type": match
.group(2),
55 "name": match
.group(4),
56 "size": int(match
.group(5)[1:-1]) if match
.group(5) else 1,
57 "desc": match
.group(6)[2:].strip() if match
.group(6) else "",
61 end_of_event
= re
.match(r
'(\s*)};', line
)
63 event_dict
['fields'] = fields
64 event_dict
['num_fields'] = len(fields
)
68 def parse_enums(lines
, idx
, event_dict
):
70 Parses lines from a proto file that contain an enum definition and stores it in event_dict
75 # record all enum values in enumeration
76 # note: we don't check if there's a leading brace.
77 while not end_of_enum
and idx
< len(lines
):
78 line
= lines
[idx
].rstrip()
81 preprocessor
= re
.search(r
'#if|#endif', line
)
84 enum
= re
.match(r
'(\s*)(\w+)(\s*)', line
)
87 enum_names
.append(line
)
89 end_of_enum
= re
.match(r
'(\s*)};', line
)
91 event_dict
['names'] = enum_names
94 def parse_protos(files
, verbose
=False):
96 Parses a proto file and returns a dictionary of event definitions
103 # "defs": { // dict of event definitions where keys are 'group_name::event_name"
105 # "ApiStat::DrawInfoEvent": {
107 # "group": "ApiStat",
108 # "name": "DrawInfoEvent", // name of event without 'group_name::' prefix
112 # "type": "uint32_t",
122 # "groups": { // dict of groups with lists of event keys
124 # "ApiStat::DispatchEvent",
125 # "ApiStat::DrawInfoEvent",
129 # "Framework::ThreadStartApiEvent",
130 # "Framework::ThreadStartWorkerEvent",
135 # "map": { // map of event ids to match archrast output to event key
136 # "1": "Framework::ThreadStartApiEvent",
137 # "2": "Framework::ThreadStartWorkerEvent",
138 # "3": "ApiStat::DrawInfoEvent",
142 # "enums": { ... } // enums follow similar defs, map (groups?) structure
147 'defs': {}, # event dictionary containing events with their fields
148 'map': {}, # dictionary to map event ids to event names
149 'groups': {} # event keys stored by groups
160 if type(files
) is not list:
163 for filename
in files
:
165 print("Parsing proto file: %s" % os
.path
.normpath(filename
))
167 with
open(filename
, 'r') as f
:
168 lines
= f
.readlines()
172 while idx
< len(lines
):
173 line
= lines
[idx
].strip()
176 # If currently processing a brief, keep processing or change state
178 match
= re
.match(r
'^\s*\/\/\/\s*(.*)$', line
) # i.e. "/// more event desc..."
180 brief
.append(match
.group(1).strip())
185 # Match event/enum brief
186 match
= re
.match(r
'^\s*\/\/\/\s*@(brief|breif)\s*(.*)$', line
) # i.e. "///@brief My event desc..."
189 brief
.append(match
.group(2).strip())
192 # Match event definition
193 match
= re
.match(r
'event(\s*)(((\w*)::){0,1}(\w+))', line
) # i.e. "event SWTag::CounterEvent"
197 # Parse event attributes
198 event_key
= match
.group(2) # i.e. SWTag::CounterEvent
199 event_group
= match
.group(4) if match
.group(4) else "" # i.e. SWTag
200 event_name
= match
.group(5) # i.e. CounterEvent
202 # Define event attributes
205 'group': event_group
,
207 'desc': ' '.join(brief
)
209 # Add period at end of event desc if necessary
210 if event
["desc"] and event
["desc"][-1] != '.':
216 # Now add event fields
217 idx
= parse_event_fields(lines
, idx
, event
)
219 # Register event and mapping
220 protos
['events']['defs'][event_key
] = event
221 protos
['events']['map'][event_id
] = event_key
225 # Match enum definition
226 match
= re
.match(r
'enum(\s*)(\w+)', line
)
230 # Parse enum attributes
231 enum_name
= match
.group(2)
236 'desc': ' '.join(brief
)
238 # Add period at end of event desc if necessary
239 if enum
["desc"] and enum
["desc"][-1] != '.':
245 # Now add enum fields
246 idx
= parse_enums(lines
, idx
, enum
)
248 # Register enum and mapping
249 protos
['enums']['defs'][enum_name
] = enum
250 protos
['enums']['map'][enum_id
] = enum_name
254 # Sort and group events
255 event_groups
= protos
['events']['groups']
256 for key
in sorted(protos
['events']['defs']):
257 group
= protos
['events']['defs'][key
]['group']
258 if group
not in event_groups
:
259 event_groups
[group
] = []
260 event_groups
[group
].append(key
)
268 parser
= ArgumentParser()
269 parser
.add_argument("--proto", "-p", dest
="protos", nargs
='+', help="Path to all proto file(s) to process. Accepts one or more paths (i.e. events.proto and events_private.proto)", required
=True)
270 parser
.add_argument("--output-dir", help="Output dir (defaults to ./codegen). Will create folder if it does not exist.", required
=False, default
="codegen")
271 parser
.add_argument("--verbose", "-v", help="Verbose", action
="store_true")
272 args
= parser
.parse_args()
274 if not os
.path
.exists(args
.output_dir
):
275 MakeDir(args
.output_dir
)
277 for f
in args
.protos
:
278 if not os
.path
.exists(f
):
279 print('Error: Could not find proto file %s' % f
, file=sys
.stderr
)
282 # Parse each proto file and add to protos container
283 protos
= parse_protos(args
.protos
, args
.verbose
)
286 ["gen_ar_event.hpp", ""],
287 ["gen_ar_event.cpp", ""],
288 ["gen_ar_eventhandler.hpp", "gen_ar_event.hpp"],
289 ["gen_ar_eventhandlerfile.hpp", "gen_ar_eventhandler.hpp"]
295 # Delete existing files
298 output_fullpath
= os
.path
.join(args
.output_dir
, filename
)
299 if os
.path
.exists(output_fullpath
):
301 print("Deleting existing file: %s" % output_fullpath
)
302 os
.remove(output_fullpath
)
304 # Generate files from templates
305 print("Generating c++ from proto files...")
309 curdir
= os
.path
.dirname(os
.path
.abspath(__file__
))
310 template_file
= os
.path
.join(curdir
, 'templates', filename
)
311 output_fullpath
= os
.path
.join(args
.output_dir
, filename
)
314 print("Generating: %s" % output_fullpath
)
315 MakoTemplateWriter
.to_file(template_file
, output_fullpath
,
319 event_header
=event_header
)
321 except Exception as e
:
327 if __name__
== '__main__':