2016-08-29 20:56:03 +01:00
# Copyright (C) 2014-2016 Intel Corporation. All Rights Reserved.
#
# 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 (including the next
# paragraph) 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.
# Python source
import os
import sys
import re
2018-04-09 18:51:14 +01:00
from gen_common import *
2016-08-29 20:56:03 +01:00
def parse_event_fields ( lines , idx , event_dict ) :
2018-09-17 20:50:47 +01:00
"""
Parses lines from a proto file that contain an event definition and stores it in event_dict
"""
2018-09-07 21:17:53 +01:00
fields = [ ]
2016-08-29 20:56:03 +01:00
end_of_event = False
# record all fields in event definition.
# note: we don't check if there's a leading brace.
while not end_of_event and idx < len ( lines ) :
line = lines [ idx ] . rstrip ( )
idx + = 1
2019-08-01 13:30:58 +01:00
# ex 1: uint32_t numSampleCLZExecuted; // number of sample_cl_z instructions executed
# ex 2: char reason[256]; // size of reason
match = re . match ( r ' ^( \ s*)([ \ w \ *]+)( \ s+)([ \ w]+)( \ [ \ d+ \ ])*; \ s*( \ / \ /.*)*$ ' , line )
# group 1 -
# group 2 type
# group 3 -
# group 4 name
# group 5 [array size]
# group 6 //comment
2016-08-29 20:56:03 +01:00
2018-09-07 21:17:53 +01:00
if match :
field = {
" type " : match . group ( 2 ) ,
2019-08-01 13:30:58 +01:00
" name " : match . group ( 4 ) ,
" size " : int ( match . group ( 5 ) [ 1 : - 1 ] ) if match . group ( 5 ) else 1 ,
" desc " : match . group ( 6 ) [ 2 : ] . strip ( ) if match . group ( 6 ) else " " ,
2018-09-07 21:17:53 +01:00
}
fields . append ( field )
2016-08-29 20:56:03 +01:00
2017-03-16 18:44:52 +00:00
end_of_event = re . match ( r ' ( \ s*)}; ' , line )
2016-08-29 20:56:03 +01:00
2018-09-07 21:17:53 +01:00
event_dict [ ' fields ' ] = fields
event_dict [ ' num_fields ' ] = len ( fields )
2016-10-15 23:35:26 +01:00
2016-08-29 20:56:03 +01:00
return idx
def parse_enums ( lines , idx , event_dict ) :
2018-09-17 20:50:47 +01:00
"""
Parses lines from a proto file that contain an enum definition and stores it in event_dict
"""
2016-08-29 20:56:03 +01:00
enum_names = [ ]
end_of_enum = False
# record all enum values in enumeration
# note: we don't check if there's a leading brace.
while not end_of_enum and idx < len ( lines ) :
line = lines [ idx ] . rstrip ( )
idx + = 1
2017-03-16 18:44:52 +00:00
preprocessor = re . search ( r ' #if|#endif ' , line )
2016-08-29 20:56:03 +01:00
if not preprocessor :
2017-03-16 18:44:52 +00:00
enum = re . match ( r ' ( \ s*)( \ w+)( \ s*) ' , line )
2016-08-29 20:56:03 +01:00
if enum :
enum_names . append ( line )
2017-03-16 18:44:52 +00:00
end_of_enum = re . match ( r ' ( \ s*)}; ' , line )
2016-08-29 20:56:03 +01:00
event_dict [ ' names ' ] = enum_names
return idx
2018-09-04 19:41:39 +01:00
def parse_protos ( files , verbose = False ) :
2018-09-17 20:50:47 +01:00
"""
Parses a proto file and returns a dictionary of event definitions
"""
2019-08-01 13:30:58 +01:00
# Protos structure:
#
# {
# "events": {
# "defs": { // dict of event definitions where keys are 'group_name::event_name"
# ...,
# "ApiStat::DrawInfoEvent": {
# "id": 3,
# "group": "ApiStat",
# "name": "DrawInfoEvent", // name of event without 'group_name::' prefix
# "desc": "",
# "fields": [
# {
# "type": "uint32_t",
# "name": "drawId",
# "size": 1,
# "desc": "",
# },
# ...
# ]
# },
# ...
# },
# "groups": { // dict of groups with lists of event keys
# "ApiStat": [
# "ApiStat::DispatchEvent",
# "ApiStat::DrawInfoEvent",
# ...
# ],
# "Framework": [
# "Framework::ThreadStartApiEvent",
# "Framework::ThreadStartWorkerEvent",
# ...
# ],
# ...
# },
# "map": { // map of event ids to match archrast output to event key
# "1": "Framework::ThreadStartApiEvent",
# "2": "Framework::ThreadStartWorkerEvent",
# "3": "ApiStat::DrawInfoEvent",
# ...
# }
# },
# "enums": { ... } // enums follow similar defs, map (groups?) structure
# }
2019-07-31 14:43:47 +01:00
protos = {
' events ' : {
' defs ' : { } , # event dictionary containing events with their fields
' map ' : { } , # dictionary to map event ids to event names
' groups ' : { } # event keys stored by groups
} ,
' enums ' : {
' defs ' : { } ,
' map ' : { }
}
}
event_id = 0
enum_id = 0
2018-09-04 19:41:39 +01:00
2018-09-17 20:50:47 +01:00
if type ( files ) is not list :
files = [ files ]
2018-09-04 19:41:39 +01:00
for filename in files :
if verbose :
print ( " Parsing proto file: %s " % os . path . normpath ( filename ) )
with open ( filename , ' r ' ) as f :
2019-07-31 14:43:47 +01:00
lines = f . readlines ( )
2019-08-01 13:30:58 +01:00
in_brief = False
brief = [ ]
2018-09-04 19:41:39 +01:00
idx = 0
while idx < len ( lines ) :
2019-07-31 14:43:47 +01:00
line = lines [ idx ] . strip ( )
2018-09-04 19:41:39 +01:00
idx + = 1
2016-08-29 20:56:03 +01:00
2019-08-01 13:30:58 +01:00
# If currently processing a brief, keep processing or change state
if in_brief :
match = re . match ( r ' ^ \ s* \ / \ / \ / \ s*(.*)$ ' , line ) # i.e. "/// more event desc..."
if match :
brief . append ( match . group ( 1 ) . strip ( ) )
continue
else :
in_brief = False
# Match event/enum brief
match = re . match ( r ' ^ \ s* \ / \ / \ / \ s*@(brief|breif) \ s*(.*)$ ' , line ) # i.e. "///@brief My event desc..."
if match :
in_brief = True
brief . append ( match . group ( 2 ) . strip ( ) )
continue
2019-07-31 14:43:47 +01:00
# Match event definition
match = re . match ( r ' event( \ s*)((( \ w*)::) { 0,1}( \ w+)) ' , line ) # i.e. "event SWTag::CounterEvent"
2018-09-04 19:41:39 +01:00
if match :
2019-07-31 14:43:47 +01:00
event_id + = 1
# Parse event attributes
event_key = match . group ( 2 ) # i.e. SWTag::CounterEvent
2019-08-01 13:30:58 +01:00
event_group = match . group ( 4 ) if match . group ( 4 ) else " " # i.e. SWTag
2019-07-31 14:43:47 +01:00
event_name = match . group ( 5 ) # i.e. CounterEvent
2016-08-29 20:56:03 +01:00
2019-07-31 14:43:47 +01:00
# Define event attributes
event = {
' id ' : event_id ,
' group ' : event_group ,
2019-08-01 13:30:58 +01:00
' name ' : event_name ,
' desc ' : ' ' . join ( brief )
2019-07-31 14:43:47 +01:00
}
2019-08-01 13:30:58 +01:00
# Add period at end of event desc if necessary
if event [ " desc " ] and event [ " desc " ] [ - 1 ] != ' . ' :
event [ " desc " ] + = ' . '
# Reset brief
brief = [ ]
2016-08-29 20:56:03 +01:00
2019-07-31 14:43:47 +01:00
# Now add event fields
idx = parse_event_fields ( lines , idx , event )
2016-08-29 20:56:03 +01:00
2019-08-01 13:30:58 +01:00
# Register event and mapping
2019-07-31 14:43:47 +01:00
protos [ ' events ' ] [ ' defs ' ] [ event_key ] = event
protos [ ' events ' ] [ ' map ' ] [ event_id ] = event_key
continue
# Match enum definition
match = re . match ( r ' enum( \ s*)( \ w+) ' , line )
2018-09-04 19:41:39 +01:00
if match :
2019-07-31 14:43:47 +01:00
enum_id + = 1
# Parse enum attributes
enum_name = match . group ( 2 )
# Define enum attr
enum = {
2019-08-01 13:30:58 +01:00
' name ' : enum_name ,
' desc ' : ' ' . join ( brief )
2019-07-31 14:43:47 +01:00
}
2019-08-01 13:30:58 +01:00
# Add period at end of event desc if necessary
if enum [ " desc " ] and enum [ " desc " ] [ - 1 ] != ' . ' :
enum [ " desc " ] + = ' . '
# Reset brief
brief = [ ]
2019-07-31 14:43:47 +01:00
# Now add enum fields
idx = parse_enums ( lines , idx , enum )
2019-08-01 13:30:58 +01:00
# Register enum and mapping
2019-07-31 14:43:47 +01:00
protos [ ' enums ' ] [ ' defs ' ] [ enum_name ] = enum
protos [ ' enums ' ] [ ' map ' ] [ enum_id ] = enum_name
continue
# Sort and group events
event_groups = protos [ ' events ' ] [ ' groups ' ]
for key in sorted ( protos [ ' events ' ] [ ' defs ' ] ) :
group = protos [ ' events ' ] [ ' defs ' ] [ key ] [ ' group ' ]
if group not in event_groups :
event_groups [ group ] = [ ]
event_groups [ group ] . append ( key )
2016-08-29 20:56:03 +01:00
2018-09-04 19:41:39 +01:00
return protos
2016-08-29 20:56:03 +01:00
def main ( ) :
# Parse args...
2017-03-17 17:39:15 +00:00
parser = ArgumentParser ( )
2018-09-04 19:41:39 +01:00
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 )
parser . add_argument ( " --output-dir " , help = " Output dir (defaults to ./codegen). Will create folder if it does not exist. " , required = False , default = " codegen " )
parser . add_argument ( " --verbose " , " -v " , help = " Verbose " , action = " store_true " )
2016-08-29 20:56:03 +01:00
args = parser . parse_args ( )
2018-08-31 18:13:56 +01:00
if not os . path . exists ( args . output_dir ) :
MakeDir ( args . output_dir )
2016-08-29 20:56:03 +01:00
2018-08-31 18:13:56 +01:00
for f in args . protos :
if not os . path . exists ( f ) :
print ( ' Error: Could not find proto file %s ' % f , file = sys . stderr )
return 1
2019-03-01 16:37:31 +00:00
2018-08-31 18:13:56 +01:00
# Parse each proto file and add to protos container
2018-09-04 19:41:39 +01:00
protos = parse_protos ( args . protos , args . verbose )
2018-08-31 18:13:56 +01:00
files = [
[ " gen_ar_event.hpp " , " " ] ,
[ " gen_ar_event.cpp " , " " ] ,
[ " gen_ar_eventhandler.hpp " , " gen_ar_event.hpp " ] ,
[ " gen_ar_eventhandlerfile.hpp " , " gen_ar_eventhandler.hpp " ]
]
2016-08-29 20:56:03 +01:00
2018-04-09 18:51:14 +01:00
rval = 0
try :
2018-08-31 18:13:56 +01:00
# Delete existing files
for f in files :
filename = f [ 0 ]
output_fullpath = os . path . join ( args . output_dir , filename )
if os . path . exists ( output_fullpath ) :
2018-09-04 19:41:39 +01:00
if args . verbose :
print ( " Deleting existing file: %s " % output_fullpath )
2018-08-31 18:13:56 +01:00
os . remove ( output_fullpath )
# Generate files from templates
2018-09-04 19:41:39 +01:00
print ( " Generating c++ from proto files... " )
2018-08-31 18:13:56 +01:00
for f in files :
filename = f [ 0 ]
event_header = f [ 1 ]
2019-03-01 16:37:31 +00:00
curdir = os . path . dirname ( os . path . abspath ( __file__ ) )
2018-08-31 18:13:56 +01:00
template_file = os . path . join ( curdir , ' templates ' , filename )
output_fullpath = os . path . join ( args . output_dir , filename )
2019-03-01 16:37:31 +00:00
2018-09-04 19:41:39 +01:00
if args . verbose :
print ( " Generating: %s " % output_fullpath )
2019-03-01 16:37:31 +00:00
MakoTemplateWriter . to_file ( template_file , output_fullpath ,
cmdline = sys . argv ,
2018-08-31 18:13:56 +01:00
filename = filename ,
protos = protos ,
event_header = event_header )
2019-03-01 16:37:31 +00:00
2018-08-31 18:13:56 +01:00
except Exception as e :
print ( e )
2018-04-09 18:51:14 +01:00
rval = 1
return rval
2016-08-29 20:56:03 +01:00
if __name__ == ' __main__ ' :
sys . exit ( main ( ) )