1#!/usr/bin/env python 2# Copyright 2015 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 6"""Usage: collect_idls_into_json.py path_file.txt json_file.json 7This script collects and organizes interface information and that information dumps into json file. 8""" 9 10import json 11import os 12import sys 13 14from blinkpy.common import path_finder 15path_finder.add_bindings_scripts_dir_to_sys_path() 16 17import utilities 18from blink_idl_parser import parse_file, BlinkIDLParser 19 20 21_INTERFACE = 'Interface' 22_IMPLEMENT = 'Implements' 23_PARTIAL = 'Partial' 24_NAME = 'Name' 25_TYPE = 'Type' 26_UNIONTYPE = 'UnionType' 27_ARRAY = 'Array' 28_ANY = 'Any' 29_SEQUENCE = 'Sequence' 30_PROP_VALUE = 'VALUE' 31_VALUE = 'Value' 32_PARENT = 'Parent' 33_FILEPATH = 'FilePath' 34_PROP_FILENAME = 'FILENAME' 35_PROP_READONLY = 'READONLY' 36_READONLY = 'Readonly' 37_PROP_STATIC = 'STATIC' 38_STATIC = 'Static' 39_CONSTS = 'Consts' 40_CONST = 'Const' 41_ATTRIBUTES = 'Attributes' 42_ATTRIBUTE = 'Attribute' 43_OPERATIONS = 'Operations' 44_OPERATION = 'Operation' 45_PROP_GETTER = 'GETTER' 46_NAMED_GETTER = '__getter__' 47_PROP_SETTER = 'SETTER' 48_NAMED_SETTER = '__setter__' 49_PROP_DELETER = 'DELETER' 50_NAMED_DELETER = '__deleter__' 51_ARGUMENTS = 'Arguments' 52_ARGUMENT = 'Argument' 53_EXTATTRIBUTES = 'ExtAttributes' 54_EXTATTRIBUTE = 'ExtAttribute' 55_INHERIT = 'Inherit' 56_PROP_REFERENCE = 'REFERENCE' 57_PARTIAL_FILEPATH = 'Partial_FilePaths' 58_MEMBERS = [_CONSTS, _ATTRIBUTES, _OPERATIONS] 59 60 61def get_definitions(paths): 62 """Returns a generator of IDL node. 63 Args: 64 paths: list of IDL file path 65 Returns: 66 a generator which yields IDL node objects 67 """ 68 parser = BlinkIDLParser() 69 for path in paths: 70 definitions = parse_file(parser, path) 71 for definition in definitions.GetChildren(): 72 yield definition 73 74 75def is_implements(definition): 76 """Returns True if class of |definition| is Implements, otherwise False. 77 Args: 78 definition: IDL node 79 Returns: 80 True if class of |definition| is Implements, otherwise False. 81 """ 82 return definition.GetClass() == _IMPLEMENT 83 84 85def is_partial(definition): 86 """Returns True if |definition| is 'partial interface' class, otherwise False. 87 Args: 88 definition: IDL node 89 Return: 90 True if |definition| is 'partial interface' class, otherwise False. 91 """ 92 return definition.GetClass() == _INTERFACE and definition.GetProperty(_PARTIAL) 93 94 95def get_filepath(interface_node): 96 """Returns relative path to the IDL in which |interface_node| is defined. 97 Args: 98 interface_node: IDL interface 99 Returns: 100 str which is |interface_node|'s file path 101 """ 102 filename = interface_node.GetProperty(_PROP_FILENAME) 103 return os.path.relpath(filename) 104 105 106def get_const_node_list(interface_node): 107 """Returns a list of Const node. 108 Args: 109 interface_node: interface node 110 Returns: 111 A list of const node 112 """ 113 return interface_node.GetListOf(_CONST) 114 115 116def get_const_type(const_node): 117 """Returns const's type. 118 Args: 119 const_node: const node 120 Returns: 121 str which is constant type. 122 """ 123 return const_node.GetChildren()[0].GetName() 124 125 126def get_const_value(const_node): 127 """Returns const's value. 128 This function only supports primitive types. 129 130 Args: 131 const_node: const node 132 Returns: 133 str which is name of constant's value. 134 """ 135 if const_node.GetChildren()[1].GetName(): 136 return const_node.GetChildren()[1].GetName() 137 else: 138 for const_child in const_node.GetChildren(): 139 if const_child.GetClass() == _VALUE and not const_child.GetName(): 140 return const_child.GetProperty(_PROP_VALUE) 141 raise Exception('Constant value is empty') 142 143 144def const_node_to_dict(const_node): 145 """Returns dictionary of const's information. 146 Args: 147 const_node: const node 148 Returns: 149 dictionary of const's information 150 """ 151 return { 152 _NAME: const_node.GetName(), 153 _TYPE: get_const_type(const_node), 154 _VALUE: get_const_value(const_node), 155 _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(const_node)], 156 } 157 158 159def get_attribute_node_list(interface_node): 160 """Returns list of Attribute if the interface have one. 161 Args: 162 interface_node: interface node 163 Returns: 164 list of attribute node 165 """ 166 return interface_node.GetListOf(_ATTRIBUTE) 167 168 169def get_attribute_type(attribute_node): 170 """Returns type of attribute. 171 Args: 172 attribute_node: attribute node 173 Returns: 174 name of attribute's type 175 """ 176 attr_type = attribute_node.GetOneOf(_TYPE).GetChildren()[0] 177 type_list = [] 178 if attr_type.GetClass() == _UNIONTYPE: 179 union_member_list = attr_type.GetListOf(_TYPE) 180 for union_member in union_member_list: 181 for type_component in union_member.GetChildren(): 182 if type_component.GetClass() == _ARRAY: 183 type_list[-1] += '[]' 184 elif type_component.GetClass() == _SEQUENCE: 185 for seq_type in type_component.GetOneOf(_TYPE).GetChildren(): 186 type_list.append('<' + seq_type.GetName() + '>') 187 else: 188 type_list.append(type_component.GetName()) 189 return type_list 190 elif attr_type.GetClass() == _SEQUENCE: 191 union_member_types = [] 192 if attr_type.GetOneOf(_TYPE).GetChildren()[0].GetClass() == _UNIONTYPE: 193 for union_member in attr_type.GetOneOf(_TYPE).GetOneOf(_UNIONTYPE).GetListOf(_TYPE): 194 if len(union_member.GetChildren()) != 1: 195 raise Exception('Complex type in a union in a sequence is not yet supported') 196 type_component = union_member.GetChildren()[0] 197 union_member_types.append(type_component.GetName()) 198 return '<' + str(union_member_types) + '>' 199 else: 200 for type_component in attr_type.GetOneOf(_TYPE).GetChildren(): 201 if type_component.GetClass() == _SEQUENCE: 202 raise Exception('Sequence in another sequence is not yet supported') 203 else: 204 if type_component.GetClass() == _ARRAY: 205 type_list[-1] += [] 206 else: 207 type_list.append(type_component.GetName()) 208 return '<' + type_list[0] + '>' 209 elif attr_type.GetClass() == _ANY: 210 return _ANY 211 else: 212 for type_component in attribute_node.GetOneOf(_TYPE).GetChildren(): 213 if type_component.GetClass() == _ARRAY: 214 type_list[-1] += '[]' 215 else: 216 type_list.append(type_component.GetName()) 217 return type_list[0] 218 219 220get_operation_type = get_attribute_type 221get_argument_type = get_attribute_type 222 223 224def attribute_node_to_dict(attribute_node): 225 """Returns dictioary of attribute's information. 226 Args: 227 attribute_node: attribute node 228 Returns: 229 dictionary of attribute's information 230 """ 231 return { 232 _NAME: attribute_node.GetName(), 233 _TYPE: get_attribute_type(attribute_node), 234 _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(attribute_node)], 235 _READONLY: attribute_node.GetProperty(_PROP_READONLY, default=False), 236 _STATIC: attribute_node.GetProperty(_PROP_STATIC, default=False), 237 } 238 239 240def get_operation_node_list(interface_node): 241 """Returns operations node list. 242 Args: 243 interface_node: interface node 244 Returns: 245 list of oparation node 246 """ 247 return interface_node.GetListOf(_OPERATION) 248 249 250def get_argument_node_list(operation_node): 251 """Returns list of argument. 252 Args: 253 operation_node: operation node 254 Returns: 255 list of argument node 256 """ 257 return operation_node.GetOneOf(_ARGUMENTS).GetListOf(_ARGUMENT) 258 259 260def argument_node_to_dict(argument_node): 261 """Returns dictionary of argument's information. 262 Args: 263 argument_node: argument node 264 Returns: 265 dictionary of argument's information 266 """ 267 return { 268 _NAME: argument_node.GetName(), 269 _TYPE: get_argument_type(argument_node), 270 } 271 272 273def get_operation_name(operation_node): 274 """Returns openration's name. 275 Args: 276 operation_node: operation node 277 Returns: 278 name of operation 279 """ 280 if operation_node.GetProperty(_PROP_GETTER): 281 return _NAMED_GETTER 282 elif operation_node.GetProperty(_PROP_SETTER): 283 return _NAMED_SETTER 284 elif operation_node.GetProperty(_PROP_DELETER): 285 return _NAMED_DELETER 286 else: 287 return operation_node.GetName() 288 289 290def operation_node_to_dict(operation_node): 291 """Returns dictionary of operation's information. 292 Args: 293 operation_node: operation node 294 Returns: 295 dictionary of operation's informantion 296 """ 297 return { 298 _NAME: get_operation_name(operation_node), 299 _ARGUMENTS: [argument_node_to_dict(argument) for argument in get_argument_node_list(operation_node) 300 if argument_node_to_dict(argument)], 301 _TYPE: get_operation_type(operation_node), 302 _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(operation_node)], 303 _STATIC: operation_node.GetProperty(_PROP_STATIC, default=False), 304 } 305 306 307def get_extattribute_node_list(node): 308 """Returns list of ExtAttribute. 309 Args: 310 node: IDL node 311 Returns: 312 list of ExtAttrbute 313 """ 314 if node.GetOneOf(_EXTATTRIBUTES): 315 return node.GetOneOf(_EXTATTRIBUTES).GetListOf(_EXTATTRIBUTE) 316 else: 317 return [] 318 319 320def extattr_node_to_dict(extattr): 321 """Returns dictionary of ExtAttribute's information. 322 Args: 323 extattr: ExtAttribute node 324 Returns: 325 dictionary of ExtAttribute's information 326 """ 327 return { 328 _NAME: extattr.GetName(), 329 } 330 331 332def inherit_node_to_dict(interface_node): 333 """Returns a dictionary of inheritance information. 334 Args: 335 interface_node: interface node 336 Returns: 337 A dictioanry of inheritance information. 338 """ 339 inherit = interface_node.GetOneOf(_INHERIT) 340 if inherit: 341 return {_PARENT: inherit.GetName()} 342 else: 343 return {_PARENT: None} 344 345 346def interface_node_to_dict(interface_node): 347 """Returns a dictioary of interface information. 348 Args: 349 interface_node: interface node 350 Returns: 351 A dictionary of the interface information. 352 """ 353 return { 354 _NAME: interface_node.GetName(), 355 _FILEPATH: get_filepath(interface_node), 356 _CONSTS: [const_node_to_dict(const) for const in get_const_node_list(interface_node)], 357 _ATTRIBUTES: [attribute_node_to_dict(attr) for attr in get_attribute_node_list(interface_node) if attr], 358 _OPERATIONS: [operation_node_to_dict(operation) for operation in get_operation_node_list(interface_node) if operation], 359 _EXTATTRIBUTES: [extattr_node_to_dict(extattr) for extattr in get_extattribute_node_list(interface_node)], 360 _INHERIT: inherit_node_to_dict(interface_node) 361 } 362 363 364def merge_partial_dicts(interfaces_dict, partials_dict): 365 """Merges partial interface into non-partial interface. 366 Args: 367 interfaces_dict: A dict of the non-partial interfaces. 368 partial_dict: A dict of partial interfaces. 369 Returns: 370 A merged dictionary of |interface_dict| with |partial_dict|. 371 """ 372 for interface_name, partial in partials_dict.iteritems(): 373 interface = interfaces_dict.get(interface_name) 374 if not interface: 375 raise Exception('There is a partial interface, but the corresponding non-partial interface was not found.') 376 for member in _MEMBERS: 377 interface[member].extend(partial.get(member)) 378 interface.setdefault(_PARTIAL_FILEPATH, []).append(partial[_FILEPATH]) 379 return interfaces_dict 380 381 382def merge_implement_nodes(interfaces_dict, implement_node_list): 383 """Combines a dict of interface information with referenced interface information. 384 Args: 385 interfaces_dict: dict of interface information 386 implement_nodes: list of implemented interface node 387 Returns: 388 A dict of interface information combined with implements nodes. 389 """ 390 for implement in implement_node_list: 391 reference = implement.GetProperty(_PROP_REFERENCE) 392 implement = implement.GetName() 393 if reference not in interfaces_dict.keys() or implement not in interfaces_dict.keys(): 394 raise Exception('There is not corresponding implement or reference interface.') 395 for member in _MEMBERS: 396 interfaces_dict[implement][member].extend(interfaces_dict[reference].get(member)) 397 return interfaces_dict 398 399 400def export_to_jsonfile(dictionary, json_file): 401 """Writes a Python dict into a JSON file. 402 Args: 403 dictioary: interface dictionary 404 json_file: json file for output 405 """ 406 with open(json_file, 'w') as f: 407 json.dump(dictionary, f, sort_keys=True) 408 409 410def usage(): 411 sys.stdout.write('Usage: collect_idls_into_json.py <path_file.txt> <output_file.json>\n') 412 413 414def main(args): 415 if len(args) != 2: 416 usage() 417 exit(1) 418 path_file = args[0] 419 json_file = args[1] 420 path_list = utilities.read_file_to_list(path_file) 421 implement_node_list = [definition 422 for definition in get_definitions(path_list) 423 if is_implements(definition)] 424 interfaces_dict = {definition.GetName(): interface_node_to_dict(definition) 425 for definition in get_definitions(path_list) 426 if not is_partial(definition)} 427 partials_dict = {definition.GetName(): interface_node_to_dict(definition) 428 for definition in get_definitions(path_list) 429 if is_partial(definition)} 430 dictionary = merge_partial_dicts(interfaces_dict, partials_dict) 431 interfaces_dict = merge_implement_nodes(interfaces_dict, implement_node_list) 432 export_to_jsonfile(dictionary, json_file) 433 434 435if __name__ == '__main__': 436 main(sys.argv[1:]) 437