| OLD | NEW |
| 1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import itertools | 6 import itertools |
| 7 import json | 7 import json |
| 8 import os.path | 8 import os.path |
| 9 import re | 9 import re |
| 10 import sys | 10 import sys |
| 11 | 11 |
| 12 from json_parse import OrderedDict | 12 from json_parse import OrderedDict |
| 13 import schema_util | |
| 14 | 13 |
| 15 # This file is a peer to json_schema.py. Each of these files understands a | 14 # This file is a peer to json_schema.py. Each of these files understands a |
| 16 # certain format describing APIs (either JSON or IDL), reads files written | 15 # certain format describing APIs (either JSON or IDL), reads files written |
| 17 # in that format into memory, and emits them as a Python array of objects | 16 # in that format into memory, and emits them as a Python array of objects |
| 18 # corresponding to those APIs, where the objects are formatted in a way that | 17 # corresponding to those APIs, where the objects are formatted in a way that |
| 19 # the JSON schema compiler understands. compiler.py drives both idl_schema.py | 18 # the JSON schema compiler understands. compiler.py drives both idl_schema.py |
| 20 # and json_schema.py. | 19 # and json_schema.py. |
| 21 | 20 |
| 22 # idl_parser expects to be able to import certain files in its directory, | 21 # idl_parser expects to be able to import certain files in its directory, |
| 23 # so let's set things up the way it wants. | 22 # so let's set things up the way it wants. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 | 77 |
| 79 # A parameter's comment goes from the end of its introduction to the | 78 # A parameter's comment goes from the end of its introduction to the |
| 80 # beginning of the next parameter's introduction. | 79 # beginning of the next parameter's introduction. |
| 81 param_comment_start = cur_param.end() | 80 param_comment_start = cur_param.end() |
| 82 param_comment_end = next_param.start() if next_param else len(comment) | 81 param_comment_end = next_param.start() if next_param else len(comment) |
| 83 params[param_name] = (comment[param_comment_start:param_comment_end | 82 params[param_name] = (comment[param_comment_start:param_comment_end |
| 84 ].strip().replace('\n\n', '<br/><br/>') | 83 ].strip().replace('\n\n', '<br/><br/>') |
| 85 .replace('\n', '')) | 84 .replace('\n', '')) |
| 86 return (parent_comment, params) | 85 return (parent_comment, params) |
| 87 | 86 |
| 87 |
| 88 class Callspec(object): | 88 class Callspec(object): |
| 89 ''' | 89 ''' |
| 90 Given a Callspec node representing an IDL function declaration, converts into | 90 Given a Callspec node representing an IDL function declaration, converts into |
| 91 a tuple: | 91 a tuple: |
| 92 (name, list of function parameters, return type) | 92 (name, list of function parameters, return type) |
| 93 ''' | 93 ''' |
| 94 def __init__(self, callspec_node, comment): | 94 def __init__(self, callspec_node, comment): |
| 95 self.node = callspec_node | 95 self.node = callspec_node |
| 96 self.comment = comment | 96 self.comment = comment |
| 97 | 97 |
| 98 def process(self, callbacks): | 98 def process(self, callbacks): |
| 99 parameters = [] | 99 parameters = [] |
| 100 return_type = None | 100 return_type = None |
| 101 if self.node.GetProperty('TYPEREF') not in ('void', None): | 101 if self.node.GetProperty('TYPEREF') not in ('void', None): |
| 102 return_type = Typeref(self.node.GetProperty('TYPEREF'), | 102 return_type = Typeref(self.node.GetProperty('TYPEREF'), |
| 103 self.node, | 103 self.node, |
| 104 {'name': self.node.GetName()}).process(callbacks) | 104 {'name': self.node.GetName()}).process(callbacks) |
| 105 # The IDL parser doesn't allow specifying return types as optional. | 105 # The IDL parser doesn't allow specifying return types as optional. |
| 106 # Instead we infer any object return values to be optional. | 106 # Instead we infer any object return values to be optional. |
| 107 # TODO(asargent): fix the IDL parser to support optional return types. | 107 # TODO(asargent): fix the IDL parser to support optional return types. |
| 108 if return_type.get('type') == 'object' or '$ref' in return_type: | 108 if return_type.get('type') == 'object' or '$ref' in return_type: |
| 109 return_type['optional'] = True; | 109 return_type['optional'] = True |
| 110 for node in self.node.children: | 110 for node in self.node.children: |
| 111 parameter = Param(node).process(callbacks) | 111 parameter = Param(node).process(callbacks) |
| 112 if parameter['name'] in self.comment: | 112 if parameter['name'] in self.comment: |
| 113 parameter['description'] = self.comment[parameter['name']] | 113 parameter['description'] = self.comment[parameter['name']] |
| 114 parameters.append(parameter) | 114 parameters.append(parameter) |
| 115 return (self.node.GetName(), parameters, return_type) | 115 return (self.node.GetName(), parameters, return_type) |
| 116 | 116 |
| 117 |
| 117 class Param(object): | 118 class Param(object): |
| 118 ''' | 119 ''' |
| 119 Given a Param node representing a function parameter, converts into a Python | 120 Given a Param node representing a function parameter, converts into a Python |
| 120 dictionary that the JSON schema compiler expects to see. | 121 dictionary that the JSON schema compiler expects to see. |
| 121 ''' | 122 ''' |
| 122 def __init__(self, param_node): | 123 def __init__(self, param_node): |
| 123 self.node = param_node | 124 self.node = param_node |
| 124 | 125 |
| 125 def process(self, callbacks): | 126 def process(self, callbacks): |
| 126 return Typeref(self.node.GetProperty('TYPEREF'), | 127 return Typeref(self.node.GetProperty('TYPEREF'), |
| 127 self.node, | 128 self.node, |
| 128 {'name': self.node.GetName()}).process(callbacks) | 129 {'name': self.node.GetName()}).process(callbacks) |
| 129 | 130 |
| 131 |
| 130 class Dictionary(object): | 132 class Dictionary(object): |
| 131 ''' | 133 ''' |
| 132 Given an IDL Dictionary node, converts into a Python dictionary that the JSON | 134 Given an IDL Dictionary node, converts into a Python dictionary that the JSON |
| 133 schema compiler expects to see. | 135 schema compiler expects to see. |
| 134 ''' | 136 ''' |
| 135 def __init__(self, dictionary_node): | 137 def __init__(self, dictionary_node): |
| 136 self.node = dictionary_node | 138 self.node = dictionary_node |
| 137 | 139 |
| 138 def process(self, callbacks): | 140 def process(self, callbacks): |
| 139 properties = OrderedDict() | 141 properties = OrderedDict() |
| 140 for node in self.node.children: | 142 for node in self.node.children: |
| 141 if node.cls == 'Member': | 143 if node.cls == 'Member': |
| 142 k, v = Member(node).process(callbacks) | 144 k, v = Member(node).process(callbacks) |
| 143 properties[k] = v | 145 properties[k] = v |
| 144 result = {'id': self.node.GetName(), | 146 result = {'id': self.node.GetName(), |
| 145 'properties': properties, | 147 'properties': properties, |
| 146 'type': 'object'} | 148 'type': 'object'} |
| 147 if self.node.GetProperty('inline_doc'): | 149 if self.node.GetProperty('inline_doc'): |
| 148 result['inline_doc'] = True | 150 result['inline_doc'] = True |
| 149 elif self.node.GetProperty('noinline_doc'): | 151 elif self.node.GetProperty('noinline_doc'): |
| 150 result['noinline_doc'] = True | 152 result['noinline_doc'] = True |
| 151 return result | 153 return result |
| 152 | 154 |
| 153 | 155 |
| 156 |
| 154 class Member(object): | 157 class Member(object): |
| 155 ''' | 158 ''' |
| 156 Given an IDL dictionary or interface member, converts into a name/value pair | 159 Given an IDL dictionary or interface member, converts into a name/value pair |
| 157 where the value is a Python dictionary that the JSON schema compiler expects | 160 where the value is a Python dictionary that the JSON schema compiler expects |
| 158 to see. | 161 to see. |
| 159 ''' | 162 ''' |
| 160 def __init__(self, member_node): | 163 def __init__(self, member_node): |
| 161 self.node = member_node | 164 self.node = member_node |
| 162 | 165 |
| 163 def process(self, callbacks): | 166 def process(self, callbacks): |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 self.node, properties).process(callbacks) | 200 self.node, properties).process(callbacks) |
| 198 enum_values = self.node.GetProperty('legalValues') | 201 enum_values = self.node.GetProperty('legalValues') |
| 199 if enum_values: | 202 if enum_values: |
| 200 if properties['type'] == 'integer': | 203 if properties['type'] == 'integer': |
| 201 enum_values = map(int, enum_values) | 204 enum_values = map(int, enum_values) |
| 202 elif properties['type'] == 'double': | 205 elif properties['type'] == 'double': |
| 203 enum_values = map(float, enum_values) | 206 enum_values = map(float, enum_values) |
| 204 properties['enum'] = enum_values | 207 properties['enum'] = enum_values |
| 205 return name, properties | 208 return name, properties |
| 206 | 209 |
| 210 |
| 207 class Typeref(object): | 211 class Typeref(object): |
| 208 ''' | 212 ''' |
| 209 Given a TYPEREF property representing the type of dictionary member or | 213 Given a TYPEREF property representing the type of dictionary member or |
| 210 function parameter, converts into a Python dictionary that the JSON schema | 214 function parameter, converts into a Python dictionary that the JSON schema |
| 211 compiler expects to see. | 215 compiler expects to see. |
| 212 ''' | 216 ''' |
| 213 def __init__(self, typeref, parent, additional_properties=OrderedDict()): | 217 def __init__(self, typeref, parent, additional_properties=OrderedDict()): |
| 214 self.typeref = typeref | 218 self.typeref = typeref |
| 215 self.parent = parent | 219 self.parent = parent |
| 216 self.additional_properties = additional_properties | 220 self.additional_properties = additional_properties |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 'events': self.events} | 347 'events': self.events} |
| 344 | 348 |
| 345 def process_interface(self, node): | 349 def process_interface(self, node): |
| 346 members = [] | 350 members = [] |
| 347 for member in node.children: | 351 for member in node.children: |
| 348 if member.cls == 'Member': | 352 if member.cls == 'Member': |
| 349 name, properties = Member(member).process(self.callbacks) | 353 name, properties = Member(member).process(self.callbacks) |
| 350 members.append(properties) | 354 members.append(properties) |
| 351 return members | 355 return members |
| 352 | 356 |
| 357 |
| 353 class IDLSchema(object): | 358 class IDLSchema(object): |
| 354 ''' | 359 ''' |
| 355 Given a list of IDLNodes and IDLAttributes, converts into a Python list | 360 Given a list of IDLNodes and IDLAttributes, converts into a Python list |
| 356 of api_defs that the JSON schema compiler expects to see. | 361 of api_defs that the JSON schema compiler expects to see. |
| 357 ''' | 362 ''' |
| 358 | 363 |
| 359 def __init__(self, idl): | 364 def __init__(self, idl): |
| 360 self.idl = idl | 365 self.idl = idl |
| 361 | 366 |
| 362 def process(self): | 367 def process(self): |
| (...skipping 20 matching lines...) Expand all Loading... |
| 383 if node.name == 'nodoc': | 388 if node.name == 'nodoc': |
| 384 nodoc = bool(node.value) | 389 nodoc = bool(node.value) |
| 385 elif node.name == 'internal': | 390 elif node.name == 'internal': |
| 386 internal = bool(node.value) | 391 internal = bool(node.value) |
| 387 else: | 392 else: |
| 388 continue | 393 continue |
| 389 else: | 394 else: |
| 390 sys.exit('Did not process %s %s' % (node.cls, node)) | 395 sys.exit('Did not process %s %s' % (node.cls, node)) |
| 391 return namespaces | 396 return namespaces |
| 392 | 397 |
| 398 |
| 393 def Load(filename): | 399 def Load(filename): |
| 394 ''' | 400 ''' |
| 395 Given the filename of an IDL file, parses it and returns an equivalent | 401 Given the filename of an IDL file, parses it and returns an equivalent |
| 396 Python dictionary in a format that the JSON schema compiler expects to see. | 402 Python dictionary in a format that the JSON schema compiler expects to see. |
| 397 ''' | 403 ''' |
| 398 | 404 |
| 399 f = open(filename, 'r') | 405 f = open(filename, 'r') |
| 400 contents = f.read() | 406 contents = f.read() |
| 401 f.close() | 407 f.close() |
| 402 | 408 |
| 403 idl = idl_parser.IDLParser().ParseData(contents, filename) | 409 idl = idl_parser.IDLParser().ParseData(contents, filename) |
| 404 idl_schema = IDLSchema(idl) | 410 idl_schema = IDLSchema(idl) |
| 405 return idl_schema.process() | 411 return idl_schema.process() |
| 406 | 412 |
| 413 |
| 407 def Main(): | 414 def Main(): |
| 408 ''' | 415 ''' |
| 409 Dump a json serialization of parse result for the IDL files whose names | 416 Dump a json serialization of parse result for the IDL files whose names |
| 410 were passed in on the command line. | 417 were passed in on the command line. |
| 411 ''' | 418 ''' |
| 412 for filename in sys.argv[1:]: | 419 for filename in sys.argv[1:]: |
| 413 schema = Load(filename) | 420 schema = Load(filename) |
| 414 print json.dumps(schema, indent=2) | 421 print json.dumps(schema, indent=2) |
| 415 | 422 |
| 423 |
| 416 if __name__ == '__main__': | 424 if __name__ == '__main__': |
| 417 Main() | 425 Main() |
| OLD | NEW |