| #!/usr/bin/env python |
| # Copyright 2015 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. |
| |
| """Usage: collect_idls_into_json.py path_file.txt json_file.json |
| This script collects and organizes interface information and that information dumps into json file. |
| """ |
| |
| import json |
| import os |
| import sys |
| |
| _bindings_path = os.path.normpath( |
| os.path.join(os.path.dirname(__file__), |
| os.pardir, os.pardir, os.pardir, os.pardir, |
| 'Source', 'bindings', 'scripts')) |
| |
| if _bindings_path not in sys.path: |
| sys.path.append(_bindings_path) |
| |
| import utilities |
| from blink_idl_parser import parse_file, BlinkIDLParser |
| |
| |
| _INTERFACE = 'Interface' |
| _IMPLEMENT = 'Implements' |
| _PARTIAL = 'Partial' |
| _NAME = 'Name' |
| _TYPE = 'Type' |
| _UNIONTYPE = 'UnionType' |
| _ARRAY = 'Array' |
| _ANY = 'Any' |
| _SEQUENCE = 'Sequence' |
| _PROP_VALUE = 'VALUE' |
| _VALUE = 'Value' |
| _PARENT = 'Parent' |
| _FILEPATH = 'FilePath' |
| _PROP_FILENAME = 'FILENAME' |
| _PROP_READONLY = 'READONLY' |
| _READONLY = 'Readonly' |
| _PROP_STATIC = 'STATIC' |
| _STATIC = 'Static' |
| _CONSTS = 'Consts' |
| _CONST = 'Const' |
| _ATTRIBUTES = 'Attributes' |
| _ATTRIBUTE = 'Attribute' |
| _OPERATIONS = 'Operations' |
| _OPERATION = 'Operation' |
| _PROP_GETTER = 'GETTER' |
| _NAMED_GETTER = '__getter__' |
| _PROP_SETTER = 'SETTER' |
| _NAMED_SETTER = '__setter__' |
| _PROP_DELETER = 'DELETER' |
| _NAMED_DELETER = '__deleter__' |
| _ARGUMENTS = 'Arguments' |
| _ARGUMENT = 'Argument' |
| _EXTATTRIBUTES = 'ExtAttributes' |
| _EXTATTRIBUTE = 'ExtAttribute' |
| _INHERIT = 'Inherit' |
| _PROP_REFERENCE = 'REFERENCE' |
| _PARTIAL_FILEPATH = 'Partial_FilePaths' |
| _MEMBERS = [_CONSTS, _ATTRIBUTES, _OPERATIONS] |
| |
| |
| def get_definitions(paths): |
| """Returns a generator of IDL node. |
| Args: |
| paths: list of IDL file path |
| Returns: |
| a generator which yields IDL node objects |
| """ |
| parser = BlinkIDLParser() |
| for path in paths: |
| definitions = parse_file(parser, path) |
| for definition in definitions.GetChildren(): |
| yield definition |
| |
| |
| def is_implements(definition): |
| """Returns True if class of |definition| is Implements, otherwise False. |
| Args: |
| definition: IDL node |
| Returns: |
| True if class of |definition| is Implements, otherwise False. |
| """ |
| return definition.GetClass() == _IMPLEMENT |
| |
| |
| def is_partial(definition): |
| """Returns True if |definition| is 'partial interface' class, otherwise False. |
| Args: |
| definition: IDL node |
| Return: |
| True if |definition| is 'partial interface' class, otherwise False. |
| """ |
| return definition.GetClass() == _INTERFACE and definition.GetProperty(_PARTIAL) |
| |
| |
| def get_filepath(interface_node): |
| """Returns relative path to the IDL in which |interface_node| is defined. |
| Args: |
| interface_node: IDL interface |
| Returns: |
| str which is |interface_node|'s file path |
| """ |
| filename = interface_node.GetProperty(_PROP_FILENAME) |
| return os.path.relpath(filename) |
| |
| |
| def get_const_node_list(interface_node): |
| """Returns a list of Const node. |
| Args: |
| interface_node: interface node |
| Returns: |
| A list of const node |
| """ |
| return interface_node.GetListOf(_CONST) |
| |
| |
| def get_const_type(const_node): |
| """Returns const's type. |
| Args: |
| const_node: const node |
| Returns: |
| str which is constant type. |
| """ |
| return const_node.GetChildren()[0].GetName() |
| |
| |
| def get_const_value(const_node): |
| """Returns const's value. |
| This function only supports primitive types. |
| |
| Args: |
| const_node: const node |
| Returns: |
| str which is name of constant's value. |
| """ |
| if const_node.GetChildren()[1].GetName(): |
| return const_node.GetChildren()[1].GetName() |
| else: |
| for const_child in const_node.GetChildren(): |
| if const_child.GetClass() == _VALUE and not const_child.GetName(): |
| return const_child.GetProperty(_PROP_VALUE) |
| raise Exception('Constant value is empty') |
| |
| |
| def const_node_to_dict(const_node): |
| """Returns dictionary of const's information. |
| Args: |
| const_node: const node |
| Returns: |
| dictionary of const's information |
| """ |
| return { |
| _NAME: const_node.GetName(), |
| _TYPE: get_const_type(const_node), |
| _VALUE: get_const_value(const_node), |
| _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(const_node)], |
| } |
| |
| |
| def get_attribute_node_list(interface_node): |
| """Returns list of Attribute if the interface have one. |
| Args: |
| interface_node: interface node |
| Returns: |
| list of attribute node |
| """ |
| return interface_node.GetListOf(_ATTRIBUTE) |
| |
| |
| def get_attribute_type(attribute_node): |
| """Returns type of attribute. |
| Args: |
| attribute_node: attribute node |
| Returns: |
| name of attribute's type |
| """ |
| attr_type = attribute_node.GetOneOf(_TYPE).GetChildren()[0] |
| type_list = [] |
| if attr_type.GetClass() == _UNIONTYPE: |
| union_member_list = attr_type.GetListOf(_TYPE) |
| for union_member in union_member_list: |
| for type_component in union_member.GetChildren(): |
| if type_component.GetClass() == _ARRAY: |
| type_list[-1] += '[]' |
| elif type_component.GetClass() == _SEQUENCE: |
| for seq_type in type_component.GetOneOf(_TYPE).GetChildren(): |
| type_list.append('<' + seq_type.GetName() + '>') |
| else: |
| type_list.append(type_component.GetName()) |
| return type_list |
| elif attr_type.GetClass() == _SEQUENCE: |
| union_member_types = [] |
| if attr_type.GetOneOf(_TYPE).GetChildren()[0].GetClass() == _UNIONTYPE: |
| for union_member in attr_type.GetOneOf(_TYPE).GetOneOf(_UNIONTYPE).GetListOf(_TYPE): |
| if len(union_member.GetChildren()) != 1: |
| raise Exception('Complex type in a union in a sequence is not yet supported') |
| type_component = union_member.GetChildren()[0] |
| union_member_types.append(type_component.GetName()) |
| return '<' + str(union_member_types) + '>' |
| else: |
| for type_component in attr_type.GetOneOf(_TYPE).GetChildren(): |
| if type_component.GetClass() == _SEQUENCE: |
| raise Exception('Sequence in another sequence is not yet supported') |
| else: |
| if type_component.GetClass() == _ARRAY: |
| type_list[-1] += [] |
| else: |
| type_list.append(type_component.GetName()) |
| return '<' + type_list[0] + '>' |
| elif attr_type.GetClass() == _ANY: |
| return _ANY |
| else: |
| for type_component in attribute_node.GetOneOf(_TYPE).GetChildren(): |
| if type_component.GetClass() == _ARRAY: |
| type_list[-1] += '[]' |
| else: |
| type_list.append(type_component.GetName()) |
| return type_list[0] |
| |
| |
| get_operation_type = get_attribute_type |
| get_argument_type = get_attribute_type |
| |
| |
| def attribute_node_to_dict(attribute_node): |
| """Returns dictioary of attribute's information. |
| Args: |
| attribute_node: attribute node |
| Returns: |
| dictionary of attribute's information |
| """ |
| return { |
| _NAME: attribute_node.GetName(), |
| _TYPE: get_attribute_type(attribute_node), |
| _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(attribute_node)], |
| _READONLY: attribute_node.GetProperty(_PROP_READONLY, default=False), |
| _STATIC: attribute_node.GetProperty(_PROP_STATIC, default=False), |
| } |
| |
| |
| def get_operation_node_list(interface_node): |
| """Returns operations node list. |
| Args: |
| interface_node: interface node |
| Returns: |
| list of oparation node |
| """ |
| return interface_node.GetListOf(_OPERATION) |
| |
| |
| def get_argument_node_list(operation_node): |
| """Returns list of argument. |
| Args: |
| operation_node: operation node |
| Returns: |
| list of argument node |
| """ |
| return operation_node.GetOneOf(_ARGUMENTS).GetListOf(_ARGUMENT) |
| |
| |
| def argument_node_to_dict(argument_node): |
| """Returns dictionary of argument's information. |
| Args: |
| argument_node: argument node |
| Returns: |
| dictionary of argument's information |
| """ |
| return { |
| _NAME: argument_node.GetName(), |
| _TYPE: get_argument_type(argument_node), |
| } |
| |
| |
| def get_operation_name(operation_node): |
| """Returns openration's name. |
| Args: |
| operation_node: operation node |
| Returns: |
| name of operation |
| """ |
| if operation_node.GetProperty(_PROP_GETTER): |
| return _NAMED_GETTER |
| elif operation_node.GetProperty(_PROP_SETTER): |
| return _NAMED_SETTER |
| elif operation_node.GetProperty(_PROP_DELETER): |
| return _NAMED_DELETER |
| else: |
| return operation_node.GetName() |
| |
| |
| def operation_node_to_dict(operation_node): |
| """Returns dictionary of operation's information. |
| Args: |
| operation_node: operation node |
| Returns: |
| dictionary of operation's informantion |
| """ |
| return { |
| _NAME: get_operation_name(operation_node), |
| _ARGUMENTS: [argument_node_to_dict(argument) for argument in get_argument_node_list(operation_node) |
| if argument_node_to_dict(argument)], |
| _TYPE: get_operation_type(operation_node), |
| _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(operation_node)], |
| _STATIC: operation_node.GetProperty(_PROP_STATIC, default=False), |
| } |
| |
| |
| def get_extattribute_node_list(node): |
| """Returns list of ExtAttribute. |
| Args: |
| node: IDL node |
| Returns: |
| list of ExtAttrbute |
| """ |
| if node.GetOneOf(_EXTATTRIBUTES): |
| return node.GetOneOf(_EXTATTRIBUTES).GetListOf(_EXTATTRIBUTE) |
| else: |
| return [] |
| |
| |
| def extattr_node_to_dict(extattr): |
| """Returns dictionary of ExtAttribute's information. |
| Args: |
| extattr: ExtAttribute node |
| Returns: |
| dictionary of ExtAttribute's information |
| """ |
| return { |
| _NAME: extattr.GetName(), |
| } |
| |
| |
| def inherit_node_to_dict(interface_node): |
| """Returns a dictionary of inheritance information. |
| Args: |
| interface_node: interface node |
| Returns: |
| A dictioanry of inheritance information. |
| """ |
| inherit = interface_node.GetOneOf(_INHERIT) |
| if inherit: |
| return {_PARENT: inherit.GetName()} |
| else: |
| return {_PARENT: None} |
| |
| |
| def interface_node_to_dict(interface_node): |
| """Returns a dictioary of interface information. |
| Args: |
| interface_node: interface node |
| Returns: |
| A dictionary of the interface information. |
| """ |
| return { |
| _NAME: interface_node.GetName(), |
| _FILEPATH: get_filepath(interface_node), |
| _CONSTS: [const_node_to_dict(const) for const in get_const_node_list(interface_node)], |
| _ATTRIBUTES: [attribute_node_to_dict(attr) for attr in get_attribute_node_list(interface_node) if attr], |
| _OPERATIONS: [operation_node_to_dict(operation) for operation in get_operation_node_list(interface_node) if operation], |
| _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(interface_node)], |
| _INHERIT: inherit_node_to_dict(interface_node) |
| } |
| |
| |
| def merge_partial_dicts(interfaces_dict, partials_dict): |
| """Merges partial interface into non-partial interface. |
| Args: |
| interfaces_dict: A dict of the non-partial interfaces. |
| partial_dict: A dict of partial interfaces. |
| Returns: |
| A merged dictionary of |interface_dict| with |partial_dict|. |
| """ |
| for interface_name, partial in partials_dict.iteritems(): |
| interface = interfaces_dict.get(interface_name) |
| if not interface: |
| raise Exception('There is a partial interface, but the corresponding non-partial interface was not found.') |
| for member in _MEMBERS: |
| interface[member].extend(partial.get(member)) |
| interface.setdefault(_PARTIAL_FILEPATH, []).append(partial[_FILEPATH]) |
| return interfaces_dict |
| |
| |
| def merge_implement_nodes(interfaces_dict, implement_node_list): |
| """Combines a dict of interface information with referenced interface information. |
| Args: |
| interfaces_dict: dict of interface information |
| implement_nodes: list of implemented interface node |
| Returns: |
| A dict of interface information combined with implements nodes. |
| """ |
| for implement in implement_node_list: |
| reference = implement.GetProperty(_PROP_REFERENCE) |
| implement = implement.GetName() |
| if reference not in interfaces_dict.keys() or implement not in interfaces_dict.keys(): |
| raise Exception('There is not corresponding implement or reference interface.') |
| for member in _MEMBERS: |
| interfaces_dict[implement][member].extend(interfaces_dict[reference].get(member)) |
| return interfaces_dict |
| |
| |
| def export_to_jsonfile(dictionary, json_file): |
| """Writes a Python dict into a JSON file. |
| Args: |
| dictioary: interface dictionary |
| json_file: json file for output |
| """ |
| with open(json_file, 'w') as f: |
| json.dump(dictionary, f, sort_keys=True) |
| |
| |
| def usage(): |
| sys.stdout.write('Usage: collect_idls_into_json.py <path_file.txt> <output_file.json>\n') |
| |
| |
| def main(args): |
| if len(args) != 2: |
| usage() |
| exit(1) |
| path_file = args[0] |
| json_file = args[1] |
| path_list = utilities.read_file_to_list(path_file) |
| implement_node_list = [definition |
| for definition in get_definitions(path_list) |
| if is_implements(definition)] |
| interfaces_dict = {definition.GetName(): interface_node_to_dict(definition) |
| for definition in get_definitions(path_list) |
| if not is_partial(definition)} |
| partials_dict = {definition.GetName(): interface_node_to_dict(definition) |
| for definition in get_definitions(path_list) |
| if is_partial(definition)} |
| dictionary = merge_partial_dicts(interfaces_dict, partials_dict) |
| interfaces_dict = merge_implement_nodes(interfaces_dict, implement_node_list) |
| export_to_jsonfile(dictionary, json_file) |
| |
| |
| if __name__ == '__main__': |
| main(sys.argv[1:]) |