summaryrefslogtreecommitdiffstats
path: root/tools/json_schema_compiler/idl_schema.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/json_schema_compiler/idl_schema.py')
-rw-r--r--tools/json_schema_compiler/idl_schema.py211
1 files changed, 211 insertions, 0 deletions
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()