diff options
Diffstat (limited to 'tools/json_schema_compiler/idl_schema.py')
-rw-r--r-- | tools/json_schema_compiler/idl_schema.py | 211 |
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() |