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