summaryrefslogtreecommitdiffstats
path: root/tools/json_schema_compiler
diff options
context:
space:
mode:
authormiket@chromium.org <miket@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-07 02:33:35 +0000
committermiket@chromium.org <miket@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-07 02:33:35 +0000
commit750b83600136c3b9bfaf33bb60ec61c41010a150 (patch)
treeaead05297ea1f7ba6840c414917be091a5970dfb /tools/json_schema_compiler
parent8a59a087de2604becfc5fb4fb691b45c37ca8795 (diff)
downloadchromium_src-750b83600136c3b9bfaf33bb60ec61c41010a150.zip
chromium_src-750b83600136c3b9bfaf33bb60ec61c41010a150.tar.gz
chromium_src-750b83600136c3b9bfaf33bb60ec61c41010a150.tar.bz2
- Extend compiler.py to recognize .idl files.
- Extend .gyp to pass certain .idl files to compiler.py. - Implement a translator taking IDL parser output and creating a schema that the JSON compiler recognizes. - Convert one API to IDL using asargent's JSON cat JSON-to-IDL converter, and adapt API's implementation to use the newly generated output. TEST=no changes BUG=none Review URL: http://codereview.chromium.org/9600050 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125300 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/json_schema_compiler')
-rw-r--r--tools/json_schema_compiler/compiler.py16
-rw-r--r--tools/json_schema_compiler/idl_schema.py211
-rw-r--r--tools/json_schema_compiler/json_schema.py2
-rw-r--r--tools/json_schema_compiler/model.py3
4 files changed, 225 insertions, 7 deletions
diff --git a/tools/json_schema_compiler/compiler.py b/tools/json_schema_compiler/compiler.py
index fb84a6c..f782f72 100644
--- a/tools/json_schema_compiler/compiler.py
+++ b/tools/json_schema_compiler/compiler.py
@@ -19,7 +19,8 @@ Usage example:
import cc_generator
import cpp_type_generator
import h_generator
-from json_schema import LoadJSON
+import idl_schema
+import json_schema
import model
import optparse
import os.path
@@ -47,17 +48,24 @@ if __name__ == '__main__':
api_model = model.Model()
-
# Actually generate for source file.
- api_defs = LoadJSON(schema)
+ schema_filename, schema_extension = os.path.splitext(schema)
+ if schema_extension == '.json':
+ api_defs = json_schema.Load(schema)
+ elif schema_extension == '.idl':
+ api_defs = idl_schema.Load(schema)
+ else:
+ sys.exit("Did not recognize file extension %s for schema %s" %
+ (schema_extension, schema))
for target_namespace in api_defs:
referenced_schemas = target_namespace.get('dependencies', [])
# Load type dependencies into the model.
+ # TODO(miket): do we need this in IDL?
for referenced_schema in referenced_schemas:
referenced_schema_path = os.path.join(
os.path.dirname(schema), referenced_schema + '.json')
- referenced_api_defs = LoadJSON(referenced_schema_path)
+ referenced_api_defs = json_schema.Load(referenced_schema_path)
for namespace in referenced_api_defs:
api_model.AddNamespace(namespace,
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
new file mode 100644
index 0000000..d64f111
--- /dev/null
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -0,0 +1,211 @@
+# Copyright (c) 2012 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.
+
+import os.path
+import sys
+
+# This file is a peer to json_schema.py. Each of these files understands a
+# certain format describing APIs (either JSON or IDL), reads files written
+# in that format into memory, and emits them as a Python array of objects
+# corresponding to those APIs, where the objects are formatted in a way that
+# the JSON schema compiler understands. compiler.py drives both idl_schema.py
+# and json_schema.py.
+
+# idl_parser expects to be able to import certain files in its directory,
+# so let's set things up the way it wants.
+idl_generators_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ os.pardir, os.pardir, 'ppapi', 'generators')
+if idl_generators_path not in sys.path:
+ sys.path.insert(0, idl_generators_path)
+import idl_parser
+
+class Callspec(object):
+ '''
+ Given a Callspec node representing an IDL function declaration, converts into
+ a name/value pair where the value is a list of function parameters.
+ '''
+ def __init__(self, callspec_node):
+ self.node = callspec_node
+
+ def process(self, refs):
+ parameters = []
+ for node in self.node.children:
+ parameters.append(Param(node).process(refs))
+ return self.node.GetName(), parameters
+
+class Param(object):
+ '''
+ Given a Param node representing a function parameter, converts into a Python
+ dictionary that the JSON schema compiler expects to see.
+ '''
+ def __init__(self, param_node):
+ self.node = param_node
+
+ def process(self, refs):
+ return Typeref(self.node.GetProperty( 'TYPEREF'),
+ self.node,
+ { 'name': self.node.GetName() }).process(refs)
+
+class Dictionary(object):
+ '''
+ Given an IDL Dictionary node, converts into a Python dictionary that the JSON
+ schema compiler expects to see.
+ '''
+ def __init__(self, dictionary_node):
+ self.node = dictionary_node
+
+ def process(self, refs):
+ properties = {}
+ for node in self.node.children:
+ if node.cls == 'Member':
+ k, v = Member(node).process(refs)
+ properties[k] = v
+ return { 'id': self.node.GetName(),
+ 'properties': properties,
+ 'type': 'object' }
+
+class Member(object):
+ '''
+ Given an IDL dictionary or interface member, converts into a name/value pair
+ where the value is a Python dictionary that the JSON schema compiler expects
+ to see.
+ '''
+ def __init__(self, member_node):
+ self.node = member_node
+
+ def process(self, refs):
+ properties = {}
+ name = self.node.GetName()
+ if self.node.GetProperty('OPTIONAL'):
+ properties['optional'] = True
+ if self.node.GetProperty('nodoc'):
+ properties['nodoc'] = True
+ is_function = False
+ for node in self.node.children:
+ if node.cls == 'Callspec':
+ is_function = True
+ name, parameters = Callspec(node).process(refs)
+ properties['parameters'] = parameters
+ properties['name'] = name
+ if is_function:
+ properties['type'] = 'function'
+ else:
+ properties = Typeref(self.node.GetProperty('TYPEREF'),
+ self.node, properties).process(refs)
+ return name, properties
+
+class Typeref(object):
+ '''
+ Given a TYPEREF property representing the type of dictionary member or
+ function parameter, converts into a Python dictionary that the JSON schema
+ compiler expects to see.
+ '''
+ def __init__(self, typeref, parent, additional_properties={}):
+ self.typeref = typeref
+ self.parent = parent
+ self.additional_properties = additional_properties
+
+ def process(self, refs):
+ properties = self.additional_properties
+ if self.typeref == 'DOMString':
+ properties['type'] = 'string'
+ elif self.typeref == 'boolean':
+ properties['type'] = 'boolean'
+ elif self.typeref == 'long':
+ properties['type'] = 'integer'
+ elif self.typeref is None:
+ properties['type'] = 'function'
+ else:
+ try:
+ properties = refs[self.typeref]
+ except KeyError, e:
+ properties['$ref'] = self.typeref
+ return properties
+
+class Namespace(object):
+ '''
+ Given an IDLNode representing an IDL namespace, converts into a Python
+ dictionary that the JSON schema compiler expects to see.
+ '''
+
+ def __init__(self, namespace_node, nodoc=False):
+ self.namespace = namespace_node
+ self.nodoc = nodoc
+ self.events = []
+ self.functions = []
+ self.types = []
+ self.refs = {}
+
+ def process(self):
+ for node in self.namespace.children:
+ cls = node.cls
+ if cls == "Dictionary":
+ self.types.append(Dictionary(node).process(self.refs))
+ elif cls == "Callback":
+ k, v = Member(node).process(self.refs)
+ self.refs[k] = v
+ elif cls == "Interface" and node.GetName() == "Functions":
+ self.functions = self.process_interface(node)
+ elif cls == "Interface" and node.GetName() == "Events":
+ self.events = self.process_interface(node)
+ else:
+ sys.exit("Did not process %s %s" % (node.cls, node))
+
+ return { 'events': self.events,
+ 'functions': self.functions,
+ 'types': self.types,
+ 'namespace': self.namespace.GetName(),
+ 'nodoc': self.nodoc }
+
+ def process_interface(self, node):
+ members = []
+ for member in node.children:
+ if member.cls == 'Member':
+ name, properties = Member(member).process(self.refs)
+ members.append(properties)
+ return members
+
+class IDLSchema(object):
+ '''
+ Given a list of IDLNodes and IDLAttributes, converts into a Python list
+ of api_defs that the JSON schema compiler expects to see.
+ '''
+
+ def __init__(self, idl):
+ self.idl = idl
+
+ def process(self):
+ namespaces = []
+ for node in self.idl:
+ nodoc = False
+ cls = node.cls
+ if cls == 'Namespace':
+ namespace = Namespace(node, nodoc)
+ namespaces.append(namespace.process())
+ elif cls == 'Copyright':
+ continue
+ elif cls == 'Comment':
+ continue
+ elif cls == 'ExtAttribute':
+ if node.name == 'nodoc':
+ nodoc = bool(node.value)
+ else:
+ continue
+ else:
+ sys.exit("Did not process %s %s" % (node.cls, node))
+ return namespaces
+
+def Load(filename):
+ '''
+ Given the filename of an IDL file, parses it and returns an equivalent
+ Python dictionary in a format that the JSON schema compiler expects to see.
+ '''
+
+ f = open(filename, 'r')
+ contents = f.read()
+ f.close()
+
+ idl = idl_parser.IDLParser().ParseData(contents, filename)
+ idl_schema = IDLSchema(idl)
+ return idl_schema.process()
diff --git a/tools/json_schema_compiler/json_schema.py b/tools/json_schema_compiler/json_schema.py
index aa192c0..779ec87 100644
--- a/tools/json_schema_compiler/json_schema.py
+++ b/tools/json_schema_compiler/json_schema.py
@@ -14,6 +14,6 @@ if third_party_path not in sys.path:
sys.path.insert(0, third_party_path)
import json_minify as minify
-def LoadJSON(filename):
+def Load(filename):
with open(filename, 'r') as handle:
return json.loads(minify.json_minify(handle.read()))
diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py
index de392d2..cb569c6 100644
--- a/tools/json_schema_compiler/model.py
+++ b/tools/json_schema_compiler/model.py
@@ -90,7 +90,7 @@ class Type(object):
props = []
for prop_name, prop_json in json.get('properties', {}).items():
# TODO(calamity): support functions (callbacks) as properties. The model
- # doesn't support it yet because to h/cc generators don't -- this is
+ # doesn't support it yet because the h/cc generators don't -- this is
# because we'd need to hook it into a base::Callback or something.
#
# However, pragmatically it's not necessary to support them anyway, since
@@ -328,4 +328,3 @@ def GetModelHierarchy(entity):
entity = entity.parent
hierarchy.reverse()
return hierarchy
-