12248c17cd3483c030571cc6163a0e0870da998c2Chirayu Desai#!/usr/bin/env python 20e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes# 3d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# Copyright (C) 2012 The Android Open Source Project 40e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes# 5d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# Licensed under the Apache License, Version 2.0 (the "License"); 6d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# you may not use this file except in compliance with the License. 7d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# You may obtain a copy of the License at 80e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes# 9d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# http://www.apache.org/licenses/LICENSE-2.0 100e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes# 11d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# Unless required by applicable law or agreed to in writing, software 12d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# distributed under the License is distributed on an "AS IS" BASIS, 13d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# See the License for the specific language governing permissions and 15d320a9a7850fabd62329d5b287787c8e31d047ccElliott Hughes# limitations under the License. 160e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 170e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes"""Generates default implementations of operator<< for enum types.""" 180e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 190e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesimport codecs 200e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesimport os 210e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesimport re 220e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesimport string 230e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesimport sys 240e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 250e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 26833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe_ENUM_START_RE = re.compile(r'\benum\b\s+(class\s+)?(\S+)\s+:?.*\{(\s+// private)?') 270e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes_ENUM_VALUE_RE = re.compile(r'([A-Za-z0-9_]+)(.*)') 280e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes_ENUM_END_RE = re.compile(r'^\s*\};$') 290e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes_ENUMS = {} 30460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes_NAMESPACES = {} 31833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe_ENUM_CLASSES = {} 320e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 330e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesdef Confused(filename, line_number, line): 340e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line)) 354825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes raise Exception("giving up!") 360e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes sys.exit(1) 370e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 380e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 390e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesdef ProcessFile(filename): 400e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') 410e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes in_enum = False 426a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers is_enum_private = False 43833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe is_enum_class = False 440e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes line_number = 0 45833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe 46460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 47460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes namespaces = [] 48460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes enclosing_classes = [] 49460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 500e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes for raw_line in lines: 510e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes line_number += 1 520e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 530e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if not in_enum: 54460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes # Is this the start of a new enum? 550e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes m = _ENUM_START_RE.search(raw_line) 560e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if m: 570e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # Yes, so add an empty entry to _ENUMS for this enum. 58833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe 59833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe # Except when it's private 60833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe if m.group(3) is not None: 616a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers is_enum_private = True 626a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers else: 636a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers is_enum_private = False 646a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers is_enum_class = m.group(1) is not None 656a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers enum_name = m.group(2) 666a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers if len(enclosing_classes) > 0: 676a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers enum_name = '::'.join(enclosing_classes) + '::' + enum_name 686a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers _ENUMS[enum_name] = [] 696a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers _NAMESPACES[enum_name] = '::'.join(namespaces) 706a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers _ENUM_CLASSES[enum_name] = is_enum_class 710e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes in_enum = True 72460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 73460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 74460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes # Is this the start or end of a namespace? 75460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes m = re.compile(r'^namespace (\S+) \{').search(raw_line) 76460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes if m: 77460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes namespaces.append(m.group(1)) 78460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 79460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes m = re.compile(r'^\}\s+// namespace').search(raw_line) 80460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes if m: 81460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes namespaces = namespaces[0:len(namespaces) - 1] 82460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 83460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 84460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes # Is this the start or end of an enclosing class or struct? 856a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers m = re.compile(r'^\s*(?:class|struct)(?: MANAGED)?(?: PACKED\([0-9]\))? (\S+).* \{').search(raw_line) 86460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes if m: 87460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes enclosing_classes.append(m.group(1)) 88460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 8997da02a5d432c8494518908c367c3979053baccaBruce Hoult 9097da02a5d432c8494518908c367c3979053baccaBruce Hoult # End of class/struct -- be careful not to match "do { ... } while" constructs by accident 9197da02a5d432c8494518908c367c3979053baccaBruce Hoult m = re.compile(r'^\s*\}(\s+)?(while)?(.+)?;').search(raw_line) 9297da02a5d432c8494518908c367c3979053baccaBruce Hoult if m and not m.group(2): 93460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes enclosing_classes = enclosing_classes[0:len(enclosing_classes) - 1] 94460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 95460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 960e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes continue 970e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 980e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # Is this the end of the current enum? 990e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes m = _ENUM_END_RE.search(raw_line) 1000e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if m: 1010e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if not in_enum: 1020e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes Confused(filename, line_number, raw_line) 1030e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes in_enum = False 1040e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes continue 1050e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1066a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers if is_enum_private: 1076a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers continue 1086a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers 109a9719eb4167b544438268d46692389761652fc5dElliott Hughes # The only useful thing in comments is the <<alternate text>> syntax for 110a9719eb4167b544438268d46692389761652fc5dElliott Hughes # overriding the default enum value names. Pull that out... 111a9719eb4167b544438268d46692389761652fc5dElliott Hughes enum_text = None 112a9719eb4167b544438268d46692389761652fc5dElliott Hughes m_comment = re.compile(r'// <<(.*?)>>').search(raw_line) 113a9719eb4167b544438268d46692389761652fc5dElliott Hughes if m_comment: 114a9719eb4167b544438268d46692389761652fc5dElliott Hughes enum_text = m_comment.group(1) 115a9719eb4167b544438268d46692389761652fc5dElliott Hughes # ...and then strip // comments. 116a9719eb4167b544438268d46692389761652fc5dElliott Hughes line = re.sub(r'//.*', '', raw_line) 1174825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes 1184825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes # Strip whitespace. 1194825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes line = line.strip() 1204825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes 1214825756c621ff709079ef3cd3f981e7036c0ebdbElliott Hughes # Skip blank lines. 122460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes if len(line) == 0: 123460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes continue 124460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 125a9719eb4167b544438268d46692389761652fc5dElliott Hughes # Since we know we're in an enum type, and we're not looking at a comment 126a9719eb4167b544438268d46692389761652fc5dElliott Hughes # or a blank line, this line should be the next enum value... 127460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes m = _ENUM_VALUE_RE.search(line) 1280e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if not m: 1290e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes Confused(filename, line_number, raw_line) 1300e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes enum_value = m.group(1) 1310e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1320e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # By default, we turn "kSomeValue" into "SomeValue". 133a9719eb4167b544438268d46692389761652fc5dElliott Hughes if enum_text == None: 134a9719eb4167b544438268d46692389761652fc5dElliott Hughes enum_text = enum_value 135a9719eb4167b544438268d46692389761652fc5dElliott Hughes if enum_text.startswith('k'): 136a9719eb4167b544438268d46692389761652fc5dElliott Hughes enum_text = enum_text[1:] 1370e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1380e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # Lose literal values because we don't care; turn "= 123, // blah" into ", // blah". 1390e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes rest = m.group(2).strip() 140460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes m_literal = re.compile(r'= (0x[0-9a-f]+|-?[0-9]+|\'.\')').search(rest) 1410e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if m_literal: 1420e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes rest = rest[(len(m_literal.group(0))):] 1430e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1440e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # With "kSomeValue = kOtherValue," we take the original and skip later synonyms. 1450e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # TODO: check that the rhs is actually an existing value. 1460e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if rest.startswith('= k'): 1470e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes continue 1480e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1490e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes # Remove any trailing comma and whitespace 1500e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes if rest.startswith(','): 1510e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes rest = rest[1:] 1520e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes rest = rest.strip() 1530e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 154a9719eb4167b544438268d46692389761652fc5dElliott Hughes # There shouldn't be anything left. 155a9719eb4167b544438268d46692389761652fc5dElliott Hughes if len(rest): 1566a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers sys.stderr.write('%s\n' % (rest)) 1570e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes Confused(filename, line_number, raw_line) 1580e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 159f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz # If the enum is scoped, we must prefix enum value with enum name (which is already prefixed 160f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz # by enclosing classes). 161f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz if is_enum_class: 162f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz enum_value = enum_name + '::' + enum_value 163f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz else: 164f795869da0a1fa006fdcdacd8afb6149a63fc1a7Sebastien Hertz if len(enclosing_classes) > 0: 165833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe enum_value = '::'.join(enclosing_classes) + '::' + enum_value 166460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 1670e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes _ENUMS[enum_name].append((enum_value, enum_text)) 1680e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1690e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesdef main(): 1707940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom local_path = sys.argv[1] 1710e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes header_files = [] 1727940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom for header_file in sys.argv[2:]: 1730e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes header_files.append(header_file) 1740e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes ProcessFile(header_file) 1750e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 176c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('#include <iostream>') 177c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('') 1780e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1790e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes for header_file in header_files: 1807940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom header_file = header_file.replace(local_path + '/', '') 181c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('#include "%s"' % header_file) 1820e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 183c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('') 1840e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 1850e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes for enum_name in _ENUMS: 186c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('// This was automatically generated by %s --- do not edit!' % sys.argv[0]) 187460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 188460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes namespaces = _NAMESPACES[enum_name].split('::') 189460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes for namespace in namespaces: 190c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('namespace %s {' % namespace) 191460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes 192c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('std::ostream& operator<<(std::ostream& os, const %s& rhs) {' % enum_name) 193c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print(' switch (rhs) {') 1940e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes for (enum_value, enum_text) in _ENUMS[enum_name]: 195c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print(' case %s: os << "%s"; break;' % (enum_value, enum_text)) 196833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe if not _ENUM_CLASSES[enum_name]: 197c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print(' default: os << "%s[" << static_cast<int>(rhs) << "]"; break;' % enum_name) 198c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print(' }') 199c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print(' return os;') 200c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('}') 2010e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 202460384f04f933f94546db7bfbfa02896b9e77962Elliott Hughes for namespace in reversed(namespaces): 203c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('} // namespace %s' % namespace) 204c2e02609a03da6abe7e97c7ef85c50368058a4dfBernhard Rosenkränzer print('') 2050e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 2060e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes sys.exit(0) 2070e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 2080e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes 2090e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughesif __name__ == '__main__': 2100e57ccbbc2de9eeaeecd699575aab22a3f555619Elliott Hughes main() 211