1#!/usr/bin/env python 2# Copyright 2016 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""Generates a JSON typemap from its command-line arguments and dependencies. 6 7Each typemap should be specified in an command-line argument of the form 8key=value, with an argument of "--start-typemap" preceding each typemap. 9 10For example, 11generate_type_mappings.py --output=foo.typemap --start-typemap \\ 12 public_headers=foo.h traits_headers=foo_traits.h \\ 13 type_mappings=mojom.Foo=FooImpl 14 15generates a foo.typemap containing 16{ 17 "c++": { 18 "mojom.Foo": { 19 "typename": "FooImpl", 20 "traits_headers": [ 21 "foo_traits.h" 22 ], 23 "public_headers": [ 24 "foo.h" 25 ] 26 } 27 } 28} 29 30Then, 31generate_type_mappings.py --dependency foo.typemap --output=bar.typemap \\ 32 --start-typemap public_headers=bar.h traits_headers=bar_traits.h \\ 33 type_mappings=mojom.Bar=BarImpl 34 35generates a bar.typemap containing 36{ 37 "c++": { 38 "mojom.Bar": { 39 "typename": "BarImpl", 40 "traits_headers": [ 41 "bar_traits.h" 42 ], 43 "public_headers": [ 44 "bar.h" 45 ] 46 }, 47 "mojom.Foo": { 48 "typename": "FooImpl", 49 "traits_headers": [ 50 "foo_traits.h" 51 ], 52 "public_headers": [ 53 "foo.h" 54 ] 55 } 56 } 57} 58""" 59 60import argparse 61import json 62import os 63import re 64 65 66def ReadTypemap(path): 67 with open(path) as f: 68 return json.load(f)['c++'] 69 70 71def ParseTypemapArgs(args): 72 typemaps = [s for s in '\n'.join(args).split('--start-typemap\n') if s] 73 result = {} 74 for typemap in typemaps: 75 result.update(ParseTypemap(typemap)) 76 return result 77 78 79def ParseTypemap(typemap): 80 values = {'type_mappings': [], 'public_headers': [], 'traits_headers': []} 81 for line in typemap.split('\n'): 82 if not line: 83 continue 84 key, _, value = line.partition('=') 85 values[key].append(value.lstrip('/')) 86 result = {} 87 mapping_pattern = \ 88 re.compile(r"""^([^=]+) # mojom type 89 = 90 ([^[]+) # native type 91 (?:\[([^]]+)\])?$ # optional attribute in square brackets 92 """, re.X) 93 for typename in values['type_mappings']: 94 match_result = mapping_pattern.match(typename) 95 assert match_result, ( 96 "Cannot parse entry in the \"type_mappings\" section: %s" % typename) 97 98 mojom_type = match_result.group(1) 99 native_type = match_result.group(2) 100 attributes = [] 101 if match_result.group(3): 102 attributes = match_result.group(3).split(',') 103 104 assert mojom_type not in result, ( 105 "Cannot map multiple native types (%s, %s) to the same mojom type: %s" % 106 (result[mojom_type]['typename'], native_type, mojom_type)) 107 108 result[mojom_type] = { 109 'typename': native_type, 110 'non_copyable_non_movable': 'non_copyable_non_movable' in attributes, 111 'move_only': 'move_only' in attributes, 112 'copyable_pass_by_value': 'copyable_pass_by_value' in attributes, 113 'nullable_is_same_type': 'nullable_is_same_type' in attributes, 114 'hashable': 'hashable' in attributes, 115 'public_headers': values['public_headers'], 116 'traits_headers': values['traits_headers'], 117 } 118 return result 119 120 121def main(): 122 parser = argparse.ArgumentParser( 123 description=__doc__, 124 formatter_class=argparse.RawDescriptionHelpFormatter) 125 parser.add_argument( 126 '--dependency', 127 type=str, 128 action='append', 129 default=[], 130 help=('A path to another JSON typemap to merge into the output. ' 131 'This may be repeated to merge multiple typemaps.')) 132 parser.add_argument('--output', 133 type=str, 134 required=True, 135 help='The path to which to write the generated JSON.') 136 params, typemap_params = parser.parse_known_args() 137 typemaps = ParseTypemapArgs(typemap_params) 138 missing = [path for path in params.dependency if not os.path.exists(path)] 139 if missing: 140 raise IOError('Missing dependencies: %s' % ', '.join(missing)) 141 for path in params.dependency: 142 typemaps.update(ReadTypemap(path)) 143 with open(params.output, 'w') as f: 144 json.dump({'c++': typemaps}, f, indent=2) 145 146 147if __name__ == '__main__': 148 main() 149