summaryrefslogtreecommitdiffstats
path: root/tools/json_schema_compiler
diff options
context:
space:
mode:
authorkalman <kalman@chromium.org>2015-04-01 19:04:10 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-02 02:05:38 +0000
commitd94f954f5e1c32e7be85e2ba835a143fd388a0d8 (patch)
tree5d9c34720d21f1b40282213e9e8738e56cc43427 /tools/json_schema_compiler
parentd205eb31669df40e3564071c600adc377036bad4 (diff)
downloadchromium_src-d94f954f5e1c32e7be85e2ba835a143fd388a0d8.zip
chromium_src-d94f954f5e1c32e7be85e2ba835a143fd388a0d8.tar.gz
chromium_src-d94f954f5e1c32e7be85e2ba835a143fd388a0d8.tar.bz2
Support JSON Schema properties with values in the JSON Schema Compiler.
This brings the Extension IDL Schema feature set closer to the JSON Schema feature set. In particular, the MDNS API needs this functionality. Unfortunately the PPAPI IDL parser doesn't support WebIDL's "const" keyword, which would be the right way to do this. Instead we fake it (though, consistent with functions and events); to define a JSON Schema property, IDL Schemas declare a 'Properties' namespace populated with no-argument functions, annotating each function with the value they should be mapped to. For example, this IDL: namespace myApi { interface Properties { // A constant. [value=42] static long someConstant(); }; }; will generate this JSON Schema: { "namespace": "myApi", "properties": { "someConstant": { "value": "42", "description": "A constant", "type": "integer", } } } and finally, an integer myApi::some_constant equal to 42 in C++. R=rdevlin.cronin@chromium.org Review URL: https://codereview.chromium.org/1051563002 Cr-Commit-Position: refs/heads/master@{#323401}
Diffstat (limited to 'tools/json_schema_compiler')
-rw-r--r--tools/json_schema_compiler/cpp_type_generator.py12
-rwxr-xr-xtools/json_schema_compiler/idl_schema.py81
-rwxr-xr-xtools/json_schema_compiler/idl_schema_test.py24
-rw-r--r--tools/json_schema_compiler/test/idl_properties.idl20
4 files changed, 118 insertions, 19 deletions
diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
index 5a573b6..944dba9 100644
--- a/tools/json_schema_compiler/cpp_type_generator.py
+++ b/tools/json_schema_compiler/cpp_type_generator.py
@@ -252,11 +252,15 @@ class CppTypeGenerator(object):
c.Comment(prop.description)
if prop.value is not None:
+ cpp_type = self.GetCppType(prop.type_)
+ cpp_value = prop.value
+ if cpp_type == 'std::string':
+ cpp_value = '"%s"' % cpp_type
c.Append(line % {
- "type": self.GetCppType(prop.type_),
- "name": prop.name,
- "value": prop.value
- })
+ "type": cpp_type,
+ "name": prop.name,
+ "value": cpp_value
+ })
else:
has_child_code = False
c.Sblock('namespace %s {' % prop.name)
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
index 7364800..65d7bae 100755
--- a/tools/json_schema_compiler/idl_schema.py
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -6,6 +6,7 @@
import itertools
import json
import os.path
+import pprint
import re
import sys
@@ -167,7 +168,7 @@ class Member(object):
def __init__(self, member_node):
self.node = member_node
- def process(self, callbacks):
+ def process(self, callbacks, functions_are_properties=False):
properties = OrderedDict()
name = self.node.GetName()
if self.node.GetProperty('deprecated'):
@@ -187,34 +188,69 @@ class Member(object):
properties['options'] = {}
properties['options'][option_name] = sanitizer(self.node.GetProperty(
option_name))
- is_function = False
+ type_override = None
parameter_comments = OrderedDict()
for node in self.node.GetChildren():
if node.cls == 'Comment':
(parent_comment, parameter_comments) = ProcessComment(node.GetName())
properties['description'] = parent_comment
elif node.cls == 'Callspec':
- is_function = True
name, parameters, return_type = (Callspec(node, parameter_comments)
.process(callbacks))
- properties['parameters'] = parameters
- if return_type is not None:
- properties['returns'] = return_type
+ if functions_are_properties:
+ # If functions are treated as properties (which will happen if the
+ # interface is named Properties) then this isn't a function, it's a
+ # property which is encoded as a function with no arguments. The
+ # property type is the return type. This is an egregious hack in lieu
+ # of the IDL parser supporting 'const'.
+ assert parameters == [], (
+ 'Property "%s" must be no-argument functions '
+ 'with a non-void return type' % name)
+ assert return_type is not None, (
+ 'Property "%s" must be no-argument functions '
+ 'with a non-void return type' % name)
+ assert 'type' in return_type, (
+ 'Property return type "%s" from "%s" must specify a '
+ 'fundamental IDL type.' % (pprint.pformat(return_type), name))
+ type_override = return_type['type']
+ else:
+ type_override = 'function'
+ properties['parameters'] = parameters
+ if return_type is not None:
+ properties['returns'] = return_type
properties['name'] = name
- if is_function:
- properties['type'] = 'function'
+ if type_override is not None:
+ properties['type'] = type_override
else:
properties = Typeref(self.node.GetProperty('TYPEREF'),
self.node, properties).process(callbacks)
+ value = self.node.GetProperty('value')
+ if value is not None:
+ # IDL always returns values as strings, so cast to their real type.
+ properties['value'] = self.cast_from_json_type(properties['type'], value)
enum_values = self.node.GetProperty('legalValues')
if enum_values:
- if properties['type'] == 'integer':
- enum_values = map(int, enum_values)
- elif properties['type'] == 'double':
- enum_values = map(float, enum_values)
- properties['enum'] = enum_values
+ # IDL always returns enum values as strings, so cast to their real type.
+ properties['enum'] = [self.cast_from_json_type(properties['type'], enum)
+ for enum in enum_values]
return name, properties
+ def cast_from_json_type(self, json_type, string_value):
+ '''Casts from string |string_value| to a real Python type based on a JSON
+ Schema type |json_type|. For example, a string value of '42' and a JSON
+ Schema type 'integer' will cast to int('42') ==> 42.
+ '''
+ if json_type == 'integer':
+ return int(string_value)
+ if json_type == 'number':
+ return float(string_value)
+ # Add more as necessary.
+ assert json_type == 'string', (
+ 'No rule exists to cast JSON Schema type "%s" to its equivalent '
+ 'Python type for value "%s". You must add a new rule here.' %
+ (json_type, string_value))
+ return string_value
+
class Typeref(object):
'''
@@ -352,6 +388,7 @@ class Namespace(object):
self.compiler_options = compiler_options
self.events = []
self.functions = []
+ self.properties = OrderedDict()
self.types = []
self.callbacks = OrderedDict()
self.description = description
@@ -369,6 +406,17 @@ class Namespace(object):
self.functions = self.process_interface(node)
elif node.cls == 'Interface' and node.GetName() == 'Events':
self.events = self.process_interface(node)
+ elif node.cls == 'Interface' and node.GetName() == 'Properties':
+ properties_as_list = self.process_interface(
+ node, functions_are_properties=True)
+ for prop in properties_as_list:
+ # Properties are given as key-value pairs, but IDL will parse
+ # it as a list. Convert back to key-value pairs.
+ prop_name = prop.pop('name')
+ assert not self.properties.has_key(prop_name), (
+ 'Property "%s" cannot be specified more than once.' %
+ prop_name)
+ self.properties[prop_name] = prop
elif node.cls == 'Enum':
self.types.append(Enum(node).process())
else:
@@ -380,6 +428,7 @@ class Namespace(object):
'nodoc': self.nodoc,
'types': self.types,
'functions': self.functions,
+ 'properties': self.properties,
'internal': self.internal,
'events': self.events,
'platforms': self.platforms,
@@ -387,11 +436,13 @@ class Namespace(object):
'deprecated': self.deprecated,
'documentation_options': documentation_options}
- def process_interface(self, node):
+ def process_interface(self, node, functions_are_properties=False):
members = []
for member in node.GetChildren():
if member.cls == 'Member':
- _, properties = Member(member).process(self.callbacks)
+ _, properties = Member(member).process(
+ self.callbacks,
+ functions_are_properties=functions_are_properties)
members.append(properties)
return members
diff --git a/tools/json_schema_compiler/idl_schema_test.py b/tools/json_schema_compiler/idl_schema_test.py
index a045716..03960c3 100755
--- a/tools/json_schema_compiler/idl_schema_test.py
+++ b/tools/json_schema_compiler/idl_schema_test.py
@@ -391,6 +391,30 @@ class IdlSchemaTest(unittest.TestCase):
self.assertEquals(expected, badabish_params)
+ def testProperties(self):
+ schema = idl_schema.Load('test/idl_properties.idl')[0]
+ self.assertEquals(OrderedDict([
+ ('first', OrderedDict([
+ ('description', 'Integer property.'),
+ ('type', 'integer'),
+ ('value', 42),
+ ])),
+ ('second', OrderedDict([
+ ('description', 'Double property.'),
+ ('type', 'number'),
+ ('value', 42.0),
+ ])),
+ ('third', OrderedDict([
+ ('description', 'String property.'),
+ ('type', 'string'),
+ ('value', 'hello world'),
+ ])),
+ ('fourth', OrderedDict([
+ ('description', 'Unvalued property.'),
+ ('type', 'integer'),
+ ])),
+ ]), schema.get('properties'))
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/json_schema_compiler/test/idl_properties.idl b/tools/json_schema_compiler/test/idl_properties.idl
new file mode 100644
index 0000000..5501602
--- /dev/null
+++ b/tools/json_schema_compiler/test/idl_properties.idl
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests parsing the Properties interface.
+namespace idl_properties {
+ interface Properties {
+ // Integer property.
+ [value=42] static long first();
+
+ // Double property.
+ [value=42.0] static double second();
+
+ // String property.
+ [value="hello world"] static DOMString third();
+
+ // Unvalued property.
+ static long fourth();
+ };
+};