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

Unified Diff: tools/json_schema_compiler/idl_schema.py

Issue 682493002: Remove the dependency on json schema compiler. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: tools/json_schema_compiler/idl_schema.py
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
deleted file mode 100755
index a9137569cc348f0583110e279e9a523b016c7543..0000000000000000000000000000000000000000
--- a/tools/json_schema_compiler/idl_schema.py
+++ /dev/null
@@ -1,488 +0,0 @@
-#! /usr/bin/env python
-# 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 itertools
-import json
-import os.path
-import re
-import sys
-
-from json_parse import OrderedDict
-
-# 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 in sys.path:
- import idl_parser
-else:
- sys.path.insert(0, _idl_generators_path)
- try:
- import idl_parser
- finally:
- sys.path.pop(0)
-
-def ProcessComment(comment):
- '''
- Convert a comment into a parent comment and a list of parameter comments.
-
- Function comments are of the form:
- Function documentation. May contain HTML and multiple lines.
-
- |arg1_name|: Description of arg1. Use <var>argument</var> to refer
- to other arguments.
- |arg2_name|: Description of arg2...
-
- Newlines are removed, and leading and trailing whitespace is stripped.
-
- Args:
- comment: The string from a Comment node.
-
- Returns: A tuple that looks like:
- (
- "The processed comment, minus all |parameter| mentions.",
- {
- 'parameter_name_1': "The comment that followed |parameter_name_1|:",
- ...
- }
- )
- '''
- def add_paragraphs(content):
- paragraphs = content.split('\n\n')
- if len(paragraphs) < 2:
- return content
- return '<p>' + '</p><p>'.join(p.strip() for p in paragraphs) + '</p>'
-
- # Find all the parameter comments of the form '|name|: comment'.
- parameter_starts = list(re.finditer(r' *\|([^|]*)\| *: *', comment))
-
- # Get the parent comment (everything before the first parameter comment.
- first_parameter_location = (parameter_starts[0].start()
- if parameter_starts else len(comment))
- parent_comment = (add_paragraphs(comment[:first_parameter_location].strip())
- .replace('\n', ''))
-
- params = OrderedDict()
- for (cur_param, next_param) in itertools.izip_longest(parameter_starts,
- parameter_starts[1:]):
- param_name = cur_param.group(1)
-
- # A parameter's comment goes from the end of its introduction to the
- # beginning of the next parameter's introduction.
- param_comment_start = cur_param.end()
- param_comment_end = next_param.start() if next_param else len(comment)
- params[param_name] = (
- add_paragraphs(comment[param_comment_start:param_comment_end].strip())
- .replace('\n', ''))
-
- return (parent_comment, params)
-
-
-class Callspec(object):
- '''
- Given a Callspec node representing an IDL function declaration, converts into
- a tuple:
- (name, list of function parameters, return type)
- '''
- def __init__(self, callspec_node, comment):
- self.node = callspec_node
- self.comment = comment
-
- def process(self, callbacks):
- parameters = []
- return_type = None
- if self.node.GetProperty('TYPEREF') not in ('void', None):
- return_type = Typeref(self.node.GetProperty('TYPEREF'),
- self.node.parent,
- {'name': self.node.GetName()}).process(callbacks)
- # The IDL parser doesn't allow specifying return types as optional.
- # Instead we infer any object return values to be optional.
- # TODO(asargent): fix the IDL parser to support optional return types.
- if return_type.get('type') == 'object' or '$ref' in return_type:
- return_type['optional'] = True
- for node in self.node.GetChildren():
- parameter = Param(node).process(callbacks)
- if parameter['name'] in self.comment:
- parameter['description'] = self.comment[parameter['name']]
- parameters.append(parameter)
- return (self.node.GetName(), parameters, return_type)
-
-
-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, callbacks):
- return Typeref(self.node.GetProperty('TYPEREF'),
- self.node,
- {'name': self.node.GetName()}).process(callbacks)
-
-
-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, callbacks):
- properties = OrderedDict()
- for node in self.node.GetChildren():
- if node.cls == 'Member':
- k, v = Member(node).process(callbacks)
- properties[k] = v
- result = {'id': self.node.GetName(),
- 'properties': properties,
- 'type': 'object'}
- if self.node.GetProperty('nodoc'):
- result['nodoc'] = True
- elif self.node.GetProperty('inline_doc'):
- result['inline_doc'] = True
- elif self.node.GetProperty('noinline_doc'):
- result['noinline_doc'] = True
- return result
-
-
-
-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, callbacks):
- properties = OrderedDict()
- name = self.node.GetName()
- if self.node.GetProperty('deprecated'):
- properties['deprecated'] = self.node.GetProperty('deprecated')
- if self.node.GetProperty('allowAmbiguousOptionalArguments'):
- properties['allowAmbiguousOptionalArguments'] = True
- for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'nodart'):
- if self.node.GetProperty(property_name):
- properties[property_name.lower()] = True
- for option_name, sanitizer in [
- ('maxListeners', int),
- ('supportsFilters', lambda s: s == 'true'),
- ('supportsListeners', lambda s: s == 'true'),
- ('supportsRules', lambda s: s == 'true')]:
- if self.node.GetProperty(option_name):
- if 'options' not in properties:
- properties['options'] = {}
- properties['options'][option_name] = sanitizer(self.node.GetProperty(
- option_name))
- is_function = False
- 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
- properties['name'] = name
- if is_function:
- properties['type'] = 'function'
- else:
- properties = Typeref(self.node.GetProperty('TYPEREF'),
- self.node, properties).process(callbacks)
- 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
- 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, callbacks):
- properties = self.additional_properties
- result = properties
-
- if self.parent.GetPropertyLocal('OPTIONAL'):
- properties['optional'] = True
-
- # The IDL parser denotes array types by adding a child 'Array' node onto
- # the Param node in the Callspec.
- for sibling in self.parent.GetChildren():
- if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName():
- properties['type'] = 'array'
- properties['items'] = OrderedDict()
- properties = properties['items']
- break
-
- if self.typeref == 'DOMString':
- properties['type'] = 'string'
- elif self.typeref == 'boolean':
- properties['type'] = 'boolean'
- elif self.typeref == 'double':
- properties['type'] = 'number'
- elif self.typeref == 'long':
- properties['type'] = 'integer'
- elif self.typeref == 'any':
- properties['type'] = 'any'
- elif self.typeref == 'object':
- properties['type'] = 'object'
- if 'additionalProperties' not in properties:
- properties['additionalProperties'] = OrderedDict()
- properties['additionalProperties']['type'] = 'any'
- instance_of = self.parent.GetProperty('instanceOf')
- if instance_of:
- properties['isInstanceOf'] = instance_of
- elif self.typeref == 'ArrayBuffer':
- properties['type'] = 'binary'
- properties['isInstanceOf'] = 'ArrayBuffer'
- elif self.typeref == 'FileEntry':
- properties['type'] = 'object'
- properties['isInstanceOf'] = 'FileEntry'
- if 'additionalProperties' not in properties:
- properties['additionalProperties'] = OrderedDict()
- properties['additionalProperties']['type'] = 'any'
- elif self.parent.GetPropertyLocal('Union'):
- choices = []
- properties['choices'] = [Typeref(node.GetProperty('TYPEREF'),
- node,
- OrderedDict()).process(callbacks)
- for node in self.parent.GetChildren()
- if node.cls == 'Option']
- elif self.typeref is None:
- properties['type'] = 'function'
- else:
- if self.typeref in callbacks:
- # Do not override name and description if they are already specified.
- name = properties.get('name', None)
- description = properties.get('description', None)
- properties.update(callbacks[self.typeref])
- if description is not None:
- properties['description'] = description
- if name is not None:
- properties['name'] = name
- else:
- properties['$ref'] = self.typeref
- return result
-
-
-class Enum(object):
- '''
- Given an IDL Enum node, converts into a Python dictionary that the JSON
- schema compiler expects to see.
- '''
- def __init__(self, enum_node):
- self.node = enum_node
- self.description = ''
-
- def process(self, callbacks):
- enum = []
- for node in self.node.GetChildren():
- if node.cls == 'EnumItem':
- enum_value = {'name': node.GetName()}
- for child in node.GetChildren():
- if child.cls == 'Comment':
- enum_value['description'] = ProcessComment(child.GetName())[0]
- else:
- raise ValueError('Did not process %s %s' % (child.cls, child))
- enum.append(enum_value)
- elif node.cls == 'Comment':
- self.description = ProcessComment(node.GetName())[0]
- else:
- sys.exit('Did not process %s %s' % (node.cls, node))
- result = {'id' : self.node.GetName(),
- 'description': self.description,
- 'type': 'string',
- 'enum': enum}
- for property_name in (
- 'inline_doc', 'noinline_doc', 'nodoc', 'cpp_enum_prefix_override',):
- if self.node.GetProperty(property_name):
- result[property_name] = self.node.GetProperty(property_name)
- if self.node.GetProperty('deprecated'):
- result[deprecated] = self.node.GetProperty('deprecated')
- return result
-
-
-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,
- description,
- nodoc=False,
- internal=False,
- platforms=None,
- compiler_options=None,
- deprecated=None):
- self.namespace = namespace_node
- self.nodoc = nodoc
- self.internal = internal
- self.platforms = platforms
- self.compiler_options = compiler_options
- self.events = []
- self.functions = []
- self.types = []
- self.callbacks = OrderedDict()
- self.description = description
- self.deprecated = deprecated
-
- def process(self):
- for node in self.namespace.GetChildren():
- if node.cls == 'Dictionary':
- self.types.append(Dictionary(node).process(self.callbacks))
- elif node.cls == 'Callback':
- k, v = Member(node).process(self.callbacks)
- self.callbacks[k] = v
- elif node.cls == 'Interface' and node.GetName() == 'Functions':
- self.functions = self.process_interface(node)
- elif node.cls == 'Interface' and node.GetName() == 'Events':
- self.events = self.process_interface(node)
- elif node.cls == 'Enum':
- self.types.append(Enum(node).process(self.callbacks))
- else:
- sys.exit('Did not process %s %s' % (node.cls, node))
- if self.compiler_options is not None:
- compiler_options = self.compiler_options
- else:
- compiler_options = {}
- return {'namespace': self.namespace.GetName(),
- 'description': self.description,
- 'nodoc': self.nodoc,
- 'types': self.types,
- 'functions': self.functions,
- 'internal': self.internal,
- 'events': self.events,
- 'platforms': self.platforms,
- 'compiler_options': compiler_options,
- 'deprecated': self.deprecated}
-
- def process_interface(self, node):
- members = []
- for member in node.GetChildren():
- if member.cls == 'Member':
- name, properties = Member(member).process(self.callbacks)
- 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 = []
- nodoc = False
- internal = False
- description = None
- platforms = None
- compiler_options = {}
- deprecated = None
- for node in self.idl:
- if node.cls == 'Namespace':
- if not description:
- # TODO(kalman): Go back to throwing an error here.
- print('%s must have a namespace-level comment. This will '
- 'appear on the API summary page.' % node.GetName())
- description = ''
- namespace = Namespace(node, description, nodoc, internal,
- platforms=platforms,
- compiler_options=compiler_options or None,
- deprecated=deprecated)
- namespaces.append(namespace.process())
- nodoc = False
- internal = False
- platforms = None
- compiler_options = None
- elif node.cls == 'Copyright':
- continue
- elif node.cls == 'Comment':
- description = node.GetName()
- elif node.cls == 'ExtAttribute':
- if node.name == 'nodoc':
- nodoc = bool(node.value)
- elif node.name == 'internal':
- internal = bool(node.value)
- elif node.name == 'platforms':
- platforms = list(node.value)
- elif node.name == 'implemented_in':
- compiler_options['implemented_in'] = node.value
- elif node.name == 'camel_case_enum_to_string':
- compiler_options['camel_case_enum_to_string'] = node.value
- elif node.name == 'deprecated':
- deprecated = str(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()
-
-
-def Main():
- '''
- Dump a json serialization of parse result for the IDL files whose names
- were passed in on the command line.
- '''
- if len(sys.argv) > 1:
- for filename in sys.argv[1:]:
- schema = Load(filename)
- print json.dumps(schema, indent=2)
- else:
- contents = sys.stdin.read()
- idl = idl_parser.IDLParser().ParseData(contents, '<stdin>')
- schema = IDLSchema(idl).process()
- print json.dumps(schema, indent=2)
-
-
-if __name__ == '__main__':
- Main()
« no previous file with comments | « tools/json_schema_compiler/highlighters/pygments_highlighter.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