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

Side by Side Diff: tools/json_schema_compiler/idl_schema.py

Issue 1051563002: Support JSON Schema properties with values in the JSON Schema Compiler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: assertr Created 5 years, 8 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
OLDNEW
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 pprint
9 import re 10 import re
10 import sys 11 import sys
11 12
12 from json_parse import OrderedDict 13 from json_parse import OrderedDict
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
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 161
161 class Member(object): 162 class Member(object):
162 ''' 163 '''
163 Given an IDL dictionary or interface member, converts into a name/value pair 164 Given an IDL dictionary or interface member, converts into a name/value pair
164 where the value is a Python dictionary that the JSON schema compiler expects 165 where the value is a Python dictionary that the JSON schema compiler expects
165 to see. 166 to see.
166 ''' 167 '''
167 def __init__(self, member_node): 168 def __init__(self, member_node):
168 self.node = member_node 169 self.node = member_node
169 170
170 def process(self, callbacks): 171 def process(self, callbacks, functions_are_properties=False):
171 properties = OrderedDict() 172 properties = OrderedDict()
172 name = self.node.GetName() 173 name = self.node.GetName()
173 if self.node.GetProperty('deprecated'): 174 if self.node.GetProperty('deprecated'):
174 properties['deprecated'] = self.node.GetProperty('deprecated') 175 properties['deprecated'] = self.node.GetProperty('deprecated')
175 if self.node.GetProperty('allowAmbiguousOptionalArguments'): 176 if self.node.GetProperty('allowAmbiguousOptionalArguments'):
176 properties['allowAmbiguousOptionalArguments'] = True 177 properties['allowAmbiguousOptionalArguments'] = True
177 for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'nodart'): 178 for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'nodart'):
178 if self.node.GetProperty(property_name): 179 if self.node.GetProperty(property_name):
179 properties[property_name.lower()] = True 180 properties[property_name.lower()] = True
180 for option_name, sanitizer in [ 181 for option_name, sanitizer in [
181 ('maxListeners', int), 182 ('maxListeners', int),
182 ('supportsFilters', lambda s: s == 'true'), 183 ('supportsFilters', lambda s: s == 'true'),
183 ('supportsListeners', lambda s: s == 'true'), 184 ('supportsListeners', lambda s: s == 'true'),
184 ('supportsRules', lambda s: s == 'true')]: 185 ('supportsRules', lambda s: s == 'true')]:
185 if self.node.GetProperty(option_name): 186 if self.node.GetProperty(option_name):
186 if 'options' not in properties: 187 if 'options' not in properties:
187 properties['options'] = {} 188 properties['options'] = {}
188 properties['options'][option_name] = sanitizer(self.node.GetProperty( 189 properties['options'][option_name] = sanitizer(self.node.GetProperty(
189 option_name)) 190 option_name))
190 is_function = False 191 type_override = None
191 parameter_comments = OrderedDict() 192 parameter_comments = OrderedDict()
192 for node in self.node.GetChildren(): 193 for node in self.node.GetChildren():
193 if node.cls == 'Comment': 194 if node.cls == 'Comment':
194 (parent_comment, parameter_comments) = ProcessComment(node.GetName()) 195 (parent_comment, parameter_comments) = ProcessComment(node.GetName())
195 properties['description'] = parent_comment 196 properties['description'] = parent_comment
196 elif node.cls == 'Callspec': 197 elif node.cls == 'Callspec':
197 is_function = True
198 name, parameters, return_type = (Callspec(node, parameter_comments) 198 name, parameters, return_type = (Callspec(node, parameter_comments)
199 .process(callbacks)) 199 .process(callbacks))
200 properties['parameters'] = parameters 200 if functions_are_properties:
201 if return_type is not None: 201 # If functions are treated as properties (which will happen if the
202 properties['returns'] = return_type 202 # interface is named Properties) then this isn't a function, it's a
203 # property which is encoded as a function with no arguments. The
204 # property type is the return type. This is an egregious hack in lieu
205 # of the IDL parser supporting 'const'.
206 assert parameters == [], (
207 'Property "%s" must be no-argument functions '
208 'with a non-void return type' % name)
209 assert return_type is not None, (
210 'Property "%s" must be no-argument functions '
211 'with a non-void return type' % name)
212 assert 'type' in return_type, (
213 'Property return type "%s" from "%s" must specify a '
214 'fundamental IDL type.' % (pprint.pformat(return_type), name))
215 type_override = return_type['type']
216 else:
217 type_override = 'function'
218 properties['parameters'] = parameters
219 if return_type is not None:
220 properties['returns'] = return_type
203 properties['name'] = name 221 properties['name'] = name
204 if is_function: 222 if type_override is not None:
205 properties['type'] = 'function' 223 properties['type'] = type_override
206 else: 224 else:
207 properties = Typeref(self.node.GetProperty('TYPEREF'), 225 properties = Typeref(self.node.GetProperty('TYPEREF'),
208 self.node, properties).process(callbacks) 226 self.node, properties).process(callbacks)
227 value = self.node.GetProperty('value')
228 if value is not None:
229 # IDL always returns values as strings, so cast to their real type.
230 properties['value'] = self.cast_from_json_type(properties['type'], value)
209 enum_values = self.node.GetProperty('legalValues') 231 enum_values = self.node.GetProperty('legalValues')
210 if enum_values: 232 if enum_values:
211 if properties['type'] == 'integer': 233 # IDL always returns enum values as strings, so cast to their real type.
212 enum_values = map(int, enum_values) 234 properties['enum'] = [self.cast_from_json_type(properties['type'], enum)
213 elif properties['type'] == 'double': 235 for enum in enum_values]
214 enum_values = map(float, enum_values)
215 properties['enum'] = enum_values
216 return name, properties 236 return name, properties
217 237
238 def cast_from_json_type(self, json_type, string_value):
239 '''Casts from string |string_value| to a real Python type based on a JSON
240 Schema type |json_type|. For example, a string value of '42' and a JSON
241 Schema type 'integer' will cast to int('42') ==> 42.
242 '''
243 if json_type == 'integer':
244 return int(string_value)
245 if json_type == 'number':
246 return float(string_value)
247 # Add more as necessary.
248 assert json_type == 'string', (
249 'No rule exists to cast JSON Schema type "%s" to its equivalent '
250 'Python type for value "%s". You must add a new rule here.' %
251 (json_type, string_value))
252 return string_value
253
218 254
219 class Typeref(object): 255 class Typeref(object):
220 ''' 256 '''
221 Given a TYPEREF property representing the type of dictionary member or 257 Given a TYPEREF property representing the type of dictionary member or
222 function parameter, converts into a Python dictionary that the JSON schema 258 function parameter, converts into a Python dictionary that the JSON schema
223 compiler expects to see. 259 compiler expects to see.
224 ''' 260 '''
225 def __init__(self, typeref, parent, additional_properties): 261 def __init__(self, typeref, parent, additional_properties):
226 self.typeref = typeref 262 self.typeref = typeref
227 self.parent = parent 263 self.parent = parent
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 compiler_options=None, 381 compiler_options=None,
346 deprecated=None, 382 deprecated=None,
347 documentation_options=None): 383 documentation_options=None):
348 self.namespace = namespace_node 384 self.namespace = namespace_node
349 self.nodoc = nodoc 385 self.nodoc = nodoc
350 self.internal = internal 386 self.internal = internal
351 self.platforms = platforms 387 self.platforms = platforms
352 self.compiler_options = compiler_options 388 self.compiler_options = compiler_options
353 self.events = [] 389 self.events = []
354 self.functions = [] 390 self.functions = []
391 self.properties = OrderedDict()
355 self.types = [] 392 self.types = []
356 self.callbacks = OrderedDict() 393 self.callbacks = OrderedDict()
357 self.description = description 394 self.description = description
358 self.deprecated = deprecated 395 self.deprecated = deprecated
359 self.documentation_options = documentation_options 396 self.documentation_options = documentation_options
360 397
361 def process(self): 398 def process(self):
362 for node in self.namespace.GetChildren(): 399 for node in self.namespace.GetChildren():
363 if node.cls == 'Dictionary': 400 if node.cls == 'Dictionary':
364 self.types.append(Dictionary(node).process(self.callbacks)) 401 self.types.append(Dictionary(node).process(self.callbacks))
365 elif node.cls == 'Callback': 402 elif node.cls == 'Callback':
366 k, v = Member(node).process(self.callbacks) 403 k, v = Member(node).process(self.callbacks)
367 self.callbacks[k] = v 404 self.callbacks[k] = v
368 elif node.cls == 'Interface' and node.GetName() == 'Functions': 405 elif node.cls == 'Interface' and node.GetName() == 'Functions':
369 self.functions = self.process_interface(node) 406 self.functions = self.process_interface(node)
370 elif node.cls == 'Interface' and node.GetName() == 'Events': 407 elif node.cls == 'Interface' and node.GetName() == 'Events':
371 self.events = self.process_interface(node) 408 self.events = self.process_interface(node)
409 elif node.cls == 'Interface' and node.GetName() == 'Properties':
410 properties_as_list = self.process_interface(
411 node, functions_are_properties=True)
412 for prop in properties_as_list:
413 # Properties are given as key-value pairs, but IDL will parse
414 # it as a list. Convert back to key-value pairs.
415 prop_name = prop.pop('name')
416 assert not self.properties.has_key(prop_name), (
417 'Property "%s" cannot be specified more than once.' %
418 prop_name)
419 self.properties[prop_name] = prop
372 elif node.cls == 'Enum': 420 elif node.cls == 'Enum':
373 self.types.append(Enum(node).process()) 421 self.types.append(Enum(node).process())
374 else: 422 else:
375 sys.exit('Did not process %s %s' % (node.cls, node)) 423 sys.exit('Did not process %s %s' % (node.cls, node))
376 compiler_options = self.compiler_options or {} 424 compiler_options = self.compiler_options or {}
377 documentation_options = self.documentation_options or {} 425 documentation_options = self.documentation_options or {}
378 return {'namespace': self.namespace.GetName(), 426 return {'namespace': self.namespace.GetName(),
379 'description': self.description, 427 'description': self.description,
380 'nodoc': self.nodoc, 428 'nodoc': self.nodoc,
381 'types': self.types, 429 'types': self.types,
382 'functions': self.functions, 430 'functions': self.functions,
431 'properties': self.properties,
383 'internal': self.internal, 432 'internal': self.internal,
384 'events': self.events, 433 'events': self.events,
385 'platforms': self.platforms, 434 'platforms': self.platforms,
386 'compiler_options': compiler_options, 435 'compiler_options': compiler_options,
387 'deprecated': self.deprecated, 436 'deprecated': self.deprecated,
388 'documentation_options': documentation_options} 437 'documentation_options': documentation_options}
389 438
390 def process_interface(self, node): 439 def process_interface(self, node, functions_are_properties=False):
391 members = [] 440 members = []
392 for member in node.GetChildren(): 441 for member in node.GetChildren():
393 if member.cls == 'Member': 442 if member.cls == 'Member':
394 _, properties = Member(member).process(self.callbacks) 443 _, properties = Member(member).process(
444 self.callbacks,
445 functions_are_properties=functions_are_properties)
395 members.append(properties) 446 members.append(properties)
396 return members 447 return members
397 448
398 449
399 class IDLSchema(object): 450 class IDLSchema(object):
400 ''' 451 '''
401 Given a list of IDLNodes and IDLAttributes, converts into a Python list 452 Given a list of IDLNodes and IDLAttributes, converts into a Python list
402 of api_defs that the JSON schema compiler expects to see. 453 of api_defs that the JSON schema compiler expects to see.
403 ''' 454 '''
404 455
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 print json.dumps(schema, indent=2) 548 print json.dumps(schema, indent=2)
498 else: 549 else:
499 contents = sys.stdin.read() 550 contents = sys.stdin.read()
500 idl = idl_parser.IDLParser().ParseData(contents, '<stdin>') 551 idl = idl_parser.IDLParser().ParseData(contents, '<stdin>')
501 schema = IDLSchema(idl).process() 552 schema = IDLSchema(idl).process()
502 print json.dumps(schema, indent=2) 553 print json.dumps(schema, indent=2)
503 554
504 555
505 if __name__ == '__main__': 556 if __name__ == '__main__':
506 Main() 557 Main()
OLDNEW
« no previous file with comments | « tools/json_schema_compiler/cpp_type_generator.py ('k') | tools/json_schema_compiler/idl_schema_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698