blob: ee55e99404e528e3f28d472e5f1a543646873cff [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates a JSON typemap from its command-line arguments and dependencies.
Each typemap should be specified in an command-line argument of the form
key=value, with an argument of "--start-typemap" preceding each typemap.
For example,
generate_type_mappings.py --output=foo.typemap --start-typemap \\
public_headers=foo.h traits_headers=foo_traits.h \\
type_mappings=mojom.Foo=FooImpl
generates a foo.typemap containing
{
"c++": {
"mojom.Foo": {
"typename": "FooImpl",
"traits_headers": [
"foo_traits.h"
],
"public_headers": [
"foo.h"
]
}
}
}
Then,
generate_type_mappings.py --dependency foo.typemap --output=bar.typemap \\
--start-typemap public_headers=bar.h traits_headers=bar_traits.h \\
type_mappings=mojom.Bar=BarImpl
generates a bar.typemap containing
{
"c++": {
"mojom.Bar": {
"typename": "BarImpl",
"traits_headers": [
"bar_traits.h"
],
"public_headers": [
"bar.h"
]
},
"mojom.Foo": {
"typename": "FooImpl",
"traits_headers": [
"foo_traits.h"
],
"public_headers": [
"foo.h"
]
}
}
}
"""
import argparse
import json
import os
import re
import sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"pylib"))
from mojom.generate.generator import WriteFile
def ReadTypemap(path):
with open(path) as f:
return json.load(f)['c++']
def ParseTypemapArgs(args):
typemaps = [s for s in '\n'.join(args).split('--start-typemap\n') if s]
result = {}
for typemap in typemaps:
result.update(ParseTypemap(typemap))
return result
def ParseTypemap(typemap):
values = {'type_mappings': [], 'public_headers': [], 'traits_headers': []}
for line in typemap.split('\n'):
if not line:
continue
key, _, value = line.partition('=')
values[key].append(value.lstrip('/'))
result = {}
mapping_pattern = \
re.compile(r"""^([^=]+) # mojom type
=
([^[]+) # native type
(?:\[([^]]+)\])?$ # optional attribute in square brackets
""", re.X)
for typename in values['type_mappings']:
match_result = mapping_pattern.match(typename)
assert match_result, (
"Cannot parse entry in the \"type_mappings\" section: %s" % typename)
mojom_type = match_result.group(1)
native_type = match_result.group(2)
attributes = []
if match_result.group(3):
attributes = match_result.group(3).split(',')
assert mojom_type not in result, (
"Cannot map multiple native types (%s, %s) to the same mojom type: %s" %
(result[mojom_type]['typename'], native_type, mojom_type))
result[mojom_type] = {
'public_headers': values['public_headers'],
'traits_headers': values['traits_headers'],
'typename': native_type,
# Attributes supported for individual mappings.
'copyable_pass_by_value': 'copyable_pass_by_value' in attributes,
'force_serialize': 'force_serialize' in attributes,
'hashable': 'hashable' in attributes,
'move_only': 'move_only' in attributes,
'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
'nullable_is_same_type': 'nullable_is_same_type' in attributes,
}
return result
def main():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
'--dependency',
type=str,
action='append',
default=[],
help=('A path to another JSON typemap to merge into the output. '
'This may be repeated to merge multiple typemaps.'))
parser.add_argument('--output',
type=str,
required=True,
help='The path to which to write the generated JSON.')
params, typemap_params = parser.parse_known_args()
typemaps = ParseTypemapArgs(typemap_params)
missing = [path for path in params.dependency if not os.path.exists(path)]
if missing:
raise IOError('Missing dependencies: %s' % ', '.join(missing))
for path in params.dependency:
typemaps.update(ReadTypemap(path))
WriteFile(json.dumps({'c++': typemaps}, indent=2), params.output)
if __name__ == '__main__':
main()