Commit fb396f70 authored by Hitoshi Yoshida's avatar Hitoshi Yoshida Committed by Commit Bot

bindings: Generate a IDL information collection per component

This CL defines a new set of Web IDL based classes under web_idl/.
Collecitor class is the main API, which reads IDL files and
stacks converted information.

This CL also updates some BUILD.gn files to generate an
intermediate dump file per component, which includes all
information in IDL files in the component.


Bug: 650150, 727971, 579896
Change-Id: Idc98be4485855afc7797b7fc3af21fb7ee68f0ed
Reviewed-on: https://chromium-review.googlesource.com/648534
Commit-Queue: Hitoshi Yoshida <peria@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarKenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522378}
parent f97b5870
...@@ -39,3 +39,10 @@ generate_global_constructors("core_global_constructors_idls") { ...@@ -39,3 +39,10 @@ generate_global_constructors("core_global_constructors_idls") {
":core_global_objects", ":core_global_objects",
] ]
} }
generate_web_idl_collection("core_web_idl_collection") {
sources = core_static_interface_idl_files - core_testing_definition_idl_files
output = "WebIdlCollectionForCore.pickle"
component = "core"
output_dir = bindings_core_output_dir
}
...@@ -198,3 +198,10 @@ source_set("generated") { ...@@ -198,3 +198,10 @@ source_set("generated") {
"//v8", "//v8",
] ]
} }
generate_web_idl_collection("modules_web_idl_collection") {
sources = modules_definition_idl_files + modules_dependency_idl_files
output = "WebIdlCollectionForModules.pickle"
component = "modules"
output_dir = bindings_modules_output_dir
}
# Copyright 2017 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.
"""Generates a data collection of IDL information per component.
In this data collection, we use identifier strings to point IDL definitions
(i.e. interface, dictionary, namespace, etc.) instead of references, because
some referred definitions can be in other components.
"""
import blink_idl_parser
import optparse
import utilities
from web_idl.collector import Collector
def parse_options():
parser = optparse.OptionParser()
parser.add_option('--idl-list-file', help='a file path which lists IDL file paths to process')
parser.add_option('--component', help='decide which component to collect IDLs', default=None)
parser.add_option('--output', help='pickle file of IDL definition')
options, args = parser.parse_args()
if options.idl_list_file is None:
parser.error('Must specify a file listing IDL files using --idl-files-list.')
if options.output is None:
parser.error('Must specify a pickle file to output using --output.')
return options, args
def main():
options, _ = parse_options()
idl_file_names = utilities.read_idl_files_list_from_file(options.idl_list_file, False)
parser = blink_idl_parser.BlinkIDLParser()
collector = Collector(component=options.component, parser=parser)
collection = collector.collect_from_idl_files(idl_file_names)
utilities.write_pickle_file(options.output, collection)
if __name__ == '__main__':
main()
...@@ -58,6 +58,29 @@ idl_compiler_files = ...@@ -58,6 +58,29 @@ idl_compiler_files =
], ],
"abspath") "abspath")
web_idl_scripts = get_path_info([
"web_idl/argument.py",
"web_idl/attribute.py",
"web_idl/callback_function.py",
"web_idl/collection.py",
"web_idl/collector.py",
"web_idl/constant.py",
"web_idl/dictionary.py",
"web_idl/ecma_script_types.py",
"web_idl/enumeration.py",
"web_idl/extended_attribute.py",
"web_idl/idl_types.py",
"web_idl/implements.py",
"web_idl/interface.py",
"web_idl/literal_token.py",
"web_idl/namespace.py",
"web_idl/operation.py",
"web_idl/typedef.py",
"web_idl/utilities.py",
"web_idl/idl_definition_builder.py",
],
"abspath")
# Calls the compute_interfaces_info_individual script. # Calls the compute_interfaces_info_individual script.
# #
# Parameters: # Parameters:
...@@ -540,3 +563,27 @@ template("generate_origin_trial_features") { ...@@ -540,3 +563,27 @@ template("generate_origin_trial_features") {
[ "//third_party/WebKit/Source/bindings/modules:interfaces_info" ] [ "//third_party/WebKit/Source/bindings/modules:interfaces_info" ]
} }
} }
template("generate_web_idl_collection") {
action(target_name) {
script = "//third_party/WebKit/Source/bindings/scripts/generate_web_idl_collection.py"
output_dir = invoker.output_dir
output_file_name = invoker.output
output_path = "${output_dir}/${output_file_name}"
inputs = web_idl_scripts + invoker.sources
outputs = [
output_path,
]
# List input file names in a temporary file.
response_file_contents = rebase_path(invoker.sources, root_build_dir)
args = [
"--idl-list-file",
"{{response_file_name}}",
"--component",
invoker.component,
"--output",
rebase_path(output_path, root_build_dir),
]
}
}
# Copyright 2017 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.
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
class Argument(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._type = kwargs.pop('type')
self._is_optional = kwargs.pop('is_optional', False)
self._is_variadic = kwargs.pop('is_variadic', False)
self._default_value = kwargs.pop('default_value', None)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def type(self):
return self._type
@property
def is_optional(self):
return self._is_optional
@property
def is_variadic(self):
return self._is_variadic
@property
def default_value(self):
return self._default_value
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .idl_types import RecordType
from .idl_types import SequenceType
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-attributes
class Attribute(object):
_INVALID_TYPES = frozenset([SequenceType, RecordType])
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._type = kwargs.pop('type')
self._is_static = kwargs.pop('is_static', False)
self._is_readonly = kwargs.pop('is_readonly', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
if type(self.type) in Attribute._INVALID_TYPES:
raise ValueError('The type of an attribute must not be either of sequence<T> and record<K,V>.')
@property
def identifier(self):
return self._identifier
@property
def type(self):
return self._type
@property
def is_static(self):
return self._is_static
@property
def is_readonly(self):
return self._is_readonly
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-callback-functions
class CallbackFunction(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._return_type = kwargs.pop('return_type')
self._arguments = tuple(kwargs.pop('arguments', []))
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def return_type(self):
return self._return_type
@property
def arguments(self):
return self._arguments
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-interfaces
class CallbackInterface(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._attributes = tuple(kwargs.pop('attributes', []))
self._operations = tuple(kwargs.pop('operations', []))
self._constants = tuple(kwargs.pop('constants', []))
self._inherited_interface_name = kwargs.pop('inherited_interface_name', None)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
if any(attribute.is_static for attribute in self.attributes):
raise ValueError('Static attributes must not be defined on a callback interface')
if any(operation.is_static for operation in self.operations):
raise ValueError('Static operations must not be defined on a callback interface')
@property
def identifier(self):
return self._identifier
@property
def attributes(self):
return self._attributes
@property
def operations(self):
return self._operations
@property
def constants(self):
return self._constants
@property
def inherited_interface_name(self):
return self._inherited_interface_name
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .callback_function import CallbackFunction
from .callback_interface import CallbackInterface
from .dictionary import Dictionary
from .enumeration import Enumeration
from .implements import Implements
from .interface import Interface
from .namespace import Namespace
from .typedef import Typedef
class Collection(object):
"""
Collection class stores Web IDL definitions and some meta information.
"""
def __init__(self, component=None):
self._interfaces = {}
self._callback_interfaces = {}
self._namespaces = {}
self._dictionaries = {}
self._enumerations = {}
self._callback_functions = {}
self._typedefs = {}
# In spec, different partial definitions can have same identifiers.
# So they are stored in a list, which is indexed by the identifier.
# i.e. {'identifer': [definition, definition, ...]}
self._partial_interfaces = {}
self._partial_namespaces = {}
self._partial_dictionaries = {}
# Implements statements are not named definitions.
self._implements = []
# These members are not in spec., but they are necessary for code generators.
self._metadata_store = []
self._component = component
def find_non_partial_definition(self, identifier):
"""Returns a non-partial named definition, if it is defined. Otherwise returns None."""
if identifier in self._interfaces:
return self._interfaces[identifier]
if identifier in self._callback_interfaces:
return self._callback_interfaces[identifier]
if identifier in self._namespaces:
return self._namespaces[identifier]
if identifier in self._dictionaries:
return self._dictionaries[identifier]
if identifier in self._enumerations:
return self._enumerations[identifier]
if identifier in self._callback_functions:
return self._callback_functions[identifier]
if identifier in self._typedefs:
return self._typedefs[identifier]
return None
def find_partial_definition(self, identifier):
if identifier in self._partial_interfaces:
return self._partial_interfaces[identifier]
if identifier in self._partial_namespaces:
return self._partial_namespaces[identifier]
if identifier in self._partial_dictionaries:
return self._partial_dictionaries[identifier]
return []
def find_filepath(self, definition):
for metadata in self._metadata_store:
if metadata.definition == definition:
return metadata.filepath
return None
def register_definition(self, definition, filepath):
if type(definition) == Interface:
if definition.is_partial:
self._register_partial_definition(self._partial_interfaces, definition)
else:
self._register_definition(self._interfaces, definition)
elif type(definition) == Namespace:
if definition.is_partial:
self._register_partial_definition(self._partial_namespaces, definition)
else:
self._register_definition(self._namespaces, definition)
elif type(definition) == Dictionary:
if definition.is_partial:
self._register_partial_definition(self._partial_dictionaries, definition)
else:
self._register_definition(self._dictionaries, definition)
elif type(definition) == CallbackInterface:
self._register_definition(self._callback_interfaces, definition)
elif type(definition) == Enumeration:
self._register_definition(self._enumerations, definition)
elif type(definition) == Typedef:
self._register_definition(self._typedefs, definition)
elif type(definition) == CallbackFunction:
self._register_definition(self._callback_functions, definition)
elif type(definition) == Implements:
self._implements.append(definition)
else:
raise ValueError('Unrecognized class definition %s in %s' % (str(type(definition)), filepath))
metadata = _Metadata(definition, filepath)
self._metadata_store.append(metadata)
@property
def interface_identifiers(self):
return self._interfaces.keys()
@property
def callback_interface_identifiers(self):
return self._callback_interfaces.keys()
@property
def namespace_identifiers(self):
return self._namespaces.keys()
@property
def dictionary_identifiers(self):
return self._dictionaries.keys()
@property
def enumeration_identifiers(self):
return self._enumerations.keys()
@property
def callback_function_identifiers(self):
return self._callback_functions.keys()
@property
def typedef_identifiers(self):
return self._typedefs.keys()
@property
def implements(self):
return self._implements
@property
def component(self):
return self._component
def _register_definition(self, definitions, definition):
identifier = definition.identifier
previous_definition = self.find_non_partial_definition(identifier)
if previous_definition and previous_definition == definition:
raise ValueError('Conflict: %s is defined in %s and %s' %
(identifier, self.find_filepath(previous_definition),
self.find_filepath(definition)))
definitions[identifier] = definition
def _register_partial_definition(self, definitions, definition):
identifier = definition.identifier
if identifier not in definitions:
definitions[identifier] = []
definitions[identifier].append(definition)
class _Metadata(object):
"""Metadata holds information of a definition which is not in spec.
- |filepath| shows the .idl file name where the definition is described.
"""
def __init__(self, definition, filepath):
self._definition = definition
self._filepath = filepath
# Copyright 2017 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
import sys
from .idl_definition_builder import IdlDefinitionBuilder
from .collection import Collection
# TODO(peria): Merge bindings/scripts/blink_idl_parser.py with tools/idl_parser,
# and put in this directory. Then we can remove this sys.path update.
_SCRIPTS_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir)
sys.path.append(_SCRIPTS_PATH)
import blink_idl_parser
class Collector(object):
def __init__(self, component, parser=blink_idl_parser.BlinkIDLParser()):
self._component = component
self._collection = Collection(component)
self._parser = parser
def collect_from_idl_files(self, filepaths):
if type(filepaths) == str:
filepaths = [filepaths]
for filepath in filepaths:
try:
ast = blink_idl_parser.parse_file(self._parser, filepath)
self.collect_from_ast(ast)
except ValueError as ve:
raise ValueError('%s\nin file %s' % (str(ve), filepath))
def collect_from_idl_text(self, text, filename='TEXT'):
ast = self._parser.ParseText(filename, text) # pylint: disable=no-member
self.collect_from_ast(ast)
def collect_from_ast(self, node):
for definition, filepath in IdlDefinitionBuilder.idl_definitions(node):
self._collection.register_definition(definition, filepath)
def get_collection(self):
return self._collection
#!/usr/bin/python
# Copyright 2017 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 unittest
from .collector import Collector
class CollectorTest(unittest.TestCase):
def setUp(self):
self._collector = Collector(component='test')
def collect_from_idl_text(self, idl_text):
self._collector.collect_from_idl_text(idl_text)
return self._collector.get_collection()
def test_definition_filters(self):
idl_text = """
interface MyInterface {};
partial interface MyInterface {};
dictionary MyDictionary {};
dictionary MyDictionary2 {};
partial dictionary MyPartialDictionary {};
namespace MyNamespace {};
partial namespace MyNamespace {};
partial namespace MyNamespace2 {};
partial namespace MyNamespace2 {};
enum MyEnum { "FOO" };
callback MyCallbackFunction = void (DOMString arg);
typedef sequence<Point> Points;
Foo implements Bar;
"""
collection = self.collect_from_idl_text(idl_text)
self.assertEqual(1, len(collection.callback_function_identifiers))
self.assertEqual(1, len(collection.enumeration_identifiers))
self.assertEqual(1, len(collection.interface_identifiers))
self.assertEqual(1, len(collection.namespace_identifiers))
self.assertEqual(1, len(collection.typedef_identifiers))
self.assertEqual(2, len(collection.dictionary_identifiers))
self.assertEqual(1, len(collection.implements))
self.assertEqual(2, len(collection.find_partial_definition('MyNamespace2')))
def test_interface(self):
idl_text = """
interface InterfaceSimpleMembers {
void operation1(DOMString arg);
attribute long longMember;
};
interface InheritInterface : InheritedInterface {};
partial interface PartialInterface {
attribute long longMember;
};
partial interface PartialInterface {
attribute long long longlongMember;
};
"""
collection = self.collect_from_idl_text(idl_text)
interface = collection.find_non_partial_definition('InterfaceSimpleMembers')
self.assertEqual('InterfaceSimpleMembers', interface.identifier)
self.assertEqual(1, len(interface.attributes))
self.assertEqual(1, len(interface.operations))
self.assertEqual('operation1', interface.operations[0].identifier)
self.assertEqual('longMember', interface.attributes[0].identifier)
interface = collection.find_non_partial_definition('InheritInterface')
self.assertEqual('InheritInterface', interface.identifier)
self.assertEqual('InheritedInterface', interface.inherited_interface_name)
partial_interfaces = collection.find_partial_definition('PartialInterface')
self.assertTrue(partial_interfaces[0].is_partial)
self.assertTrue(partial_interfaces[1].is_partial)
attribute = partial_interfaces[0].attributes[0]
self.assertEqual('longMember', attribute.identifier)
attribute = partial_interfaces[1].attributes[0]
self.assertEqual('longlongMember', attribute.identifier)
idl_text = """
interface InterfaceAttributes {
attribute long longAttr;
readonly attribute octet readonlyAttr;
static attribute DOMString staticStringAttr;
attribute [TreatNullAs=EmptyString] DOMString annotatedTypeAttr;
[Unforgeable] attribute DOMString? extendedAttributeAttr;
};
"""
collection = self.collect_from_idl_text(idl_text)
interface = collection.find_non_partial_definition('InterfaceAttributes')
attributes = interface.attributes
self.assertEqual(5, len(attributes))
attribute = attributes[0]
self.assertEqual('longAttr', attribute.identifier)
self.assertEqual('Long', attribute.type.type_name)
attribute = attributes[1]
self.assertEqual('readonlyAttr', attribute.identifier)
self.assertEqual('Octet', attribute.type.type_name)
self.assertTrue(attribute.is_readonly)
attribute = attributes[2]
self.assertEqual('staticStringAttr', attribute.identifier)
self.assertEqual('String', attribute.type.type_name)
self.assertTrue(attribute.is_static)
attribute = attributes[3]
self.assertEqual('annotatedTypeAttr', attribute.identifier)
self.assertEqual('String', attribute.type.type_name)
self.assertEqual('EmptyString', attribute.type.treat_null_as)
attribute = attributes[4]
self.assertEqual('extendedAttributeAttr', attribute.identifier)
self.assertEqual('String', attribute.type.type_name)
self.assertTrue(attribute.type.is_nullable)
self.assertTrue(attribute.extended_attribute_list.has('Unforgeable'))
def test_extended_attributes(self):
idl_text = """
[
NoInterfaceObject,
OriginTrialEnabled=FooBar
] interface ExtendedAttributeInterface {};
"""
collection = self.collect_from_idl_text(idl_text)
interface = collection.find_non_partial_definition('ExtendedAttributeInterface')
extended_attribute_list = interface.extended_attribute_list
self.assertTrue(extended_attribute_list.has('OriginTrialEnabled'))
self.assertTrue(extended_attribute_list.has('NoInterfaceObject'))
self.assertEqual('FooBar', extended_attribute_list.get('OriginTrialEnabled'))
idl_text = """
[
Constructor,
Constructor(DOMString arg),
CustomConstructor,
CustomConstructor(long arg),
NamedConstructor=Audio,
NamedConstructor=Audio(DOMString src)
] interface ConstructorInterface {};
"""
collection = self.collect_from_idl_text(idl_text)
interface = collection.find_non_partial_definition('ConstructorInterface')
constructors = interface.constructors
self.assertEqual(4, len(constructors))
self.assertFalse(constructors[0].is_custom)
self.assertFalse(constructors[1].is_custom)
self.assertTrue(constructors[2].is_custom)
self.assertTrue(constructors[3].is_custom)
named_constructors = interface.named_constructors
self.assertEqual('Audio', named_constructors[0].identifier)
self.assertEqual('Audio', named_constructors[1].identifier)
self.assertEqual('arg', constructors[1].arguments[0].identifier)
self.assertEqual('arg', constructors[3].arguments[0].identifier)
self.assertEqual('src', named_constructors[1].arguments[0].identifier)
idl_text = """
[
Exposed=(Window, Worker),
Exposed(Window Feature1, Worker Feature2)
] interface ExposedInterface {};
"""
collection = self.collect_from_idl_text(idl_text)
interface = collection.find_non_partial_definition('ExposedInterface')
exposures = interface.exposures
self.assertEqual(4, len(exposures))
self.assertEqual('Window', exposures[0].global_interface)
self.assertEqual('Worker', exposures[1].global_interface)
self.assertEqual('Window', exposures[2].global_interface)
self.assertEqual('Worker', exposures[3].global_interface)
self.assertEqual('Feature1', exposures[2].runtime_enabled_feature)
self.assertEqual('Feature2', exposures[3].runtime_enabled_feature)
if __name__ == '__main__':
unittest.main(verbosity=2)
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .idl_types import RecordType
from .idl_types import SequenceType
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-constants
class Constant(object):
_INVALID_IDENTIFIERS = frozenset(['length', 'name', 'prototype'])
_INVALID_TYPES = frozenset([SequenceType, RecordType])
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._type = kwargs.pop('type')
self._value = kwargs.pop('value')
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
if self.identifier in Constant._INVALID_IDENTIFIERS:
raise ValueError('Invalid identifier for a constant: %s' % self.identifier)
if type(self.type) in Constant._INVALID_TYPES:
raise ValueError('sequence<T> must not be used as the type of a constant.')
@property
def identifier(self):
return self._identifier
@property
def type(self):
return self._type
@property
def value(self):
return self._value
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-dictionaries
class Dictionary(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._members = kwargs.pop('members', {})
self._inherited_dictionary_name = kwargs.pop('inherited_dictionary_name', None)
self._is_partial = kwargs.pop('is_partial', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def members(self):
return self._members
@property
def inherited_dictionary_name(self):
return self._inherited_dictionary_name
@property
def is_partial(self):
return self._is_partial
@property
def extended_attribute_list(self):
return self._extended_attribute_list
class DictionaryMember(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._type = kwargs.pop('type')
self._default_value = kwargs.pop('default_value', None)
self._is_required = kwargs.pop('is_required', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def type(self):
return self._type
@property
def default_value(self):
return self._default_value
@property
def is_required(self):
return self._is_required
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .idl_types import TypeBase
from .utilities import assert_no_extra_args
class EcmaScriptType(TypeBase):
"""
EcmascriptType represents an EcmaScript type, which appears in Chromium IDL files.
@param string type_name : the identifier of a named definition to refer
@param bool is_nullable : True if the type is nullable (optional)
"""
_ALLOWED_TYPE_NAMES = frozenset(['Date'])
def __init__(self, **kwargs):
self._type_name = kwargs.pop('type_name')
self._is_nullable = kwargs.pop('is_nullable', False)
assert_no_extra_args(kwargs)
# Now we use only 'Date' type.
if self.type_name not in EcmaScriptType._ALLOWED_TYPE_NAMES:
raise ValueError('Unknown type name: %s' % self.type_name)
@property
def type_name(self):
return self._type_name
@property
def is_nullable(self):
return self._is_nullable
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-enums
class Enumeration(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._values = kwargs.pop('values', [])
# Extended attributes on enumerations are not allowed in spec, but Blink uses them.
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def values(self):
return self._values
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-extended-attributes
# To work with [Exposed], [Constructor], [CustomConstrucotr], and [NamedConstructor] easily, we define some classes
# for them in this file.
class ExtendedAttributeList(object):
def __init__(self, **kwargs):
self._extended_attributes = kwargs.pop('extended_attributes', {})
self._exposures = tuple(kwargs.pop('exposures', []))
constructors = kwargs.pop('constructors', [])
self._constructors = tuple([ctor for ctor in constructors if type(ctor) == Constructor])
self._named_constructors = tuple([ctor for ctor in constructors if type(ctor) == NamedConstructor])
if self.exposures:
self._extended_attributes['Exposed'] = self.exposures
if self.named_constructors:
self._extended_attributes['NamedConstructor'] = self.named_constructors
if any(ctor.is_custom for ctor in self.constructors):
self._extended_attributes['CustomConstructor'] = [ctor for ctor in self.constructors if ctor.is_custom]
if any(not ctor.is_custom for ctor in self.constructors):
self._extended_attributes['CustomConstructor'] = [ctor for ctor in self.constructors if not ctor.is_custom]
def get(self, key):
return self.extended_attributes.get(key)
def has(self, key):
return key in self.extended_attributes
@property
def extended_attributes(self):
"""
[Exposed], [Constructor], [CustomConstrucotr], and [NamedConstructor] can be taken with
other property methods, but the returned value of this method also includes them.
"""
return self._extended_attributes
@property
def constructors(self):
return self._constructors
@property
def named_constructors(self):
return self._named_constructors
@property
def exposures(self):
return self._exposures
# https://heycam.github.io/webidl/#Constructor
class Constructor(object):
def __init__(self, **kwargs):
self._arguments = kwargs.pop('arguments', [])
self._is_custom = kwargs.pop('is_custom', False)
assert_no_extra_args(kwargs)
@property
def arguments(self):
return self._arguments
@property
def is_custom(self):
return self._is_custom
# https://heycam.github.io/webidl/#NamedConstructor
class NamedConstructor(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier', None)
self._arguments = kwargs.pop('arguments', [])
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def arguments(self):
return self._arguments
# https://heycam.github.io/webidl/#Exposed
class Exposure(object):
"""Exposure holds an exposed target, and can hold a runtime enabled condition.
"[Exposed=global_interface]" is represented as Exposure(global_interface), and
"[Exposed(global_interface runtime_enabled_feature)] is represented as Exposure(global_interface, runtime_enabled_feature).
"""
def __init__(self, **kwargs):
self._global_interface = kwargs.pop('global_interface')
self._runtime_enabled_feature = kwargs.pop('runtime_enabled_feature', None)
assert_no_extra_args(kwargs)
@property
def global_interface(self):
return self._global_interface
@property
def runtime_enabled_feature(self):
return self._runtime_enabled_feature
# Copyright 2017 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.
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-implements-statements
class Implements(object):
"""Implement class represents Implements statement in Web IDL spec."""
def __init__(self, **kwargs):
self._implementer_name = kwargs.pop('implementer_name')
self._implementee_name = kwargs.pop('implementee_name')
assert_no_extra_args(kwargs)
if self.implementer_name == self.implementee_name:
raise ValueError('Implements cannot refer same identifiers: %s' % self.implementer_name)
@property
def implementer_name(self):
return self._implementer_name
@property
def implementee_name(self):
return self._implementee_name
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-interfaces
class Interface(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._attributes = tuple(kwargs.pop('attributes', []))
self._operations = tuple(kwargs.pop('operations', []))
self._constants = tuple(kwargs.pop('constants', []))
self._iterable = kwargs.pop('iterable', None)
self._maplike = kwargs.pop('maplike', None)
self._setlike = kwargs.pop('setlike', None)
# BUG(736332): Remove support of legacy serializer members.
self._serializer = kwargs.pop('serializer', None)
self._inherited_interface_name = kwargs.pop('inherited_interface_name', None)
self._is_partial = kwargs.pop('is_partial', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
num_declaration = (1 if self.iterable else 0) + (1 if self.maplike else 0) + (1 if self.setlike else 0)
if num_declaration > 1:
raise ValueError('At most one of iterable<>, maplike<>, or setlike<> must be applied.')
@property
def identifier(self):
return self._identifier
@property
def attributes(self):
return self._attributes
@property
def operations(self):
return self._operations
@property
def constants(self):
return self._constants
@property
def iterable(self):
return self._iterable
@property
def maplike(self):
return self._maplike
@property
def setlike(self):
return self._setlike
@property
def serializer(self):
return self._serializer
@property
def inherited_interface_name(self):
return self._inherited_interface_name
@property
def is_partial(self):
return self._is_partial
@property
def constructors(self):
return self.extended_attribute_list.constructors
@property
def named_constructors(self):
return self.extended_attribute_list.named_constructors
@property
def exposures(self):
return self.extended_attribute_list.exposures
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# https://heycam.github.io/webidl/#idl-iterable
class Iterable(object):
def __init__(self, **kwargs):
self._key_type = kwargs.pop('key_type', None)
self._value_type = kwargs.pop('value_type')
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def key_type(self):
return self._key_type
@property
def value_type(self):
return self._value_type
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# https://heycam.github.io/webidl/#idl-maplike
class Maplike(object):
def __init__(self, **kwargs):
self._key_type = kwargs.pop('key_type')
self._value_type = kwargs.pop('value_type')
self._is_readonly = kwargs.pop('is_readonly', False)
assert_no_extra_args(kwargs)
@property
def key_type(self):
return self._key_type
@property
def value_type(self):
return self._value_type
@property
def is_readonly(self):
return self._is_readonly
# https://heycam.github.io/webidl/#idl-setlike
class Setlike(object):
def __init__(self, **kwargs):
self._value_type = kwargs.pop('value_type')
self._is_readonly = kwargs.pop('is_readonly', False)
assert_no_extra_args(kwargs)
@property
def value_type(self):
return self._value_type
@property
def is_readonly(self):
return self._is_readonly
# https://www.w3.org/TR/WebIDL-1/#idl-serializers
# BUG(736332): Remove support of legacy serializer.
# We support styles only used in production code. i.e.
# - serializer;
# - serializer = { attribute };
# - serializer = { inherit, attribute };
class Serializer(object):
def __init__(self, **kwargs):
self._is_map = kwargs.pop('is_map', False)
self._has_attribute = kwargs.pop('has_attribute', False)
self._has_inherit = kwargs.pop('has_inherit', False)
assert_no_extra_args(kwargs)
if (self.has_attribute or self.has_inherit) and not self._is_map:
raise ValueError('has_attribute and has_inherit must be set with is_map')
@property
def is_map(self):
return self._is_map
@property
def has_attribute(self):
return self._has_attribute
@property
def has_inherit(self):
return self._has_inherit
# Copyright 2017 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.
from .utilities import assert_no_extra_args
class LiteralToken(object):
"""Literal class represents literal tokens in Web IDL. It appears
- default values of dictionary members
- default values of arguments in operations
- constant values in interfaces (string and [] are not allowed)
- arguments of some extended attributes
"""
def __init__(self, **kwargs):
self._type_name = kwargs.pop('type_name')
self._value = kwargs.pop('value')
assert_no_extra_args(kwargs)
@property
def type_name(self):
return self._type_name
@property
def value(self):
return self._value
NULL_TOKEN = LiteralToken(type_name='NULL', value='null')
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-namespaces
class Namespace(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._attributes = tuple(kwargs.pop('attributes', []))
self._operations = tuple(kwargs.pop('operations', []))
self._is_partial = kwargs.pop('is_partial', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def attributes(self):
return self._attributes
@property
def operations(self):
return self._operations
@property
def exposures(self):
return self.extended_attribute_list.exposures
@property
def is_partial(self):
return self._is_partial
@property
def extended_attribute_list(self):
return self._extended_attribute_list
# Copyright 2017 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.
from .extended_attribute import ExtendedAttributeList
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-operations
class Operation(object):
# https://www.w3.org/TR/WebIDL-1/#idl-special-operations
_SPECIAL_KEYWORDS = frozenset(['deleter', 'getter', 'legacycaller', 'setter', 'stringifier', 'serializer'])
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._return_type = kwargs.pop('return_type')
self._arguments = tuple(kwargs.pop('arguments', []))
self._special_keywords = frozenset(kwargs.pop('special_keywords', []))
self._is_static = kwargs.pop('is_static', False)
self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
assert_no_extra_args(kwargs)
if any(keyword not in Operation._SPECIAL_KEYWORDS for keyword in self._special_keywords):
raise ValueError('Unknown keyword is specified in special keywords')
@property
def identifier(self):
return self._identifier
@property
def return_type(self):
return self._return_type
@property
def arguments(self):
return self._arguments
@property
def special_keywords(self):
return self._special_keywords
@property
def is_static(self):
return self._is_static
@property
def extended_attribute_list(self):
return self._extended_attribute_list
@property
def is_regular(self):
return self.identifier and not self.is_static
@property
def is_special(self):
return bool(self.special_keywords)
# Copyright 2017 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.
from .utilities import assert_no_extra_args
# https://heycam.github.io/webidl/#idl-typedefs
class Typedef(object):
def __init__(self, **kwargs):
self._identifier = kwargs.pop('identifier')
self._type = kwargs.pop('type')
assert_no_extra_args(kwargs)
@property
def identifier(self):
return self._identifier
@property
def type(self):
return self._type
# Copyright 2017 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.
def assert_no_extra_args(kwargs):
if kwargs:
raise ValueError('Unknown parameters are passed: %s' % kwargs.keys())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment