Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: third_party/chrome/tools/idl_schema.py

Issue 12261015: Import chrome idl into third_party (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #! /usr/bin/env python
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
4 # found in the LICENSE file.
5
6 import itertools
7 import json
8 import os.path
9 import re
10 import sys
11
12 from json_parse import OrderedDict
13 import schema_util
14
15 # 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
17 # 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
19 # the JSON schema compiler understands. compiler.py drives both idl_schema.py
20 # and json_schema.py.
21
22 # idl_parser expects to be able to import certain files in its directory,
23 # so let's set things up the way it wants.
24 _idl_generators_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
25 os.pardir, os.pardir, 'ppapi', 'generators')
26 if _idl_generators_path in sys.path:
27 import idl_parser
28 else:
29 sys.path.insert(0, _idl_generators_path)
30 try:
31 import idl_parser
32 finally:
33 sys.path.pop(0)
34
35 def ProcessComment(comment):
36 '''
37 Convert a comment into a parent comment and a list of parameter comments.
38
39 Function comments are of the form:
40 Function documentation. May contain HTML and multiple lines.
41
42 |arg1_name|: Description of arg1. Use <var>argument</var> to refer
43 to other arguments.
44 |arg2_name|: Description of arg2...
45
46 Newlines are removed, and leading and trailing whitespace is stripped.
47
48 Args:
49 comment: The string from a Comment node.
50
51 Returns: A tuple that looks like:
52 (
53 "The processed comment, minus all |parameter| mentions.",
54 {
55 'parameter_name_1': "The comment that followed |parameter_name_1|:",
56 ...
57 }
58 )
59 '''
60 # Find all the parameter comments of the form '|name|: comment'.
61 parameter_starts = list(re.finditer(r' *\|([^|]*)\| *: *', comment))
62
63 # Get the parent comment (everything before the first parameter comment.
64 first_parameter_location = (parameter_starts[0].start()
65 if parameter_starts else len(comment))
66 parent_comment = comment[:first_parameter_location]
67
68 # We replace \n\n with <br/><br/> here and below, because the documentation
69 # needs to know where the newlines should be, and this is easier than
70 # escaping \n.
71 parent_comment = (parent_comment.strip().replace('\n\n', '<br/><br/>')
72 .replace('\n', ''))
73
74 params = OrderedDict()
75 for (cur_param, next_param) in itertools.izip_longest(parameter_starts,
76 parameter_starts[1:]):
77 param_name = cur_param.group(1)
78
79 # A parameter's comment goes from the end of its introduction to the
80 # beginning of the next parameter's introduction.
81 param_comment_start = cur_param.end()
82 param_comment_end = next_param.start() if next_param else len(comment)
83 params[param_name] = (comment[param_comment_start:param_comment_end
84 ].strip().replace('\n\n', '<br/><br/>')
85 .replace('\n', ''))
86 return (parent_comment, params)
87
88 class Callspec(object):
89 '''
90 Given a Callspec node representing an IDL function declaration, converts into
91 a name/value pair where the value is a list of function parameters.
92 '''
93 def __init__(self, callspec_node, comment):
94 self.node = callspec_node
95 self.comment = comment
96
97 def process(self, callbacks):
98 parameters = []
99 for node in self.node.children:
100 parameter = Param(node).process(callbacks)
101 if parameter['name'] in self.comment:
102 parameter['description'] = self.comment[parameter['name']]
103 parameters.append(parameter)
104 return self.node.GetName(), parameters
105
106 class Param(object):
107 '''
108 Given a Param node representing a function parameter, converts into a Python
109 dictionary that the JSON schema compiler expects to see.
110 '''
111 def __init__(self, param_node):
112 self.node = param_node
113
114 def process(self, callbacks):
115 return Typeref(self.node.GetProperty('TYPEREF'),
116 self.node,
117 {'name': self.node.GetName()}).process(callbacks)
118
119 class Dictionary(object):
120 '''
121 Given an IDL Dictionary node, converts into a Python dictionary that the JSON
122 schema compiler expects to see.
123 '''
124 def __init__(self, dictionary_node):
125 self.node = dictionary_node
126
127 def process(self, callbacks):
128 properties = OrderedDict()
129 for node in self.node.children:
130 if node.cls == 'Member':
131 k, v = Member(node).process(callbacks)
132 properties[k] = v
133 result = {'id': self.node.GetName(),
134 'properties': properties,
135 'type': 'object'}
136 if self.node.GetProperty('inline_doc'):
137 result['inline_doc'] = True
138 return result
139
140
141 class Member(object):
142 '''
143 Given an IDL dictionary or interface member, converts into a name/value pair
144 where the value is a Python dictionary that the JSON schema compiler expects
145 to see.
146 '''
147 def __init__(self, member_node):
148 self.node = member_node
149
150 def process(self, callbacks):
151 properties = OrderedDict()
152 name = self.node.GetName()
153 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'):
154 if self.node.GetProperty(property_name):
155 properties[property_name.lower()] = True
156 is_function = False
157 parameter_comments = OrderedDict()
158 for node in self.node.children:
159 if node.cls == 'Comment':
160 (parent_comment, parameter_comments) = ProcessComment(node.GetName())
161 properties['description'] = parent_comment
162 elif node.cls == 'Callspec':
163 is_function = True
164 name, parameters = Callspec(node, parameter_comments).process(callbacks)
165 properties['parameters'] = parameters
166 properties['name'] = name
167 if is_function:
168 properties['type'] = 'function'
169 else:
170 properties = Typeref(self.node.GetProperty('TYPEREF'),
171 self.node, properties).process(callbacks)
172 enum_values = self.node.GetProperty('legalValues')
173 if enum_values:
174 if properties['type'] == 'integer':
175 enum_values = map(int, enum_values)
176 elif properties['type'] == 'double':
177 enum_values = map(float, enum_values)
178 properties['enum'] = enum_values
179 return name, properties
180
181 class Typeref(object):
182 '''
183 Given a TYPEREF property representing the type of dictionary member or
184 function parameter, converts into a Python dictionary that the JSON schema
185 compiler expects to see.
186 '''
187 def __init__(self, typeref, parent, additional_properties=OrderedDict()):
188 self.typeref = typeref
189 self.parent = parent
190 self.additional_properties = additional_properties
191
192 def process(self, callbacks):
193 properties = self.additional_properties
194 result = properties
195
196 if self.parent.GetProperty('OPTIONAL', False):
197 properties['optional'] = True
198
199 # The IDL parser denotes array types by adding a child 'Array' node onto
200 # the Param node in the Callspec.
201 for sibling in self.parent.GetChildren():
202 if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName():
203 properties['type'] = 'array'
204 properties['items'] = OrderedDict()
205 properties = properties['items']
206 break
207
208 if self.typeref == 'DOMString':
209 properties['type'] = 'string'
210 elif self.typeref == 'boolean':
211 properties['type'] = 'boolean'
212 elif self.typeref == 'double':
213 properties['type'] = 'number'
214 elif self.typeref == 'long':
215 properties['type'] = 'integer'
216 elif self.typeref == 'any':
217 properties['type'] = 'any'
218 elif self.typeref == 'object':
219 properties['type'] = 'object'
220 if 'additionalProperties' not in properties:
221 properties['additionalProperties'] = OrderedDict()
222 properties['additionalProperties']['type'] = 'any'
223 instance_of = self.parent.GetProperty('instanceOf')
224 if instance_of:
225 properties['isInstanceOf'] = instance_of
226 elif self.typeref == 'ArrayBuffer':
227 properties['type'] = 'binary'
228 properties['isInstanceOf'] = 'ArrayBuffer'
229 elif self.typeref is None:
230 properties['type'] = 'function'
231 else:
232 if self.typeref in callbacks:
233 # Do not override name and description if they are already specified.
234 name = properties.get('name', None)
235 description = properties.get('description', None)
236 properties.update(callbacks[self.typeref])
237 if description is not None:
238 properties['description'] = description
239 if name is not None:
240 properties['name'] = name
241 else:
242 properties['$ref'] = self.typeref
243 return result
244
245
246 class Enum(object):
247 '''
248 Given an IDL Enum node, converts into a Python dictionary that the JSON
249 schema compiler expects to see.
250 '''
251 def __init__(self, enum_node):
252 self.node = enum_node
253 self.description = ''
254
255 def process(self, callbacks):
256 enum = []
257 for node in self.node.children:
258 if node.cls == 'EnumItem':
259 enum.append(node.GetName())
260 elif node.cls == 'Comment':
261 self.description = ProcessComment(node.GetName())[0]
262 else:
263 sys.exit('Did not process %s %s' % (node.cls, node))
264 result = {'id' : self.node.GetName(),
265 'description': self.description,
266 'type': 'string',
267 'enum': enum}
268 if self.node.GetProperty('inline_doc'):
269 result['inline_doc'] = True
270 return result
271
272
273 class Namespace(object):
274 '''
275 Given an IDLNode representing an IDL namespace, converts into a Python
276 dictionary that the JSON schema compiler expects to see.
277 '''
278
279 def __init__(self, namespace_node, nodoc=False, permissions=None,
280 internal=False):
281 self.namespace = namespace_node
282 self.nodoc = nodoc
283 self.internal = internal
284 self.events = []
285 self.functions = []
286 self.types = []
287 self.callbacks = OrderedDict()
288 self.permissions = permissions or []
289
290 def process(self):
291 for node in self.namespace.children:
292 if node.cls == 'Dictionary':
293 self.types.append(Dictionary(node).process(self.callbacks))
294 elif node.cls == 'Callback':
295 k, v = Member(node).process(self.callbacks)
296 self.callbacks[k] = v
297 elif node.cls == 'Interface' and node.GetName() == 'Functions':
298 self.functions = self.process_interface(node)
299 elif node.cls == 'Interface' and node.GetName() == 'Events':
300 self.events = self.process_interface(node)
301 elif node.cls == 'Enum':
302 self.types.append(Enum(node).process(self.callbacks))
303 else:
304 sys.exit('Did not process %s %s' % (node.cls, node))
305 return {'namespace': self.namespace.GetName(),
306 'nodoc': self.nodoc,
307 'documentation_permissions_required': self.permissions,
308 'types': self.types,
309 'functions': self.functions,
310 'internal': self.internal,
311 'events': self.events}
312
313 def process_interface(self, node):
314 members = []
315 for member in node.children:
316 if member.cls == 'Member':
317 name, properties = Member(member).process(self.callbacks)
318 members.append(properties)
319 return members
320
321 class IDLSchema(object):
322 '''
323 Given a list of IDLNodes and IDLAttributes, converts into a Python list
324 of api_defs that the JSON schema compiler expects to see.
325 '''
326
327 def __init__(self, idl):
328 self.idl = idl
329
330 def process(self):
331 namespaces = []
332 nodoc = False
333 internal = False
334 permissions = None
335 for node in self.idl:
336 if node.cls == 'Namespace':
337 namespace = Namespace(node, nodoc, permissions, internal)
338 namespaces.append(namespace.process())
339 nodoc = False
340 internal = False
341 elif node.cls == 'Copyright':
342 continue
343 elif node.cls == 'Comment':
344 continue
345 elif node.cls == 'ExtAttribute':
346 if node.name == 'nodoc':
347 nodoc = bool(node.value)
348 elif node.name == 'permissions':
349 permission = node.value.split(',')
350 elif node.name == 'internal':
351 internal = bool(node.value)
352 else:
353 continue
354 else:
355 sys.exit('Did not process %s %s' % (node.cls, node))
356 return namespaces
357
358 def Load(filename):
359 '''
360 Given the filename of an IDL file, parses it and returns an equivalent
361 Python dictionary in a format that the JSON schema compiler expects to see.
362 '''
363
364 f = open(filename, 'r')
365 contents = f.read()
366 f.close()
367
368 idl = idl_parser.IDLParser().ParseData(contents, filename)
369 idl_schema = IDLSchema(idl)
370 return idl_schema.process()
371
372 def Main():
373 '''
374 Dump a json serialization of parse result for the IDL files whose names
375 were passed in on the command line.
376 '''
377 for filename in sys.argv[1:]:
378 schema = Load(filename)
379 print json.dumps(schema, indent=2)
380
381 if __name__ == '__main__':
382 Main()
OLDNEW
« no previous file with comments | « third_party/chrome/tools/highlighters/pygments_highlighter.py ('k') | third_party/chrome/tools/idl_schema_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698