1# Copyright (C) 2014-2016 Intel Corporation. All Rights Reserved. 2# 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: 9# 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 12# Software. 13# 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 20# IN THE SOFTWARE. 21 22# Python source 23from __future__ import print_function 24import os 25import sys 26import re 27from gen_common import * 28 29def parse_event_fields(lines, idx, event_dict): 30 """ 31 Parses lines from a proto file that contain an event definition and stores it in event_dict 32 """ 33 fields = [] 34 end_of_event = False 35 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() 40 idx += 1 41 42 match = re.match(r'(\s*)([\w\*]+)(\s+)(counter\s+)*([\w]+)(\[\d+\])*', line) 43 44 if match: 45 field = { 46 "type": match.group(2), 47 "name": match.group(5), 48 "size": int(match.group(6)[1:-1]) if match.group(6) else 1, 49 "counter": True if match.group(4) else False 50 } 51 fields.append(field) 52 53 end_of_event = re.match(r'(\s*)};', line) 54 55 event_dict['fields'] = fields 56 event_dict['num_fields'] = len(fields) 57 58 return idx 59 60def parse_enums(lines, idx, event_dict): 61 """ 62 Parses lines from a proto file that contain an enum definition and stores it in event_dict 63 """ 64 enum_names = [] 65 end_of_enum = False 66 67 # record all enum values in enumeration 68 # note: we don't check if there's a leading brace. 69 while not end_of_enum and idx < len(lines): 70 line = lines[idx].rstrip() 71 idx += 1 72 73 preprocessor = re.search(r'#if|#endif', line) 74 75 if not preprocessor: 76 enum = re.match(r'(\s*)(\w+)(\s*)', line) 77 78 if enum: 79 enum_names.append(line) 80 81 end_of_enum = re.match(r'(\s*)};', line) 82 83 event_dict['names'] = enum_names 84 return idx 85 86def parse_protos(files, verbose=False): 87 """ 88 Parses a proto file and returns a dictionary of event definitions 89 """ 90 protos = {} 91 protos['events'] = {} # event dictionary containing events with their fields 92 protos['event_names'] = [] # needed to keep events in order parsed. dict is not ordered. 93 protos['event_map'] = {} # dictionary to map event ids to event names 94 protos['enums'] = {} 95 protos['enum_names'] = [] 96 97 eventId = 0 98 99 if type(files) is not list: 100 files = [files] 101 102 for filename in files: 103 if verbose: 104 print("Parsing proto file: %s" % os.path.normpath(filename)) 105 106 with open(filename, 'r') as f: 107 lines=f.readlines() 108 109 idx = 0 110 111 raw_text = [] 112 while idx < len(lines): 113 line = lines[idx].rstrip() 114 idx += 1 115 116 # search for event definitions. 117 match = re.match(r'(\s*)event(\s*)(\w+)', line) 118 119 if match: 120 eventId += 1 121 event_name = match.group(3) 122 protos["event_names"].append(event_name) 123 124 protos["events"][event_name] = {} 125 protos["events"][event_name]["event_id"] = eventId 126 protos["event_map"][eventId] = event_name 127 idx = parse_event_fields(lines, idx, protos["events"][event_name]) 128 129 # search for enums. 130 match = re.match(r'(\s*)enum(\s*)(\w+)', line) 131 132 if match: 133 enum_name = match.group(3) 134 protos["enum_names"].append(enum_name) 135 136 protos["enums"][enum_name] = {} 137 idx = parse_enums(lines, idx, protos["enums"][enum_name]) 138 return protos 139 140 141def main(): 142 143 # Parse args... 144 parser = ArgumentParser() 145 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) 146 parser.add_argument("--output-dir", help="Output dir (defaults to ./codegen). Will create folder if it does not exist.", required=False, default="codegen") 147 parser.add_argument("--verbose", "-v", help="Verbose", action="store_true") 148 args = parser.parse_args() 149 150 if not os.path.exists(args.output_dir): 151 MakeDir(args.output_dir) 152 153 for f in args.protos: 154 if not os.path.exists(f): 155 print('Error: Could not find proto file %s' % f, file=sys.stderr) 156 return 1 157 158 # Parse each proto file and add to protos container 159 protos = parse_protos(args.protos, args.verbose) 160 161 files = [ 162 ["gen_ar_event.hpp", ""], 163 ["gen_ar_event.cpp", ""], 164 ["gen_ar_eventhandler.hpp", "gen_ar_event.hpp"], 165 ["gen_ar_eventhandlerfile.hpp", "gen_ar_eventhandler.hpp"] 166 ] 167 168 rval = 0 169 170 try: 171 # Delete existing files 172 for f in files: 173 filename = f[0] 174 output_fullpath = os.path.join(args.output_dir, filename) 175 if os.path.exists(output_fullpath): 176 if args.verbose: 177 print("Deleting existing file: %s" % output_fullpath) 178 os.remove(output_fullpath) 179 180 # Generate files from templates 181 print("Generating c++ from proto files...") 182 for f in files: 183 filename = f[0] 184 event_header = f[1] 185 curdir = os.path.dirname(os.path.abspath(__file__)) 186 template_file = os.path.join(curdir, 'templates', filename) 187 output_fullpath = os.path.join(args.output_dir, filename) 188 189 if args.verbose: 190 print("Generating: %s" % output_fullpath) 191 MakoTemplateWriter.to_file(template_file, output_fullpath, 192 cmdline=sys.argv, 193 filename=filename, 194 protos=protos, 195 event_header=event_header) 196 197 except Exception as e: 198 print(e) 199 rval = 1 200 201 return rval 202 203if __name__ == '__main__': 204 sys.exit(main()) 205