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 |