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 import schema_util | 13 import schema_util |
13 | 14 |
14 # This file is a peer to json_schema.py. Each of these files understands a | 15 # This file is a peer to json_schema.py. Each of these files understands a |
15 # certain format describing APIs (either JSON or IDL), reads files written | 16 # certain format describing APIs (either JSON or IDL), reads files written |
16 # in that format into memory, and emits them as a Python array of objects | 17 # in that format into memory, and emits them as a Python array of objects |
17 # corresponding to those APIs, where the objects are formatted in a way that | 18 # corresponding to those APIs, where the objects are formatted in a way that |
18 # the JSON schema compiler understands. compiler.py drives both idl_schema.py | 19 # the JSON schema compiler understands. compiler.py drives both idl_schema.py |
19 # and json_schema.py. | 20 # and json_schema.py. |
20 | 21 |
21 # idl_parser expects to be able to import certain files in its directory, | 22 # idl_parser expects to be able to import certain files in its directory, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 first_parameter_location = (parameter_starts[0].start() | 64 first_parameter_location = (parameter_starts[0].start() |
64 if parameter_starts else len(comment)) | 65 if parameter_starts else len(comment)) |
65 parent_comment = comment[:first_parameter_location] | 66 parent_comment = comment[:first_parameter_location] |
66 | 67 |
67 # We replace \n\n with <br/><br/> here and below, because the documentation | 68 # We replace \n\n with <br/><br/> here and below, because the documentation |
68 # needs to know where the newlines should be, and this is easier than | 69 # needs to know where the newlines should be, and this is easier than |
69 # escaping \n. | 70 # escaping \n. |
70 parent_comment = (parent_comment.strip().replace('\n\n', '<br/><br/>') | 71 parent_comment = (parent_comment.strip().replace('\n\n', '<br/><br/>') |
71 .replace('\n', '')) | 72 .replace('\n', '')) |
72 | 73 |
73 params = {} | 74 params = OrderedDict() |
74 for (cur_param, next_param) in itertools.izip_longest(parameter_starts, | 75 for (cur_param, next_param) in itertools.izip_longest(parameter_starts, |
75 parameter_starts[1:]): | 76 parameter_starts[1:]): |
76 param_name = cur_param.group(1) | 77 param_name = cur_param.group(1) |
77 | 78 |
78 # A parameter's comment goes from the end of its introduction to the | 79 # A parameter's comment goes from the end of its introduction to the |
79 # beginning of the next parameter's introduction. | 80 # beginning of the next parameter's introduction. |
80 param_comment_start = cur_param.end() | 81 param_comment_start = cur_param.end() |
81 param_comment_end = next_param.start() if next_param else len(comment) | 82 param_comment_end = next_param.start() if next_param else len(comment) |
82 params[param_name] = (comment[param_comment_start:param_comment_end | 83 params[param_name] = (comment[param_comment_start:param_comment_end |
83 ].strip().replace('\n\n', '<br/><br/>') | 84 ].strip().replace('\n\n', '<br/><br/>') |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 | 118 |
118 class Dictionary(object): | 119 class Dictionary(object): |
119 ''' | 120 ''' |
120 Given an IDL Dictionary node, converts into a Python dictionary that the JSON | 121 Given an IDL Dictionary node, converts into a Python dictionary that the JSON |
121 schema compiler expects to see. | 122 schema compiler expects to see. |
122 ''' | 123 ''' |
123 def __init__(self, dictionary_node): | 124 def __init__(self, dictionary_node): |
124 self.node = dictionary_node | 125 self.node = dictionary_node |
125 | 126 |
126 def process(self, callbacks): | 127 def process(self, callbacks): |
127 properties = {} | 128 properties = OrderedDict() |
128 for node in self.node.children: | 129 for node in self.node.children: |
129 if node.cls == 'Member': | 130 if node.cls == 'Member': |
130 k, v = Member(node).process(callbacks) | 131 k, v = Member(node).process(callbacks) |
131 properties[k] = v | 132 properties[k] = v |
132 result = {'id': self.node.GetName(), | 133 result = {'id': self.node.GetName(), |
133 'properties': properties, | 134 'properties': properties, |
134 'type': 'object'} | 135 'type': 'object'} |
135 if self.node.GetProperty('inline_doc'): | 136 if self.node.GetProperty('inline_doc'): |
136 result['inline_doc'] = True | 137 result['inline_doc'] = True |
137 return result | 138 return result |
138 | 139 |
139 | 140 |
140 class Member(object): | 141 class Member(object): |
141 ''' | 142 ''' |
142 Given an IDL dictionary or interface member, converts into a name/value pair | 143 Given an IDL dictionary or interface member, converts into a name/value pair |
143 where the value is a Python dictionary that the JSON schema compiler expects | 144 where the value is a Python dictionary that the JSON schema compiler expects |
144 to see. | 145 to see. |
145 ''' | 146 ''' |
146 def __init__(self, member_node): | 147 def __init__(self, member_node): |
147 self.node = member_node | 148 self.node = member_node |
148 | 149 |
149 def process(self, callbacks): | 150 def process(self, callbacks): |
150 properties = {} | 151 properties = OrderedDict() |
151 name = self.node.GetName() | 152 name = self.node.GetName() |
152 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'): | 153 for property_name in ('OPTIONAL', 'nodoc', 'nocompile'): |
153 if self.node.GetProperty(property_name): | 154 if self.node.GetProperty(property_name): |
154 properties[property_name.lower()] = True | 155 properties[property_name.lower()] = True |
155 is_function = False | 156 is_function = False |
156 parameter_comments = {} | 157 parameter_comments = OrderedDict() |
157 for node in self.node.children: | 158 for node in self.node.children: |
158 if node.cls == 'Comment': | 159 if node.cls == 'Comment': |
159 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) | 160 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) |
160 properties['description'] = parent_comment | 161 properties['description'] = parent_comment |
161 elif node.cls == 'Callspec': | 162 elif node.cls == 'Callspec': |
162 is_function = True | 163 is_function = True |
163 name, parameters = Callspec(node, parameter_comments).process(callbacks) | 164 name, parameters = Callspec(node, parameter_comments).process(callbacks) |
164 properties['parameters'] = parameters | 165 properties['parameters'] = parameters |
165 properties['name'] = name | 166 properties['name'] = name |
166 if is_function: | 167 if is_function: |
167 properties['type'] = 'function' | 168 properties['type'] = 'function' |
168 else: | 169 else: |
169 properties = Typeref(self.node.GetProperty('TYPEREF'), | 170 properties = Typeref(self.node.GetProperty('TYPEREF'), |
170 self.node, properties).process(callbacks) | 171 self.node, properties).process(callbacks) |
171 enum_values = self.node.GetProperty('legalValues') | 172 enum_values = self.node.GetProperty('legalValues') |
172 if enum_values: | 173 if enum_values: |
173 if properties['type'] == 'integer': | 174 if properties['type'] == 'integer': |
174 enum_values = map(int, enum_values) | 175 enum_values = map(int, enum_values) |
175 elif properties['type'] == 'double': | 176 elif properties['type'] == 'double': |
176 enum_values = map(float, enum_values) | 177 enum_values = map(float, enum_values) |
177 properties['enum'] = enum_values | 178 properties['enum'] = enum_values |
178 return name, properties | 179 return name, properties |
179 | 180 |
180 class Typeref(object): | 181 class Typeref(object): |
181 ''' | 182 ''' |
182 Given a TYPEREF property representing the type of dictionary member or | 183 Given a TYPEREF property representing the type of dictionary member or |
183 function parameter, converts into a Python dictionary that the JSON schema | 184 function parameter, converts into a Python dictionary that the JSON schema |
184 compiler expects to see. | 185 compiler expects to see. |
185 ''' | 186 ''' |
186 def __init__(self, typeref, parent, additional_properties={}): | 187 def __init__(self, typeref, parent, additional_properties=OrderedDict()): |
187 self.typeref = typeref | 188 self.typeref = typeref |
188 self.parent = parent | 189 self.parent = parent |
189 self.additional_properties = additional_properties | 190 self.additional_properties = additional_properties |
190 | 191 |
191 def process(self, callbacks): | 192 def process(self, callbacks): |
192 properties = self.additional_properties | 193 properties = self.additional_properties |
193 result = properties | 194 result = properties |
194 | 195 |
195 if self.parent.GetProperty('OPTIONAL', False): | 196 if self.parent.GetProperty('OPTIONAL', False): |
196 properties['optional'] = True | 197 properties['optional'] = True |
197 | 198 |
198 # The IDL parser denotes array types by adding a child 'Array' node onto | 199 # The IDL parser denotes array types by adding a child 'Array' node onto |
199 # the Param node in the Callspec. | 200 # the Param node in the Callspec. |
200 for sibling in self.parent.GetChildren(): | 201 for sibling in self.parent.GetChildren(): |
201 if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName(): | 202 if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName(): |
202 properties['type'] = 'array' | 203 properties['type'] = 'array' |
203 properties['items'] = {} | 204 properties['items'] = OrderedDict() |
204 properties = properties['items'] | 205 properties = properties['items'] |
205 break | 206 break |
206 | 207 |
207 if self.typeref == 'DOMString': | 208 if self.typeref == 'DOMString': |
208 properties['type'] = 'string' | 209 properties['type'] = 'string' |
209 elif self.typeref == 'boolean': | 210 elif self.typeref == 'boolean': |
210 properties['type'] = 'boolean' | 211 properties['type'] = 'boolean' |
211 elif self.typeref == 'double': | 212 elif self.typeref == 'double': |
212 properties['type'] = 'number' | 213 properties['type'] = 'number' |
213 elif self.typeref == 'long': | 214 elif self.typeref == 'long': |
214 properties['type'] = 'integer' | 215 properties['type'] = 'integer' |
215 elif self.typeref == 'any': | 216 elif self.typeref == 'any': |
216 properties['type'] = 'any' | 217 properties['type'] = 'any' |
217 elif self.typeref == 'object': | 218 elif self.typeref == 'object': |
218 properties['type'] = 'object' | 219 properties['type'] = 'object' |
219 if 'additionalProperties' not in properties: | 220 if 'additionalProperties' not in properties: |
220 properties['additionalProperties'] = {} | 221 properties['additionalProperties'] = OrderedDict() |
221 properties['additionalProperties']['type'] = 'any' | 222 properties['additionalProperties']['type'] = 'any' |
222 instance_of = self.parent.GetProperty('instanceOf') | 223 instance_of = self.parent.GetProperty('instanceOf') |
223 if instance_of: | 224 if instance_of: |
224 properties['isInstanceOf'] = instance_of | 225 properties['isInstanceOf'] = instance_of |
225 elif self.typeref == 'ArrayBuffer': | 226 elif self.typeref == 'ArrayBuffer': |
226 properties['type'] = 'binary' | 227 properties['type'] = 'binary' |
227 properties['isInstanceOf'] = 'ArrayBuffer' | 228 properties['isInstanceOf'] = 'ArrayBuffer' |
228 elif self.typeref is None: | 229 elif self.typeref is None: |
229 properties['type'] = 'function' | 230 properties['type'] = 'function' |
230 else: | 231 else: |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 ''' | 277 ''' |
277 | 278 |
278 def __init__(self, namespace_node, nodoc=False, permissions=None, | 279 def __init__(self, namespace_node, nodoc=False, permissions=None, |
279 internal=False): | 280 internal=False): |
280 self.namespace = namespace_node | 281 self.namespace = namespace_node |
281 self.nodoc = nodoc | 282 self.nodoc = nodoc |
282 self.internal = internal | 283 self.internal = internal |
283 self.events = [] | 284 self.events = [] |
284 self.functions = [] | 285 self.functions = [] |
285 self.types = [] | 286 self.types = [] |
286 self.callbacks = {} | 287 self.callbacks = OrderedDict() |
287 self.permissions = permissions or [] | 288 self.permissions = permissions or [] |
288 | 289 |
289 def process(self): | 290 def process(self): |
290 for node in self.namespace.children: | 291 for node in self.namespace.children: |
291 if node.cls == 'Dictionary': | 292 if node.cls == 'Dictionary': |
292 self.types.append(Dictionary(node).process(self.callbacks)) | 293 self.types.append(Dictionary(node).process(self.callbacks)) |
293 elif node.cls == 'Callback': | 294 elif node.cls == 'Callback': |
294 k, v = Member(node).process(self.callbacks) | 295 k, v = Member(node).process(self.callbacks) |
295 self.callbacks[k] = v | 296 self.callbacks[k] = v |
296 elif node.cls == 'Interface' and node.GetName() == 'Functions': | 297 elif node.cls == 'Interface' and node.GetName() == 'Functions': |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 ''' | 373 ''' |
373 Dump a json serialization of parse result for the IDL files whose names | 374 Dump a json serialization of parse result for the IDL files whose names |
374 were passed in on the command line. | 375 were passed in on the command line. |
375 ''' | 376 ''' |
376 for filename in sys.argv[1:]: | 377 for filename in sys.argv[1:]: |
377 schema = Load(filename) | 378 schema = Load(filename) |
378 print json.dumps(schema, indent=2) | 379 print json.dumps(schema, indent=2) |
379 | 380 |
380 if __name__ == '__main__': | 381 if __name__ == '__main__': |
381 Main() | 382 Main() |
OLD | NEW |