Home | History | Annotate | Download | only in bindings
      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 
      7 Each typemap should be specified in an command-line argument of the form
      8 key=value, with an argument of "--start-typemap" preceding each typemap.
      9 
     10 For example,
     11 generate_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 
     15 generates 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 
     30 Then,
     31 generate_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 
     35 generates 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 
     60 import argparse
     61 import json
     62 import os
     63 import re
     64 
     65 
     66 def ReadTypemap(path):
     67   with open(path) as f:
     68     return json.load(f)['c++']
     69 
     70 
     71 def 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 
     79 def 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     # The only attribute supported currently is "move_only".
    101     move_only = match_result.group(3) and match_result.group(3) == "move_only"
    102 
    103     assert mojom_type not in result, (
    104         "Cannot map multiple native types (%s, %s) to the same mojom type: %s" %
    105         (result[mojom_type]['typename'], native_type, mojom_type))
    106 
    107     result[mojom_type] = {
    108         'typename': native_type,
    109         'move_only': move_only,
    110         'public_headers': values['public_headers'],
    111         'traits_headers': values['traits_headers'],
    112     }
    113   return result
    114 
    115 
    116 def main():
    117   parser = argparse.ArgumentParser(
    118       description=__doc__,
    119       formatter_class=argparse.RawDescriptionHelpFormatter)
    120   parser.add_argument(
    121       '--dependency',
    122       type=str,
    123       action='append',
    124       default=[],
    125       help=('A path to another JSON typemap to merge into the output. '
    126             'This may be repeated to merge multiple typemaps.'))
    127   parser.add_argument('--output',
    128                       type=str,
    129                       required=True,
    130                       help='The path to which to write the generated JSON.')
    131   params, typemap_params = parser.parse_known_args()
    132   typemaps = ParseTypemapArgs(typemap_params)
    133   missing = [path for path in params.dependency if not os.path.exists(path)]
    134   if missing:
    135     raise IOError('Missing dependencies: %s' % ', '.join(missing))
    136   for path in params.dependency:
    137     typemaps.update(ReadTypemap(path))
    138   with open(params.output, 'w') as f:
    139     json.dump({'c++': typemaps}, f, indent=2)
    140 
    141 
    142 if __name__ == '__main__':
    143   main()
    144