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 json | 6 import json |
7 import os.path | 7 import os.path |
8 import re | 8 import re |
9 import sys | 9 import sys |
10 | 10 |
(...skipping 19 matching lines...) Expand all Loading... |
30 Given the string from a Comment node, parse it into a tuple that looks | 30 Given the string from a Comment node, parse it into a tuple that looks |
31 like: | 31 like: |
32 ( | 32 ( |
33 "The processed comment, minus all |parameter| mentions.", | 33 "The processed comment, minus all |parameter| mentions.", |
34 { | 34 { |
35 'parameter_name_1': "The comment that followed |parameter_name_1|:", | 35 'parameter_name_1': "The comment that followed |parameter_name_1|:", |
36 ... | 36 ... |
37 } | 37 } |
38 ) | 38 ) |
39 ''' | 39 ''' |
40 # Find all the parameter comments of the form "|name|: comment". | 40 # Find all the parameter comments of the form '|name|: comment'. |
41 parameter_comments = re.findall(r'\n *\|([^|]*)\| *: *(.*)', comment) | 41 parameter_comments = re.findall(r'\n *\|([^|]*)\| *: *(.*)', comment) |
42 # Get the parent comment (everything before the first parameter comment. | 42 # Get the parent comment (everything before the first parameter comment. |
43 parent_comment = re.sub(r'\n *\|.*', '', comment) | 43 parent_comment = re.sub(r'\n *\|.*', '', comment) |
44 parent_comment = parent_comment.replace('\n', '').strip() | 44 parent_comment = parent_comment.replace('\n', '').strip() |
45 | 45 |
46 parsed = {} | 46 parsed = {} |
47 for (name, comment) in parameter_comments: | 47 for (name, comment) in parameter_comments: |
48 parsed[name] = comment.replace('\n', '').strip() | 48 parsed[name] = comment.replace('\n', '').strip() |
49 return (parent_comment, parsed) | 49 return (parent_comment, parsed) |
50 | 50 |
(...skipping 17 matching lines...) Expand all Loading... |
68 | 68 |
69 class Param(object): | 69 class Param(object): |
70 ''' | 70 ''' |
71 Given a Param node representing a function parameter, converts into a Python | 71 Given a Param node representing a function parameter, converts into a Python |
72 dictionary that the JSON schema compiler expects to see. | 72 dictionary that the JSON schema compiler expects to see. |
73 ''' | 73 ''' |
74 def __init__(self, param_node): | 74 def __init__(self, param_node): |
75 self.node = param_node | 75 self.node = param_node |
76 | 76 |
77 def process(self, callbacks): | 77 def process(self, callbacks): |
78 return Typeref(self.node.GetProperty( 'TYPEREF'), | 78 return Typeref(self.node.GetProperty('TYPEREF'), |
79 self.node, | 79 self.node, |
80 { 'name': self.node.GetName() }).process(callbacks) | 80 {'name': self.node.GetName()}).process(callbacks) |
81 | 81 |
82 class Dictionary(object): | 82 class Dictionary(object): |
83 ''' | 83 ''' |
84 Given an IDL Dictionary node, converts into a Python dictionary that the JSON | 84 Given an IDL Dictionary node, converts into a Python dictionary that the JSON |
85 schema compiler expects to see. | 85 schema compiler expects to see. |
86 ''' | 86 ''' |
87 def __init__(self, dictionary_node): | 87 def __init__(self, dictionary_node): |
88 self.node = dictionary_node | 88 self.node = dictionary_node |
89 | 89 |
90 def process(self, callbacks): | 90 def process(self, callbacks): |
91 properties = {} | 91 properties = {} |
92 for node in self.node.children: | 92 for node in self.node.children: |
93 if node.cls == 'Member': | 93 if node.cls == 'Member': |
94 k, v = Member(node).process(callbacks) | 94 k, v = Member(node).process(callbacks) |
95 properties[k] = v | 95 properties[k] = v |
96 return { 'id': self.node.GetName(), | 96 result = {'id': self.node.GetName(), |
97 'properties': properties, | 97 'properties': properties, |
98 'type': 'object' } | 98 'type': 'object'} |
99 | 99 if self.node.GetProperty('nodoc'): |
100 class Enum(object): | 100 result['nodoc'] = True |
101 ''' | 101 return result |
102 Given an IDL Enum node, converts into a Python dictionary that the JSON | |
103 schema compiler expects to see. | |
104 ''' | |
105 def __init__(self, enum_node): | |
106 self.node = enum_node | |
107 | |
108 def process(self, callbacks): | |
109 enum = [] | |
110 for node in self.node.children: | |
111 if node.cls == 'EnumItem': | |
112 name = node.GetName() | |
113 enum.append(name) | |
114 else: | |
115 sys.exit("Did not process %s %s" % (node.cls, node)) | |
116 return { "id" : self.node.GetName(), | |
117 'enum': enum, | |
118 'type': 'string' } | |
119 | |
120 | |
121 | 102 |
122 class Member(object): | 103 class Member(object): |
123 ''' | 104 ''' |
124 Given an IDL dictionary or interface member, converts into a name/value pair | 105 Given an IDL dictionary or interface member, converts into a name/value pair |
125 where the value is a Python dictionary that the JSON schema compiler expects | 106 where the value is a Python dictionary that the JSON schema compiler expects |
126 to see. | 107 to see. |
127 ''' | 108 ''' |
128 def __init__(self, member_node): | 109 def __init__(self, member_node): |
129 self.node = member_node | 110 self.node = member_node |
130 | 111 |
131 def process(self, callbacks): | 112 def process(self, callbacks): |
132 properties = {} | 113 properties = {} |
133 name = self.node.GetName() | 114 name = self.node.GetName() |
134 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'): | 115 for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'inline_doc'): |
135 if self.node.GetProperty(property_name): | 116 if self.node.GetProperty(property_name): |
136 properties[property_name.lower()] = True | 117 properties[property_name.lower()] = True |
137 is_function = False | 118 is_function = False |
138 parameter_comments = {} | 119 parameter_comments = {} |
139 for node in self.node.children: | 120 for node in self.node.children: |
140 if node.cls == 'Comment': | 121 if node.cls == 'Comment': |
141 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) | 122 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) |
142 properties['description'] = parent_comment | 123 properties['description'] = parent_comment |
143 for node in self.node.children: | 124 elif node.cls == 'Callspec': |
144 if node.cls == 'Callspec': | |
145 is_function = True | 125 is_function = True |
146 name, parameters = Callspec(node, parameter_comments).process(callbacks) | 126 name, parameters = Callspec(node, parameter_comments).process(callbacks) |
147 properties['parameters'] = parameters | 127 properties['parameters'] = parameters |
148 properties['name'] = name | 128 properties['name'] = name |
149 if is_function: | 129 if is_function: |
150 properties['type'] = 'function' | 130 properties['type'] = 'function' |
151 else: | 131 else: |
152 properties = Typeref(self.node.GetProperty('TYPEREF'), | 132 properties = Typeref(self.node.GetProperty('TYPEREF'), |
153 self.node, properties).process(callbacks) | 133 self.node, properties).process(callbacks) |
| 134 enum_values = self.node.GetProperty('legalValues') |
| 135 if enum_values: |
| 136 if properties['type'] == 'integer': |
| 137 enum_values = map(int, enum_values) |
| 138 elif properties['type'] == 'double': |
| 139 enum_values = map(float, enum_values) |
| 140 properties['enum'] = enum_values |
154 return name, properties | 141 return name, properties |
155 | 142 |
156 class Typeref(object): | 143 class Typeref(object): |
157 ''' | 144 ''' |
158 Given a TYPEREF property representing the type of dictionary member or | 145 Given a TYPEREF property representing the type of dictionary member or |
159 function parameter, converts into a Python dictionary that the JSON schema | 146 function parameter, converts into a Python dictionary that the JSON schema |
160 compiler expects to see. | 147 compiler expects to see. |
161 ''' | 148 ''' |
162 def __init__(self, typeref, parent, additional_properties={}): | 149 def __init__(self, typeref, parent, additional_properties={}): |
163 self.typeref = typeref | 150 self.typeref = typeref |
164 self.parent = parent | 151 self.parent = parent |
165 self.additional_properties = additional_properties | 152 self.additional_properties = additional_properties |
166 | 153 |
167 def process(self, callbacks): | 154 def process(self, callbacks): |
168 properties = self.additional_properties | 155 properties = self.additional_properties |
169 result = properties | 156 result = properties |
170 | 157 |
171 if self.parent.GetProperty('OPTIONAL', False): | 158 if self.parent.GetProperty('OPTIONAL', False): |
172 properties['optional'] = True | 159 properties['optional'] = True |
| 160 if self.parent.GetProperty('inline_doc', False): |
| 161 properties['inline_doc'] = True |
173 | 162 |
174 # The IDL parser denotes array types by adding a child 'Array' node onto | 163 # The IDL parser denotes array types by adding a child 'Array' node onto |
175 # the Param node in the Callspec. | 164 # the Param node in the Callspec. |
176 for sibling in self.parent.GetChildren(): | 165 for sibling in self.parent.GetChildren(): |
177 if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName(): | 166 if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName(): |
178 properties['type'] = 'array' | 167 properties['type'] = 'array' |
179 properties['items'] = {} | 168 properties['items'] = {} |
180 properties = properties['items'] | 169 properties = properties['items'] |
181 break | 170 break |
182 | 171 |
(...skipping 20 matching lines...) Expand all Loading... |
203 elif self.typeref is None: | 192 elif self.typeref is None: |
204 properties['type'] = 'function' | 193 properties['type'] = 'function' |
205 else: | 194 else: |
206 if self.typeref in callbacks: | 195 if self.typeref in callbacks: |
207 properties.update(callbacks[self.typeref]) | 196 properties.update(callbacks[self.typeref]) |
208 else: | 197 else: |
209 properties['$ref'] = self.typeref | 198 properties['$ref'] = self.typeref |
210 | 199 |
211 return result | 200 return result |
212 | 201 |
| 202 |
| 203 class Enum(object): |
| 204 ''' |
| 205 Given an IDL Enum node, converts into a Python dictionary that the JSON |
| 206 schema compiler expects to see. |
| 207 ''' |
| 208 def __init__(self, enum_node): |
| 209 self.node = enum_node |
| 210 self.description = '' |
| 211 |
| 212 def process(self, callbacks): |
| 213 enum = [] |
| 214 for node in self.node.children: |
| 215 if node.cls == 'EnumItem': |
| 216 enum.append(node.GetName()) |
| 217 elif node.cls == 'Comment': |
| 218 self.description = ProcessComment(node.GetName())[0] |
| 219 else: |
| 220 sys.exit('Did not process %s %s' % (node.cls, node)) |
| 221 return {'id' : self.node.GetName(), |
| 222 'description': self.description, |
| 223 'type': 'string', |
| 224 'enum': enum} |
| 225 |
| 226 |
213 class Namespace(object): | 227 class Namespace(object): |
214 ''' | 228 ''' |
215 Given an IDLNode representing an IDL namespace, converts into a Python | 229 Given an IDLNode representing an IDL namespace, converts into a Python |
216 dictionary that the JSON schema compiler expects to see. | 230 dictionary that the JSON schema compiler expects to see. |
217 ''' | 231 ''' |
218 | 232 |
219 def __init__(self, namespace_node, nodoc=False): | 233 def __init__(self, namespace_node, nodoc=False, |
| 234 permissions=None): |
220 self.namespace = namespace_node | 235 self.namespace = namespace_node |
221 self.nodoc = nodoc | 236 self.nodoc = nodoc |
222 self.events = [] | 237 self.events = [] |
223 self.functions = [] | 238 self.functions = [] |
224 self.types = [] | 239 self.types = [] |
225 self.callbacks = {} | 240 self.callbacks = {} |
| 241 self.permissions = permissions or [] |
226 | 242 |
227 def process(self): | 243 def process(self): |
228 for node in self.namespace.children: | 244 for node in self.namespace.children: |
229 cls = node.cls | 245 if node.cls == 'Dictionary': |
230 if cls == "Dictionary": | |
231 self.types.append(Dictionary(node).process(self.callbacks)) | 246 self.types.append(Dictionary(node).process(self.callbacks)) |
232 elif cls == "Callback": | 247 elif node.cls == 'Callback': |
233 k, v = Member(node).process(self.callbacks) | 248 k, v = Member(node).process(self.callbacks) |
234 self.callbacks[k] = v | 249 self.callbacks[k] = v |
235 elif cls == "Interface" and node.GetName() == "Functions": | 250 elif node.cls == 'Interface' and node.GetName() == 'Functions': |
236 self.functions = self.process_interface(node) | 251 self.functions = self.process_interface(node) |
237 elif cls == "Interface" and node.GetName() == "Events": | 252 elif node.cls == 'Interface' and node.GetName() == 'Events': |
238 self.events = self.process_interface(node) | 253 self.events = self.process_interface(node) |
239 elif cls == "Enum": | 254 elif node.cls == 'Enum': |
240 self.types.append(Enum(node).process(self.callbacks)) | 255 self.types.append(Enum(node).process(self.callbacks)) |
| 256 elif node.cls == 'Member': |
| 257 name, properties = Member(node).process(self.callbacks) |
| 258 self.functions.append(properties) |
241 else: | 259 else: |
242 sys.exit("Did not process %s %s" % (node.cls, node)) | 260 sys.exit('Did not process %s %s' % (node.cls, node)) |
243 | 261 |
244 return { 'events': self.events, | 262 return {'namespace': self.namespace.GetName(), |
245 'functions': self.functions, | 263 'documentation_permissions_required': self.permissions, |
246 'types': self.types, | 264 'nodoc': self.nodoc, |
247 'namespace': self.namespace.GetName(), | 265 'types': self.types, |
248 'nodoc': self.nodoc } | 266 'events': self.events, |
| 267 'functions': self.functions} |
249 | 268 |
250 def process_interface(self, node): | 269 def process_interface(self, node): |
251 members = [] | 270 members = [] |
252 for member in node.children: | 271 for member in node.children: |
253 if member.cls == 'Member': | 272 if member.cls == 'Member': |
254 name, properties = Member(member).process(self.callbacks) | 273 name, properties = Member(member).process(self.callbacks) |
255 members.append(properties) | 274 members.append(properties) |
256 return members | 275 return members |
257 | 276 |
258 class IDLSchema(object): | 277 class IDLSchema(object): |
259 ''' | 278 ''' |
260 Given a list of IDLNodes and IDLAttributes, converts into a Python list | 279 Given a list of IDLNodes and IDLAttributes, converts into a Python list |
261 of api_defs that the JSON schema compiler expects to see. | 280 of api_defs that the JSON schema compiler expects to see. |
262 ''' | 281 ''' |
263 | 282 |
264 def __init__(self, idl): | 283 def __init__(self, idl): |
265 self.idl = idl | 284 self.idl = idl |
266 | 285 |
267 def process(self): | 286 def process(self): |
268 namespaces = [] | 287 namespaces = [] |
| 288 nodoc = False |
| 289 permissions = None |
269 for node in self.idl: | 290 for node in self.idl: |
270 nodoc = False | 291 if node.cls == 'Namespace': |
271 cls = node.cls | 292 namespace = Namespace(node, nodoc, permissions) |
272 if cls == 'Namespace': | |
273 namespace = Namespace(node, nodoc) | |
274 namespaces.append(namespace.process()) | 293 namespaces.append(namespace.process()) |
275 elif cls == 'Copyright': | 294 elif node.cls in ['Copyright', 'Comment']: |
276 continue | 295 continue |
277 elif cls == 'Comment': | 296 elif node.cls == 'ExtAttribute': |
278 continue | |
279 elif cls == 'ExtAttribute': | |
280 if node.name == 'nodoc': | 297 if node.name == 'nodoc': |
281 nodoc = bool(node.value) | 298 nodoc = bool(node.value) |
| 299 elif node.name == 'permissions': |
| 300 permissions = node.value.split(',') |
282 else: | 301 else: |
283 continue | 302 continue |
284 else: | 303 else: |
285 sys.exit("Did not process %s %s" % (node.cls, node)) | 304 sys.exit('Did not process %s %s' % (node.cls, node)) |
286 schema_util.PrefixSchemasWithNamespace(namespaces) | 305 schema_util.PrefixSchemasWithNamespace(namespaces) |
287 return namespaces | 306 return namespaces |
288 | 307 |
289 def Load(filename): | 308 def Load(filename): |
290 ''' | 309 ''' |
291 Given the filename of an IDL file, parses it and returns an equivalent | 310 Given the filename of an IDL file, parses it and returns an equivalent |
292 Python dictionary in a format that the JSON schema compiler expects to see. | 311 Python dictionary in a format that the JSON schema compiler expects to see. |
293 ''' | 312 ''' |
294 | 313 |
295 f = open(filename, 'r') | 314 f = open(filename, 'r') |
296 contents = f.read() | 315 contents = f.read() |
297 f.close() | 316 f.close() |
298 | 317 |
299 idl = idl_parser.IDLParser().ParseData(contents, filename) | 318 idl = idl_parser.IDLParser().ParseData(contents, filename) |
300 idl_schema = IDLSchema(idl) | 319 idl_schema = IDLSchema(idl) |
301 return idl_schema.process() | 320 return idl_schema.process() |
302 | 321 |
303 def Main(): | 322 def Main(): |
304 ''' | 323 ''' |
305 Dump a json serialization of parse result for the IDL files whose names | 324 Dump a json serialization of parse result for the IDL files whose names |
306 were passed in on the command line. | 325 were passed in on the command line. |
307 ''' | 326 ''' |
308 for filename in sys.argv[1:]: | 327 for filename in sys.argv[1:]: |
309 schema = Load(filename) | 328 schema = Load(filename) |
310 print json.dumps(schema, indent=2) | 329 print json.dumps(schema, indent=2) |
311 | 330 |
312 if __name__ == '__main__': | 331 if __name__ == '__main__': |
313 Main() | 332 Main() |
OLD | NEW |