15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#! /usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import itertools
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os.path
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from json_parse import OrderedDict
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This file is a peer to json_schema.py. Each of these files understands a
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# certain format describing APIs (either JSON or IDL), reads files written
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in that format into memory, and emits them as a Python array of objects
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# corresponding to those APIs, where the objects are formatted in a way that
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the JSON schema compiler understands. compiler.py drives both idl_schema.py
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and json_schema.py.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# idl_parser expects to be able to import certain files in its directory,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# so let's set things up the way it wants.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_idl_generators_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    os.pardir, os.pardir, 'ppapi', 'generators')
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if _idl_generators_path in sys.path:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  import idl_parser
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.path.insert(0, _idl_generators_path)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    import idl_parser
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finally:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.path.pop(0)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ProcessComment(comment):
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Convert a comment into a parent comment and a list of parameter comments.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Function comments are of the form:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Function documentation. May contain HTML and multiple lines.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    |arg1_name|: Description of arg1. Use <var>argument</var> to refer
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to other arguments.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    |arg2_name|: Description of arg2...
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Newlines are removed, and leading and trailing whitespace is stripped.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    comment: The string from a Comment node.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns: A tuple that looks like:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "The processed comment, minus all |parameter| mentions.",
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'parameter_name_1': "The comment that followed |parameter_name_1|:",
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ...
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    )
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def add_paragraphs(content):
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    paragraphs = content.split('\n\n')
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if len(paragraphs) < 2:
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return content
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return '<p>' + '</p><p>'.join(p.strip() for p in paragraphs) + '</p>'
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Find all the parameter comments of the form '|name|: comment'.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parameter_starts = list(re.finditer(r' *\|([^|]*)\| *: *', comment))
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Get the parent comment (everything before the first parameter comment.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  first_parameter_location = (parameter_starts[0].start()
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              if parameter_starts else len(comment))
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parent_comment = (add_paragraphs(comment[:first_parameter_location].strip())
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    .replace('\n', ''))
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params = OrderedDict()
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (cur_param, next_param) in itertools.izip_longest(parameter_starts,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        parameter_starts[1:]):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    param_name = cur_param.group(1)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # A parameter's comment goes from the end of its introduction to the
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # beginning of the next parameter's introduction.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    param_comment_start = cur_param.end()
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    param_comment_end = next_param.start() if next_param else len(comment)
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    params[param_name] = (
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        add_paragraphs(comment[param_comment_start:param_comment_end].strip())
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        .replace('\n', ''))
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (parent_comment, params)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Callspec(object):
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given a Callspec node representing an IDL function declaration, converts into
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  a tuple:
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (name, list of function parameters, return type)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, callspec_node, comment):
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.node = callspec_node
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.comment = comment
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parameters = []
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return_type = None
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self.node.GetProperty('TYPEREF') not in ('void', None):
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return_type = Typeref(self.node.GetProperty('TYPEREF'),
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            self.node.parent,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            {'name': self.node.GetName()}).process(callbacks)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # The IDL parser doesn't allow specifying return types as optional.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Instead we infer any object return values to be optional.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # TODO(asargent): fix the IDL parser to support optional return types.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if return_type.get('type') == 'object' or '$ref' in return_type:
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return_type['optional'] = True
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for node in self.node.GetChildren():
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parameter = Param(node).process(callbacks)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if parameter['name'] in self.comment:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parameter['description'] = self.comment[parameter['name']]
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parameters.append(parameter)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (self.node.GetName(), parameters, return_type)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Param(object):
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given a Param node representing a function parameter, converts into a Python
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary that the JSON schema compiler expects to see.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, param_node):
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.node = param_node
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Typeref(self.node.GetProperty('TYPEREF'),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   self.node,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   {'name': self.node.GetName()}).process(callbacks)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Dictionary(object):
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given an IDL Dictionary node, converts into a Python dictionary that the JSON
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  schema compiler expects to see.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, dictionary_node):
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.node = dictionary_node
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    properties = OrderedDict()
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for node in self.node.GetChildren():
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.cls == 'Member':
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        k, v = Member(node).process(callbacks)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties[k] = v
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = {'id': self.node.GetName(),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'properties': properties,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'type': 'object'}
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if self.node.GetProperty('nodoc'):
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      result['nodoc'] = True
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    elif self.node.GetProperty('inline_doc'):
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result['inline_doc'] = True
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    elif self.node.GetProperty('noinline_doc'):
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      result['noinline_doc'] = True
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Member(object):
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given an IDL dictionary or interface member, converts into a name/value pair
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  where the value is a Python dictionary that the JSON schema compiler expects
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to see.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, member_node):
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.node = member_node
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    properties = OrderedDict()
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = self.node.GetName()
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.node.GetProperty('deprecated'):
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      properties['deprecated'] = self.node.GetProperty('deprecated')
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if self.node.GetProperty('allowAmbiguousOptionalArguments'):
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      properties['allowAmbiguousOptionalArguments'] = True
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'nodart'):
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.node.GetProperty(property_name):
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties[property_name.lower()] = True
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for option_name, sanitizer in [
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ('maxListeners', int),
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ('supportsFilters', lambda s: s == 'true'),
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ('supportsListeners', lambda s: s == 'true'),
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ('supportsRules', lambda s: s == 'true')]:
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self.node.GetProperty(option_name):
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if 'options' not in properties:
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          properties['options'] = {}
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        properties['options'][option_name] = sanitizer(self.node.GetProperty(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          option_name))
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_function = False
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    parameter_comments = OrderedDict()
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for node in self.node.GetChildren():
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.cls == 'Comment':
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (parent_comment, parameter_comments) = ProcessComment(node.GetName())
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties['description'] = parent_comment
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Callspec':
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        is_function = True
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        name, parameters, return_type = (Callspec(node, parameter_comments)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         .process(callbacks))
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties['parameters'] = parameters
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if return_type is not None:
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          properties['returns'] = return_type
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    properties['name'] = name
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if is_function:
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'function'
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties = Typeref(self.node.GetProperty('TYPEREF'),
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self.node, properties).process(callbacks)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enum_values = self.node.GetProperty('legalValues')
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if enum_values:
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if properties['type'] == 'integer':
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        enum_values = map(int, enum_values)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif properties['type'] == 'double':
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        enum_values = map(float, enum_values)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['enum'] = enum_values
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return name, properties
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Typeref(object):
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given a TYPEREF property representing the type of dictionary member or
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function parameter, converts into a Python dictionary that the JSON schema
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  compiler expects to see.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, typeref, parent, additional_properties):
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.typeref = typeref
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.parent = parent
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.additional_properties = additional_properties
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    properties = self.additional_properties
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = properties
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if self.parent.GetPropertyLocal('OPTIONAL'):
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['optional'] = True
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The IDL parser denotes array types by adding a child 'Array' node onto
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the Param node in the Callspec.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sibling in self.parent.GetChildren():
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if sibling.cls == 'Array' and sibling.GetName() == self.parent.GetName():
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties['type'] = 'array'
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        properties['items'] = OrderedDict()
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties = properties['items']
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.typeref == 'DOMString':
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'string'
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'boolean':
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'boolean'
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'double':
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'number'
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'long':
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'integer'
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'any':
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'any'
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'object':
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'object'
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'additionalProperties' not in properties:
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        properties['additionalProperties'] = OrderedDict()
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['additionalProperties']['type'] = 'any'
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instance_of = self.parent.GetProperty('instanceOf')
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if instance_of:
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties['isInstanceOf'] = instance_of
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref == 'ArrayBuffer':
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'binary'
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['isInstanceOf'] = 'ArrayBuffer'
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif self.typeref == 'FileEntry':
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      properties['type'] = 'object'
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      properties['isInstanceOf'] = 'FileEntry'
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if 'additionalProperties' not in properties:
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        properties['additionalProperties'] = OrderedDict()
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      properties['additionalProperties']['type'] = 'any'
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    elif self.parent.GetPropertyLocal('Union'):
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      choices = []
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      properties['choices'] = [Typeref(node.GetProperty('TYPEREF'),
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       node,
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       OrderedDict()).process(callbacks)
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               for node in self.parent.GetChildren()
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               if node.cls == 'Option']
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self.typeref is None:
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties['type'] = 'function'
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.typeref in callbacks:
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Do not override name and description if they are already specified.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name = properties.get('name', None)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = properties.get('description', None)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties.update(callbacks[self.typeref])
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if description is not None:
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          properties['description'] = description
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if name is not None:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          properties['name'] = name
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        properties['$ref'] = self.typeref
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Enum(object):
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given an IDL Enum node, converts into a Python dictionary that the JSON
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  schema compiler expects to see.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, enum_node):
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.node = enum_node
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.description = ''
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self, callbacks):
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enum = []
308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for node in self.node.GetChildren():
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.cls == 'EnumItem':
3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        enum_value = {'name': node.GetName()}
311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        for child in node.GetChildren():
3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          if child.cls == 'Comment':
3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            enum_value['description'] = ProcessComment(child.GetName())[0]
3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          else:
3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            raise ValueError('Did not process %s %s' % (child.cls, child))
3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        enum.append(enum_value)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Comment':
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.description = ProcessComment(node.GetName())[0]
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.exit('Did not process %s %s' % (node.cls, node))
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = {'id' : self.node.GetName(),
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'description': self.description,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'type': 'string',
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'enum': enum}
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for property_name in (
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        'inline_doc', 'noinline_doc', 'nodoc', 'cpp_enum_prefix_override',):
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self.node.GetProperty(property_name):
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        result[property_name] = self.node.GetProperty(property_name)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.node.GetProperty('deprecated'):
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        result[deprecated] = self.node.GetProperty('deprecated')
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Namespace(object):
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given an IDLNode representing an IDL namespace, converts into a Python
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary that the JSON schema compiler expects to see.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def __init__(self,
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               namespace_node,
3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               description,
3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               nodoc=False,
3441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               internal=False,
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)               platforms=None,
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               compiler_options=None,
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               deprecated=None):
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.namespace = namespace_node
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.nodoc = nodoc
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.internal = internal
3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.platforms = platforms
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.compiler_options = compiler_options
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.events = []
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.functions = []
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.types = []
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.callbacks = OrderedDict()
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    self.description = description
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.deprecated = deprecated
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self):
361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for node in self.namespace.GetChildren():
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.cls == 'Dictionary':
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.types.append(Dictionary(node).process(self.callbacks))
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Callback':
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        k, v = Member(node).process(self.callbacks)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.callbacks[k] = v
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Interface' and node.GetName() == 'Functions':
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.functions = self.process_interface(node)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Interface' and node.GetName() == 'Events':
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.events = self.process_interface(node)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Enum':
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.types.append(Enum(node).process(self.callbacks))
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.exit('Did not process %s %s' % (node.cls, node))
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.compiler_options is not None:
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      compiler_options = self.compiler_options
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else:
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      compiler_options = {}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return {'namespace': self.namespace.GetName(),
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            'description': self.description,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'nodoc': self.nodoc,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'types': self.types,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'functions': self.functions,
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'internal': self.internal,
3851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            'events': self.events,
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            'platforms': self.platforms,
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'compiler_options': compiler_options,
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'deprecated': self.deprecated}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process_interface(self, node):
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    members = []
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for member in node.GetChildren():
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if member.cls == 'Member':
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name, properties = Member(member).process(self.callbacks)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        members.append(properties)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return members
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IDLSchema(object):
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given a list of IDLNodes and IDLAttributes, converts into a Python list
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of api_defs that the JSON schema compiler expects to see.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, idl):
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.idl = idl
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def process(self):
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    namespaces = []
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodoc = False
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal = False
412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    description = None
4131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    platforms = None
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    compiler_options = {}
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    deprecated = None
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for node in self.idl:
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.cls == 'Namespace':
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if not description:
4197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          # TODO(kalman): Go back to throwing an error here.
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          print('%s must have a namespace-level comment. This will '
421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           'appear on the API summary page.' % node.GetName())
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          description = ''
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        namespace = Namespace(node, description, nodoc, internal,
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              platforms=platforms,
425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                              compiler_options=compiler_options or None,
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              deprecated=deprecated)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        namespaces.append(namespace.process())
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nodoc = False
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        internal = False
4301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        platforms = None
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        compiler_options = None
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Copyright':
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'Comment':
435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        description = node.GetName()
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.cls == 'ExtAttribute':
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if node.name == 'nodoc':
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodoc = bool(node.value)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif node.name == 'internal':
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          internal = bool(node.value)
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        elif node.name == 'platforms':
4421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          platforms = list(node.value)
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        elif node.name == 'implemented_in':
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          compiler_options['implemented_in'] = node.value
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        elif node.name == 'camel_case_enum_to_string':
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          compiler_options['camel_case_enum_to_string'] = node.value
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        elif node.name == 'deprecated':
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          deprecated = str(node.value)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.exit('Did not process %s %s' % (node.cls, node))
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return namespaces
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Load(filename):
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given the filename of an IDL file, parses it and returns an equivalent
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Python dictionary in a format that the JSON schema compiler expects to see.
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f = open(filename, 'r')
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents = f.read()
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f.close()
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idl = idl_parser.IDLParser().ParseData(contents, filename)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idl_schema = IDLSchema(idl)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return idl_schema.process()
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Main():
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dump a json serialization of parse result for the IDL files whose names
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  were passed in on the command line.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
47646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if len(sys.argv) > 1:
47746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    for filename in sys.argv[1:]:
47846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      schema = Load(filename)
47946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      print json.dumps(schema, indent=2)
48046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  else:
48146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    contents = sys.stdin.read()
48246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    idl = idl_parser.IDLParser().ParseData(contents, '<stdin>')
48346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    schema = IDLSchema(idl).process()
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print json.dumps(schema, indent=2)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Main()
489