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 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 { | 48 { |
49 'parameter_name_1': "The comment that followed |parameter_name_1|:", | 49 'parameter_name_1': "The comment that followed |parameter_name_1|:", |
50 ... | 50 ... |
51 } | 51 } |
52 ) | 52 ) |
53 ''' | 53 ''' |
54 | 54 |
55 # Escape double quotes. | 55 # Escape double quotes. |
56 comment = comment.replace('"', '\\"'); | 56 comment = comment.replace('"', '\\"'); |
57 | 57 |
58 # Find all the parameter comments of the form "|name|: comment". | 58 # Find all the parameter comments of the form '|name|: comment'. |
59 parameter_starts = list(re.finditer(r'\n *\|([^|]*)\| *: *', comment)) | 59 parameter_starts = list(re.finditer(r'\n *\|([^|]*)\| *: *', comment)) |
60 | 60 |
61 # Get the parent comment (everything before the first parameter comment. | 61 # Get the parent comment (everything before the first parameter comment. |
62 first_parameter_location = (parameter_starts[0].start() | 62 first_parameter_location = (parameter_starts[0].start() |
63 if parameter_starts else len(comment)) | 63 if parameter_starts else len(comment)) |
64 parent_comment = comment[:first_parameter_location] | 64 parent_comment = comment[:first_parameter_location] |
65 parent_comment = parent_comment.replace('\n', '').strip() | 65 parent_comment = parent_comment.replace('\n', '').strip() |
66 | 66 |
67 params = {} | 67 params = {} |
68 for (cur_param, next_param) in itertools.izip_longest(parameter_starts, | 68 for (cur_param, next_param) in itertools.izip_longest(parameter_starts, |
(...skipping 28 matching lines...) Expand all Loading... |
97 | 97 |
98 class Param(object): | 98 class Param(object): |
99 ''' | 99 ''' |
100 Given a Param node representing a function parameter, converts into a Python | 100 Given a Param node representing a function parameter, converts into a Python |
101 dictionary that the JSON schema compiler expects to see. | 101 dictionary that the JSON schema compiler expects to see. |
102 ''' | 102 ''' |
103 def __init__(self, param_node): | 103 def __init__(self, param_node): |
104 self.node = param_node | 104 self.node = param_node |
105 | 105 |
106 def process(self, callbacks): | 106 def process(self, callbacks): |
107 return Typeref(self.node.GetProperty( 'TYPEREF'), | 107 return Typeref(self.node.GetProperty('TYPEREF'), |
108 self.node, | 108 self.node, |
109 { 'name': self.node.GetName() }).process(callbacks) | 109 {'name': self.node.GetName()}).process(callbacks) |
110 | 110 |
111 class Dictionary(object): | 111 class Dictionary(object): |
112 ''' | 112 ''' |
113 Given an IDL Dictionary node, converts into a Python dictionary that the JSON | 113 Given an IDL Dictionary node, converts into a Python dictionary that the JSON |
114 schema compiler expects to see. | 114 schema compiler expects to see. |
115 ''' | 115 ''' |
116 def __init__(self, dictionary_node): | 116 def __init__(self, dictionary_node): |
117 self.node = dictionary_node | 117 self.node = dictionary_node |
118 | 118 |
119 def process(self, callbacks): | 119 def process(self, callbacks): |
120 properties = {} | 120 properties = {} |
121 for node in self.node.children: | 121 for node in self.node.children: |
122 if node.cls == 'Member': | 122 if node.cls == 'Member': |
123 k, v = Member(node).process(callbacks) | 123 k, v = Member(node).process(callbacks) |
124 properties[k] = v | 124 properties[k] = v |
125 return { 'id': self.node.GetName(), | 125 result = {'id': self.node.GetName(), |
126 'properties': properties, | 126 'properties': properties, |
127 'type': 'object' } | 127 'type': 'object'} |
128 | 128 if self.node.GetProperty('inline_doc'): |
129 class Enum(object): | 129 result['inline_doc'] = True |
130 ''' | 130 return result |
131 Given an IDL Enum node, converts into a Python dictionary that the JSON | |
132 schema compiler expects to see. | |
133 ''' | |
134 def __init__(self, enum_node): | |
135 self.node = enum_node | |
136 | |
137 def process(self, callbacks): | |
138 enum = [] | |
139 for node in self.node.children: | |
140 if node.cls == 'EnumItem': | |
141 name = node.GetName() | |
142 enum.append(name) | |
143 else: | |
144 sys.exit("Did not process %s %s" % (node.cls, node)) | |
145 return { "id" : self.node.GetName(), | |
146 'enum': enum, | |
147 'type': 'string' } | |
148 | |
149 | 131 |
150 | 132 |
151 class Member(object): | 133 class Member(object): |
152 ''' | 134 ''' |
153 Given an IDL dictionary or interface member, converts into a name/value pair | 135 Given an IDL dictionary or interface member, converts into a name/value pair |
154 where the value is a Python dictionary that the JSON schema compiler expects | 136 where the value is a Python dictionary that the JSON schema compiler expects |
155 to see. | 137 to see. |
156 ''' | 138 ''' |
157 def __init__(self, member_node): | 139 def __init__(self, member_node): |
158 self.node = member_node | 140 self.node = member_node |
159 | 141 |
160 def process(self, callbacks): | 142 def process(self, callbacks): |
161 properties = {} | 143 properties = {} |
162 name = self.node.GetName() | 144 name = self.node.GetName() |
163 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'): | 145 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'): |
164 if self.node.GetProperty(property_name): | 146 if self.node.GetProperty(property_name): |
165 properties[property_name.lower()] = True | 147 properties[property_name.lower()] = True |
166 is_function = False | 148 is_function = False |
167 parameter_comments = {} | 149 parameter_comments = {} |
168 for node in self.node.children: | 150 for node in self.node.children: |
169 if node.cls == 'Comment': | 151 if node.cls == 'Comment': |
170 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) | 152 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) |
171 properties['description'] = parent_comment | 153 properties['description'] = parent_comment |
172 for node in self.node.children: | 154 elif node.cls == 'Callspec': |
173 if node.cls == 'Callspec': | |
174 is_function = True | 155 is_function = True |
175 name, parameters = Callspec(node, parameter_comments).process(callbacks) | 156 name, parameters = Callspec(node, parameter_comments).process(callbacks) |
176 properties['parameters'] = parameters | 157 properties['parameters'] = parameters |
177 properties['name'] = name | 158 properties['name'] = name |
178 if is_function: | 159 if is_function: |
179 properties['type'] = 'function' | 160 properties['type'] = 'function' |
180 else: | 161 else: |
181 properties = Typeref(self.node.GetProperty('TYPEREF'), | 162 properties = Typeref(self.node.GetProperty('TYPEREF'), |
182 self.node, properties).process(callbacks) | 163 self.node, properties).process(callbacks) |
| 164 enum_values = self.node.GetProperty('legalValues') |
| 165 if enum_values: |
| 166 if properties['type'] == 'integer': |
| 167 enum_values = map(int, enum_values) |
| 168 elif properties['type'] == 'double': |
| 169 enum_values = map(float, enum_values) |
| 170 properties['enum'] = enum_values |
183 return name, properties | 171 return name, properties |
184 | 172 |
185 class Typeref(object): | 173 class Typeref(object): |
186 ''' | 174 ''' |
187 Given a TYPEREF property representing the type of dictionary member or | 175 Given a TYPEREF property representing the type of dictionary member or |
188 function parameter, converts into a Python dictionary that the JSON schema | 176 function parameter, converts into a Python dictionary that the JSON schema |
189 compiler expects to see. | 177 compiler expects to see. |
190 ''' | 178 ''' |
191 def __init__(self, typeref, parent, additional_properties={}): | 179 def __init__(self, typeref, parent, additional_properties={}): |
192 self.typeref = typeref | 180 self.typeref = typeref |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 elif self.typeref is None: | 221 elif self.typeref is None: |
234 properties['type'] = 'function' | 222 properties['type'] = 'function' |
235 else: | 223 else: |
236 if self.typeref in callbacks: | 224 if self.typeref in callbacks: |
237 properties.update(callbacks[self.typeref]) | 225 properties.update(callbacks[self.typeref]) |
238 else: | 226 else: |
239 properties['$ref'] = self.typeref | 227 properties['$ref'] = self.typeref |
240 | 228 |
241 return result | 229 return result |
242 | 230 |
| 231 |
| 232 class Enum(object): |
| 233 ''' |
| 234 Given an IDL Enum node, converts into a Python dictionary that the JSON |
| 235 schema compiler expects to see. |
| 236 ''' |
| 237 def __init__(self, enum_node): |
| 238 self.node = enum_node |
| 239 self.description = '' |
| 240 |
| 241 def process(self, callbacks): |
| 242 enum = [] |
| 243 for node in self.node.children: |
| 244 if node.cls == 'EnumItem': |
| 245 enum.append(node.GetName()) |
| 246 elif node.cls == 'Comment': |
| 247 self.description = ProcessComment(node.GetName())[0] |
| 248 else: |
| 249 sys.exit('Did not process %s %s' % (node.cls, node)) |
| 250 result = {'id' : self.node.GetName(), |
| 251 'description': self.description, |
| 252 'type': 'string', |
| 253 'enum': enum} |
| 254 if self.node.GetProperty('inline_doc'): |
| 255 result['inline_doc'] = True |
| 256 return result |
| 257 |
| 258 |
243 class Namespace(object): | 259 class Namespace(object): |
244 ''' | 260 ''' |
245 Given an IDLNode representing an IDL namespace, converts into a Python | 261 Given an IDLNode representing an IDL namespace, converts into a Python |
246 dictionary that the JSON schema compiler expects to see. | 262 dictionary that the JSON schema compiler expects to see. |
247 ''' | 263 ''' |
248 | 264 |
249 def __init__(self, namespace_node, nodoc=False): | 265 def __init__(self, namespace_node, nodoc=False, permissions=None): |
250 self.namespace = namespace_node | 266 self.namespace = namespace_node |
251 self.nodoc = nodoc | 267 self.nodoc = nodoc |
252 self.events = [] | 268 self.events = [] |
253 self.functions = [] | 269 self.functions = [] |
254 self.types = [] | 270 self.types = [] |
255 self.callbacks = {} | 271 self.callbacks = {} |
| 272 self.permissions = permissions or [] |
256 | 273 |
257 def process(self): | 274 def process(self): |
258 for node in self.namespace.children: | 275 for node in self.namespace.children: |
259 cls = node.cls | 276 if node.cls == 'Dictionary': |
260 if cls == "Dictionary": | |
261 self.types.append(Dictionary(node).process(self.callbacks)) | 277 self.types.append(Dictionary(node).process(self.callbacks)) |
262 elif cls == "Callback": | 278 elif node.cls == 'Callback': |
263 k, v = Member(node).process(self.callbacks) | 279 k, v = Member(node).process(self.callbacks) |
264 self.callbacks[k] = v | 280 self.callbacks[k] = v |
265 elif cls == "Interface" and node.GetName() == "Functions": | 281 elif node.cls == 'Interface' and node.GetName() == 'Functions': |
266 self.functions = self.process_interface(node) | 282 self.functions = self.process_interface(node) |
267 elif cls == "Interface" and node.GetName() == "Events": | 283 elif node.cls == 'Interface' and node.GetName() == 'Events': |
268 self.events = self.process_interface(node) | 284 self.events = self.process_interface(node) |
269 elif cls == "Enum": | 285 elif node.cls == 'Enum': |
270 self.types.append(Enum(node).process(self.callbacks)) | 286 self.types.append(Enum(node).process(self.callbacks)) |
271 else: | 287 else: |
272 sys.exit("Did not process %s %s" % (node.cls, node)) | 288 sys.exit('Did not process %s %s' % (node.cls, node)) |
273 | 289 return {'namespace': self.namespace.GetName(), |
274 return { 'events': self.events, | 290 'nodoc': self.nodoc, |
275 'functions': self.functions, | 291 'documentation_permissions_required': self.permissions, |
276 'types': self.types, | 292 'types': self.types, |
277 'namespace': self.namespace.GetName(), | 293 'functions': self.functions, |
278 'nodoc': self.nodoc } | 294 'events': self.events} |
279 | 295 |
280 def process_interface(self, node): | 296 def process_interface(self, node): |
281 members = [] | 297 members = [] |
282 for member in node.children: | 298 for member in node.children: |
283 if member.cls == 'Member': | 299 if member.cls == 'Member': |
284 name, properties = Member(member).process(self.callbacks) | 300 name, properties = Member(member).process(self.callbacks) |
285 members.append(properties) | 301 members.append(properties) |
286 return members | 302 return members |
287 | 303 |
288 class IDLSchema(object): | 304 class IDLSchema(object): |
289 ''' | 305 ''' |
290 Given a list of IDLNodes and IDLAttributes, converts into a Python list | 306 Given a list of IDLNodes and IDLAttributes, converts into a Python list |
291 of api_defs that the JSON schema compiler expects to see. | 307 of api_defs that the JSON schema compiler expects to see. |
292 ''' | 308 ''' |
293 | 309 |
294 def __init__(self, idl): | 310 def __init__(self, idl): |
295 self.idl = idl | 311 self.idl = idl |
296 | 312 |
297 def process(self): | 313 def process(self): |
298 namespaces = [] | 314 namespaces = [] |
| 315 nodoc = False |
| 316 permissions = None |
299 for node in self.idl: | 317 for node in self.idl: |
300 nodoc = False | 318 if node.cls == 'Namespace': |
301 cls = node.cls | 319 namespace = Namespace(node, nodoc, permissions) |
302 if cls == 'Namespace': | |
303 namespace = Namespace(node, nodoc) | |
304 namespaces.append(namespace.process()) | 320 namespaces.append(namespace.process()) |
305 elif cls == 'Copyright': | 321 elif node.cls == 'Copyright': |
306 continue | 322 continue |
307 elif cls == 'Comment': | 323 elif node.cls == 'Comment': |
308 continue | 324 continue |
309 elif cls == 'ExtAttribute': | 325 elif node.cls == 'ExtAttribute': |
310 if node.name == 'nodoc': | 326 if node.name == 'nodoc': |
311 nodoc = bool(node.value) | 327 nodoc = bool(node.value) |
| 328 elif node.name == 'permissions': |
| 329 permission = node.value.split(',') |
312 else: | 330 else: |
313 continue | 331 continue |
314 else: | 332 else: |
315 sys.exit("Did not process %s %s" % (node.cls, node)) | 333 sys.exit('Did not process %s %s' % (node.cls, node)) |
316 schema_util.PrefixSchemasWithNamespace(namespaces) | 334 schema_util.PrefixSchemasWithNamespace(namespaces) |
317 return namespaces | 335 return namespaces |
318 | 336 |
319 def Load(filename): | 337 def Load(filename): |
320 ''' | 338 ''' |
321 Given the filename of an IDL file, parses it and returns an equivalent | 339 Given the filename of an IDL file, parses it and returns an equivalent |
322 Python dictionary in a format that the JSON schema compiler expects to see. | 340 Python dictionary in a format that the JSON schema compiler expects to see. |
323 ''' | 341 ''' |
324 | 342 |
325 f = open(filename, 'r') | 343 f = open(filename, 'r') |
326 contents = f.read() | 344 contents = f.read() |
327 f.close() | 345 f.close() |
328 | 346 |
329 idl = idl_parser.IDLParser().ParseData(contents, filename) | 347 idl = idl_parser.IDLParser().ParseData(contents, filename) |
330 idl_schema = IDLSchema(idl) | 348 idl_schema = IDLSchema(idl) |
331 return idl_schema.process() | 349 return idl_schema.process() |
332 | 350 |
333 def Main(): | 351 def Main(): |
334 ''' | 352 ''' |
335 Dump a json serialization of parse result for the IDL files whose names | 353 Dump a json serialization of parse result for the IDL files whose names |
336 were passed in on the command line. | 354 were passed in on the command line. |
337 ''' | 355 ''' |
338 for filename in sys.argv[1:]: | 356 for filename in sys.argv[1:]: |
339 schema = Load(filename) | 357 schema = Load(filename) |
340 print json.dumps(schema, indent=2) | 358 print json.dumps(schema, indent=2) |
341 | 359 |
342 if __name__ == '__main__': | 360 if __name__ == '__main__': |
343 Main() | 361 Main() |
OLD | NEW |