WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
WIP: generates InspectorWebBackendCommands.js and InspectorWebBackendDispatchers.h
bug-131596-20140417215703.patch (text/plain), 80.96 KB, created by
Brian Burg
on 2014-04-17 21:58:08 PDT
(
hide
)
Description:
WIP: generates InspectorWebBackendCommands.js and InspectorWebBackendDispatchers.h
Filename:
MIME Type:
Creator:
Brian Burg
Created:
2014-04-17 21:58:08 PDT
Size:
80.96 KB
patch
obsolete
>Subversion Revision: 167181 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index ddd7772f78a5796448fbeb627665443e5f0ae0d9..b78caf5f97e21c729cf9199bad88d0f621133097 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,175 @@ >+2014-04-17 Brian J. Burg <burg@cs.washington.edu> >+ >+ Web Inspector: rewrite CodeGeneratorInspector to be modular and testable >+ https://bugs.webkit.org/show_bug.cgi?id=131596 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * inspector/scripts/CodeGeneratorInspector2.py: Added. >+ (generate_from_specification): >+ (generate_from_specification.load_specification): >+ * inspector/scripts/codegen/__init__.py: Added. >+ * inspector/scripts/codegen/generate_backend_commands.py: Added. >+ (make_javascript_identifier): >+ (make_javascript_identifier.replaceCallback): >+ (BackendCommandsGenerator): >+ (BackendCommandsGenerator.__init__): >+ (BackendCommandsGenerator.model): >+ (BackendCommandsGenerator.output_filename): >+ (BackendCommandsGenerator.write_output_files): >+ (BackendCommandsGenerator.generate_license): >+ (BackendCommandsGenerator.generate_backend_commands): >+ (BackendCommandsGenerator.generate_domain): >+ (BackendCommandsGenerator.generate_domain.generate_parameter_object): >+ * inspector/scripts/codegen/generate_backend_dispatcher_header.py: Added. >+ (ucfirst): >+ (BackendDispatcherHeaderGenerator): >+ (BackendDispatcherHeaderGenerator.__init__): >+ (BackendDispatcherHeaderGenerator.model): >+ (BackendDispatcherHeaderGenerator.output_filename): >+ (BackendDispatcherHeaderGenerator.write_output_files): >+ (BackendDispatcherHeaderGenerator.generate_license): >+ (BackendDispatcherHeaderGenerator.generate_backend_dispatcher): >+ (BackendDispatcherHeaderGenerator.generate_backend_dispatcher.should_generate_domain): >+ (BackendDispatcherHeaderGenerator.generate_domain_handler): >+ (BackendDispatcherHeaderGenerator.generate_handler_command): >+ (BackendDispatcherHeaderGenerator.generate_async_handler_command): >+ (BackendDispatcherHeaderGenerator.generate_domain_dispatcher): >+ (BackendDispatcherHeaderGenerator.generate_dispatcher_command): >+ * inspector/scripts/codegen/generator.py: Added. >+ (Generator): >+ (Generator.__init__): >+ (Generator.model): >+ (Generator.write_output_files): >+ (Generator.cpp_guard_for_domain): >+ (DummyGenerator): >+ (IncrementalFileWriter): >+ (IncrementalFileWriter.__init__): >+ (IncrementalFileWriter.write): >+ (IncrementalFileWriter.close): >+ * inspector/scripts/codegen/generator_templates.py: Added. >+ (GeneratorTemplates): >+ (String): >+ * inspector/scripts/codegen/models.py: Added. >+ (ParseException): >+ (TypecheckException): >+ (Framework): >+ (Framework.__init__): >+ (Framework.setting): >+ (Framework.fromString): >+ (Frameworks): >+ (TypeMode): >+ (TypeMode.__init__): >+ (TypeMode.fromString): >+ (TypeModes): >+ (TypeReference): >+ (TypeReference.__init__): >+ (TypeReference.referenced_name): >+ (Type): >+ (Type.__init__): >+ (Type.__eq__): >+ (Type.__hash__): >+ (Type.is_enum): >+ (Type.type_domain): >+ (Type.type_mode): >+ (Type.qualified_name): >+ (Type.resolve_type_references): >+ (Type.in_parameter_type): >+ (Type.out_parameter_type): >+ (Type.type_builder_type): >+ (ObjectType): >+ (ObjectType.__init__): >+ (ObjectType.type_domain): >+ (ObjectType.type_mode): >+ (ObjectType.qualified_name): >+ (ObjectType.resolve_type_references): >+ (ObjectType.in_parameter_type): >+ (ObjectType.out_parameter_type): >+ (ObjectType.type_builder_type): >+ (PrimitiveType): >+ (PrimitiveType.__init__): >+ (PrimitiveType.type_domain): >+ (PrimitiveType.type_mode): >+ (PrimitiveType.qualified_name): >+ (PrimitiveType.in_parameter_type): >+ (PrimitiveType.out_parameter_type): >+ (PrimitiveType.type_builder_type): >+ (PrimitiveType.cpp_primitive_name): >+ (AliasedType): >+ (AliasedType.__init__): >+ (AliasedType.type_domain): >+ (AliasedType.type_mode): >+ (AliasedType.qualified_name): >+ (AliasedType.resolve_type_references): >+ (AliasedType.in_parameter_type): >+ (AliasedType.out_parameter_type): >+ (AliasedType.type_builder_type): >+ (EnumType): >+ (EnumType.__init__): >+ (EnumType.is_enum): >+ (EnumType.type_domain): >+ (EnumType.type_mode): >+ (EnumType.enum_values): >+ (EnumType.qualified_name): >+ (EnumType.resolve_type_references): >+ (EnumType.in_parameter_type): >+ (EnumType.out_parameter_type): >+ (EnumType.type_builder_type): >+ (VectorType): >+ (VectorType.__init__): >+ (VectorType.type_domain): >+ (VectorType.type_mode): >+ (VectorType.qualified_name): >+ (VectorType.resolve_type_references): >+ (VectorType.in_parameter_type): >+ (VectorType.out_parameter_type): >+ (VectorType.type_builder_type): >+ (check_for_required_properties): >+ (Protocol): >+ (Protocol.__init__): >+ (Protocol.parse_specification): >+ (Protocol.parse_domain): >+ (Protocol.parse_type_declaration): >+ (Protocol.parse_type_member): >+ (Protocol.parse_command): >+ (Protocol.parse_event): >+ (Protocol.parse_parameter): >+ (Protocol.resolve_types): >+ (Protocol.lookup_type_for_declaration): >+ (Protocol.lookup_type_reference): >+ (Domain): >+ (Domain.__init__): >+ (Domain.resolve_type_references): >+ (Domains): >+ (TypeDeclaration): >+ (TypeDeclaration.__init__): >+ (TypeDeclaration.resolve_type_references): >+ (TypeMember): >+ (TypeMember.__init__): >+ (TypeMember.resolve_type_references): >+ (Parameter): >+ (Parameter.__init__): >+ (Parameter.resolve_type_references): >+ (Command): >+ (Command.__init__): >+ (Command.resolve_type_references): >+ (Event): >+ (Event.__init__): >+ (Event.resolve_type_references): >+ * inspector/scripts/tests/expected/fail-on-duplicate-type-declarations.json-error: Added. >+ * inspector/scripts/tests/expected/fail-on-type-declaration-using-type-reference.json-error: Added. >+ * inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-declaration.json-error: Added. >+ * inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-member.json-error: Added. >+ * inspector/scripts/tests/expected/same-type-id-different-domain.json-error: Added. >+ * inspector/scripts/tests/fail-on-duplicate-type-declarations.json: Added. >+ * inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json: Added. >+ * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json: Added. >+ * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json: Added. >+ * inspector/scripts/tests/same-type-id-different-domain.json: Added. >+ * inspector/scripts/tests/type-declaration-aliased-primitive-type.json: Added. >+ * inspector/scripts/tests/type-declaration-array-type.json: Added. >+ * inspector/scripts/tests/type-declaration-enum-type.json: Added. >+ > 2014-04-11 Brian J. Burg <burg@cs.washington.edu> > > Web Replay: code generator should consider enclosing class when computing duplicate type names >diff --git a/Source/JavaScriptCore/inspector/scripts/CodeGeneratorInspector2.py b/Source/JavaScriptCore/inspector/scripts/CodeGeneratorInspector2.py >new file mode 100755 >index 0000000000000000000000000000000000000000..107cf7b412047786068588d9fbc399d2158c596c >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/CodeGeneratorInspector2.py >@@ -0,0 +1,116 @@ >+#!/usr/bin/env python >+# >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+import os.path >+import re >+import sys >+import string >+from string import Template >+import optparse >+import logging >+ >+try: >+ import json >+except ImportError: >+ import simplejson as json >+ >+from codegen import * >+ >+ >+# Use a global logger, which normally only logs errors. >+# It can be configured to log debug messages from the CLI. >+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) >+log = logging.getLogger('global') >+ >+ >+def generate_from_specification(primary_specification_filepath=None, >+ supplemental_specification_filepaths=[], >+ output_prefix="", >+ output_dirpath=None, >+ force_output=False, >+ framework_name=""): >+ >+ def load_specification(protocol, filepath, isSupplemental=False): >+ try: >+ with open(filepath, "r") as input_file: >+ parsed_json = json.load(input_file) >+ protocol.parse_specification(parsed_json, isSupplemental=isSupplemental) >+ except ValueError as e: >+ raise Exception("Error parsing valid JSON in file: " + filepath) >+ >+ protocol = models.Protocol(framework_name) >+ for specification in supplemental_specification_filepaths: >+ load_specification(protocol, specification, isSupplemental=True) >+ load_specification(protocol, primary_specification_filepath, isSupplemental=False) >+ >+ protocol.resolve_types() >+ >+ generators = [] >+ generators.append(DummyGenerator(protocol, primary_specification_filepath, output_prefix)) >+ generators.append(BackendCommandsGenerator(protocol, primary_specification_filepath, output_prefix)) >+ generators.append(BackendDispatcherHeaderGenerator(protocol, primary_specification_filepath, output_prefix)) >+ >+ for generator in generators: >+ generator.write_output_files(output_dirpath, force_output) >+ >+ >+if __name__ == '__main__': >+ allowed_framework_names = ['WTF', 'JavaScriptCore', 'WebCore', 'WebKit', 'WebKit2', 'Test'] >+ cli_parser = optparse.OptionParser(usage="usage: %prog [options] PrimaryProtocol.json [SupplementalProtocol.json ...]") >+ cli_parser.add_option("-o", "--outputDir", help="Directory where generated files should be written.") >+ cli_parser.add_option("--framework", type="choice", choices=allowed_framework_names, help="The framework that the primary specification belongs to.") >+ cli_parser.add_option("--force", action="store_true", help="Force output of generated scripts, even if nothing changed.") >+ cli_parser.add_option("-v", "--debug", action="store_true", help="Log extra output for debugging the generator itself.") >+ cli_parser.add_option("-t", "--test", action="store_true", help="Enable test mode. Use unique output filenames created by prepending the input filename.") >+ >+ options = None >+ >+ arg_options, arg_values = cli_parser.parse_args() >+ if (len(arg_values) < 1): >+ raise ParseException("At least one plain argument expected") >+ >+ if not arg_options.outputDir: >+ raise ParseException("Missing output directory") >+ >+ if arg_options.debug: >+ log.setLevel(logging.DEBUG) >+ >+ options = { >+ 'primary_specification_filepath': arg_values[0], >+ 'supplemental_specification_filepaths': arg_values[1:], >+ 'output_dirpath': arg_options.outputDir, >+ 'output_prefix': os.path.basename(arg_values[0]) if arg_options.test else "", >+ 'framework_name': arg_options.framework, >+ 'force_output': arg_options.force >+ } >+ >+ try: >+ generate_from_specification(**options) >+ except (ParseException, TypecheckException) as e: >+ if arg_options.test: >+ log.error(e.message) >+ else: >+ raise # Force the build to fail. >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py b/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py >new file mode 100644 >index 0000000000000000000000000000000000000000..f0fa3239d2c8e3b7b75f2e90d70b9b2f24616836 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py >@@ -0,0 +1,7 @@ >+# Required for Python to search this directory for module files >+ >+from models import * >+from generator import * >+ >+from generate_backend_commands import * >+from generate_backend_dispatcher_header import * >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_commands.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_commands.py >new file mode 100644 >index 0000000000000000000000000000000000000000..d0116f5c84c0b590a51e5d697c152c1316d2109a >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_commands.py >@@ -0,0 +1,131 @@ >+#!/usr/bin/env python >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+ >+import logging >+import os.path >+import re >+import string >+ >+from generator import Generator, IncrementalFileWriter >+from string import Template >+from generator_templates import GeneratorTemplates as Templates >+ >+# Use a global logger, which normally only logs errors. >+# It can be configured to log debug messages from the CLI. >+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) >+log = logging.getLogger('global') >+ >+def make_javascript_identifier(str): >+ ALWAYS_UPPERCASED_SUBSTRINGS = ['API', 'CSS', 'DOM', 'HTML', 'XHR', 'XML'] >+ regex = '(\w*)(%s)(\w*)' % "|".join(ALWAYS_UPPERCASED_SUBSTRINGS) >+ def replaceCallback(match): >+ return "".join([match.group(1), match.group(2).upper(), match.group(3)]) >+ >+ # Split on hyphen, introduce camelcase, and force uppercasing of acronyms. >+ subwords = map(lambda x: x[0].upper() + x[1:], str.split('-')) >+ return re.sub(regex, replaceCallback, "".join(subwords), flags=re.IGNORECASE) >+ >+class BackendCommandsGenerator(Generator): >+ def __init__(self, model, input_filepath, output_prefix): >+ self._model = model >+ self._input_filepath = input_filepath >+ self._output_prefix = output_prefix >+ >+ def model(self): >+ return self._model >+ >+ def output_filename(self): >+ return "Inspector%sBackendCommands.js" % self.model().framework.setting('prefix') >+ >+ def write_output_files(self, _dir, force=False): >+ header_file = IncrementalFileWriter(os.path.join(_dir, self.output_filename()), force) >+ header_file.write(self.generate_backend_commands()) >+ header_file.close() >+ >+ def generate_license(self): >+ return Template(Templates.CopyrightBlock).substitute(None, inputFilename=os.path.basename(self._input_filepath)) >+ >+ def generate_backend_commands(self): >+ sections = [] >+ sections.append(self.generate_license()) >+ sections.extend([self.generate_domain(domain) for domain in filter(lambda domain: not domain.is_supplemental, self.model().domains)]) >+ return "\n\n".join(sections) >+ >+ def generate_domain(self, domain): >+ lines = [] >+ args = { >+ 'domain': domain.domain_name >+ } >+ >+ # Preamble >+ lines.append('// %(domain)s.' % args) >+ lines.append('InspectorBackend.register%(domain)sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "%(domain)s");' % args) >+ >+ # Enum Type Declarations >+ for _declaration in domain.type_declarations: >+ if _declaration.type.is_enum(): >+ enum_args = { >+ 'domain': domain.domain_name, >+ 'enumName': _declaration.type_name, >+ 'enumMap': ", ".join(['%s: "%s"' % (make_javascript_identifier(_value), _value) for _value in _declaration.type.enum_values()]) >+ } >+ lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s};' % enum_args) >+ >+ for _member in filter(lambda x: x.type.is_enum(), _declaration.type_members): >+ enum_args = { >+ 'domain': domain.domain_name, >+ 'enumName': '%s%s' % (_declaration.type_name, _member.member_name.capitalize()), >+ 'enumMap': ", ".join(['%s: "%s"' % (make_javascript_identifier(_value), _value) for _value in _member.type.enum_values()]) >+ } >+ lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s};' % enum_args) >+ >+ # Events >+ for _event in domain.events: >+ event_args = { >+ 'domain': domain.domain_name, >+ 'eventName': _event.event_name, >+ 'params': ", ".join(['"%s"' % _parameter.parameter_name for _parameter in _event.event_parameters]) >+ } >+ lines.append('InspectorBackend.registerEvent("%(domain)s.%(eventName)s", [%(params)s]);' % event_args) >+ >+ # Commands >+ for _command in domain.commands: >+ def generate_parameter_object(parameter): >+ pairs = [] >+ pairs.append('"name": "%s"' % _parameter.parameter_name) >+ pairs.append('"type": "%s"' % _parameter.type_ref.type_kind) >+ pairs.append('"optional": %s' % "true" if _parameter.is_optional else "false") >+ return ", ".join(pairs) >+ >+ command_args = { >+ 'domain': domain.domain_name, >+ 'commandName': _command.command_name, >+ 'callParams': ", ".join([generate_parameter_object(_parameter) for _parameter in _command.call_parameters]), >+ 'returnParams': ", ".join([generate_parameter_object(_parameter) for _parameter in _command.return_parameters]), >+ } >+ lines.append('InspectorBackend.registerCommand("%(domain)s.%(commandName)s", [%(callParams)s], [%(returnParams)s]);' % command_args) >+ >+ return "\n".join(lines) >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_dispatcher_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_dispatcher_header.py >new file mode 100644 >index 0000000000000000000000000000000000000000..509d2fe304c1b511f6dc156d3f178581b93196e7 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_dispatcher_header.py >@@ -0,0 +1,175 @@ >+#!/usr/bin/env python >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+ >+import logging >+import os.path >+import re >+import string >+ >+from generator import Generator, IncrementalFileWriter >+from string import Template >+from generator_templates import GeneratorTemplates as Templates >+ >+# Use a global logger, which normally only logs errors. >+# It can be configured to log debug messages from the CLI. >+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) >+log = logging.getLogger('global') >+ >+ >+def ucfirst(str): >+ return str[:1].upper() + str[1:] >+ >+ >+class BackendDispatcherHeaderGenerator(Generator): >+ def __init__(self, model, input_filepath, output_prefix): >+ self._model = model >+ self._input_filepath = input_filepath >+ self._output_prefix = output_prefix >+ >+ def model(self): >+ return self._model >+ >+ def output_filename(self): >+ return "Inspector%sBackendDispatchers.h" % self.model().framework.setting('prefix') >+ >+ def write_output_files(self, _dir, force=False): >+ header_file = IncrementalFileWriter(os.path.join(_dir, self.output_filename()), force) >+ header_file.write(self.generate_backend_dispatcher()) >+ header_file.close() >+ >+ def generate_license(self): >+ return Template(Templates.CopyrightBlock).substitute(None, inputFilename=os.path.basename(self._input_filepath)) >+ >+ def generate_backend_dispatcher(self): >+ sections = [] >+ sections.append(self.generate_license()) >+ header_args = { >+ 'headerGuardString': re.sub('[-./]', '_', self.output_filename()), >+ 'frameworkPrefix': self.model().framework.setting('prefix'), >+ 'inputFilename': self._input_filepath >+ >+ } >+ >+ def should_generate_domain(domain): >+ return len(domain.commands) > 0 and not domain.is_supplemental >+ >+ sections.append(Template(Templates.DispatcherHeaderPrelude).substitute(None, **header_args)) >+ sections.extend([self.generate_domain_handler(domain) for domain in filter(should_generate_domain, self.model().domains)]) >+ sections.extend([self.generate_domain_dispatcher(domain) for domain in filter(should_generate_domain, self.model().domains)]) >+ sections.append(Template(Templates.DispatcherHeaderPostlude).substitute(None, **header_args)) >+ return "\n\n".join(sections) >+ >+ def generate_domain_handler(self, domain): >+ lines = [] >+ domain_guard = Generator.cpp_guard_for_domain(domain) >+ if domain_guard is not None: >+ lines.append("#if %s" % domain_guard) >+ >+ classComponents = ['class'] >+ exportMacro = self.model().framework.setting('export_macro', None) >+ if exportMacro is not None: >+ classComponents.append(exportMacro) >+ >+ handler_args = { >+ 'classAndExportMacro': " ".join(classComponents), >+ 'domainName': domain.domain_name, >+ 'commandDeclarations': "\n".join([self.generate_handler_command(command) for command in domain.commands]) >+ } >+ >+ lines.append(Template(Templates.DispatchHeaderDomainHandlerDeclaration).substitute(None, **handler_args)) >+ if domain_guard is not None: >+ lines.append("#endif // %s" % domain_guard) >+ return "\n".join(lines) >+ >+ def generate_handler_command(self, command): >+ if command.is_async: >+ return self.generate_async_handler_command(command) >+ >+ parameters = ['ErrorString*'] >+ for _parameter in command.call_parameters: >+ parameters.append("%s in_%s" % (_parameter.type.in_parameter_type(_parameter.is_optional), _parameter.parameter_name)) >+ >+ for _parameter in command.return_parameters: >+ optional_prefix = 'opt_' if _parameter.is_optional else '' >+ parameters.append("%s %sout_%s" % (_parameter.type.out_parameter_type(_parameter.is_optional), optional_prefix, _parameter.parameter_name)) >+ >+ command_args = { >+ 'commandName': command.command_name, >+ 'parameters': ", ".join(parameters) >+ } >+ return " virtual void %(commandName)s(%(parameters)s) = 0;" % command_args >+ >+ def generate_async_handler_command(self, command): >+ callbackName = "%sCallback" % ucfirst(command.command_name) >+ >+ in_parameters = ['ErrorString*'] >+ for _parameter in command.call_parameters: >+ in_parameters.append("%s in_%s" % (_parameter.type.in_parameter_type(_parameter.is_optional), _parameter.parameter_name)) >+ in_parameters.append("PassRefPtr<%s> callback" % callbackName) >+ >+ out_parameters = [] >+ for _parameter in command.return_parameters: >+ optional_prefix = 'opt_' if _parameter.is_optional else '' >+ out_parameters.append("%s %s%s" % (_parameter.type.in_parameter_type(_parameter.is_optional), optional_prefix, _parameter.parameter_name)) >+ >+ command_args = { >+ 'callbackName': callbackName, >+ 'commandName': command.command_name, >+ 'inParameters': ", ".join(in_parameters), >+ 'outParameters': ", ".join(out_parameters), >+ } >+ >+ return Template(Templates.DispatchHeaderAsyncCommandDeclaration).substitute(None, **command_args) >+ >+ def generate_domain_dispatcher(self, domain): >+ lines = [] >+ domain_guard = Generator.cpp_guard_for_domain(domain) >+ if domain_guard is not None: >+ lines.append("#if %s" % domain_guard) >+ >+ classComponents = ['class'] >+ exportMacro = self.model().framework.setting('export_macro', None) >+ if exportMacro is not None: >+ classComponents.append(exportMacro) >+ >+ declarations = [] >+ if len(domain.commands) > 0: >+ declarations.append('private:') >+ declarations.extend([self.generate_dispatcher_command(command) for command in domain.commands]) >+ >+ handler_args = { >+ 'classAndExportMacro': " ".join(classComponents), >+ 'domainName': domain.domain_name, >+ 'commandDeclarations': "\n".join(declarations) >+ } >+ >+ lines.append(Template(Templates.DispatchHeaderDomainDispatcherDeclaration).substitute(None, **handler_args)) >+ if domain_guard is not None: >+ lines.append("#endif // %s" % domain_guard) >+ return "\n".join(lines) >+ >+ def generate_dispatcher_command(self, command): >+ return " void %s(long callId, const Inspector::InspectorObject& message);" % command.command_name >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generator.py b/Source/JavaScriptCore/inspector/scripts/codegen/generator.py >new file mode 100644 >index 0000000000000000000000000000000000000000..4fa72d0d3f8ffc1b5c80c059dd8a453d3665624c >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generator.py >@@ -0,0 +1,79 @@ >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+ >+class Generator: >+ def __init__(self, model, input_filepath, output_prefix): >+ self._model = model >+ self._input_filepath = input_filepath >+ self._output_prefix = output_prefix >+ >+ def model(self): >+ return self._model >+ >+ def write_output_files(self, _dir, force=False): >+ pass >+ >+ # FIXME: This should be converted into a property on the domain in JSON. >+ @staticmethod >+ def cpp_guard_for_domain(domain): >+ overrides = { >+ 'Database': "ENABLE(SQL_DATABASE)", >+ 'IndexedDB': "ENABLE(INDEXED_DATABASE)", >+ 'WebReplay': "ENABLE(WEB_REPLAY)", >+ } >+ >+ return overrides.get(domain.domain_name, None) >+ >+class DummyGenerator(Generator): >+ pass >+ >+ >+# A writer that only updates file if it actually changed. >+class IncrementalFileWriter: >+ def __init__(self, filepath, force_output): >+ self._filepath = filepath >+ self._output = "" >+ self.force_output = force_output >+ >+ def write(self, text): >+ self._output += text >+ >+ def close(self): >+ text_changed = True >+ self._output = self._output.rstrip() + "\n" >+ >+ try: >+ read_file = open(self._filepath, "r") >+ old_text = read_file.read() >+ read_file.close() >+ text_changed = old_text != self._output >+ except: >+ # Ignore, just overwrite by default >+ pass >+ >+ if text_changed or self.force_output: >+ out_file = open(self._filepath, "w") >+ out_file.write(self._output) >+ out_file.close() >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py b/Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py >new file mode 100644 >index 0000000000000000000000000000000000000000..0f40106eb0ed0e8407e10c88e68ed2374bae8cc4 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py >@@ -0,0 +1,107 @@ >+#!/usr/bin/env python >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+# Generator templates, which can be filled with string.Template. >+# Following are classes that fill the templates from the typechecked model. >+ >+ >+class GeneratorTemplates: >+ CopyrightBlock = ( >+ """/* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+// DO NOT EDIT THIS FILE. It is automatically generated from ${inputFilename} >+// by the script: JavaScriptCore/replay/scripts/CodeGeneratorInspector.py""") >+ >+ DispatcherHeaderPrelude = ( >+ """#ifndef ${headerGuardString} >+#define ${headerGuardString} >+ >+#if ENABLE(INSPECTOR) >+ >+#include "Inspector${frameworkPrefix}TypeBuilders.h" >+#include <inspector/InspectorBackendDispatcher.h> >+#include <wtf/PassRefPtr.h> >+#include <wtf/text/WTFString.h> >+ >+namespace Inspector { >+ >+typedef String ErrorString;""") >+ >+ DispatcherHeaderPostlude = ( >+ """}// namespace Inspector >+ >+#endif // ENABLE(INSPECTOR) >+ >+#endif // !defined(${headerGuardString})""") >+ >+ DispatchHeaderDomainHandlerDeclaration = ( >+ """${classAndExportMacro} Inspector${domainName}BackendDispatcherHandler { >+public: >+${commandDeclarations} >+protected: >+ virtual ~Inspector${domainName}BackendDispatcherHandler(); >+};""") >+ >+ DispatchHeaderDomainDispatcherDeclaration = ( >+ """${classAndExportMacro} Inspector${domainName}BackendDispatcher final : public Inspector::InspectorSupplementalBackendDispatcher { >+public: >+ static PassRefPtr<Inspector${domainName}BackendDispatcher> create(Inspector::InspectorBackendDispatcher*, Inspector${domainName}BackendDispatcherHandler*); >+ virtual void dispatch(long callId, const String& method, PassRefPtr<Inspector::InspectorObject> message) override; >+${commandDeclarations} >+private: >+ Inspector${domainName}BackendDispatcher(Inspector::InspectorBackendDispatcher*, Inspector${domainName}BackendDispatcherHandler*); >+ Inspector${domainName}BackendDispatcherHandler* m_agent; >+};""") >+ >+ DispatchHeaderAsyncCommandDeclaration = ( >+ """ class ${callbackName} : public Inspector::InspectorBackendDispatcher::CallbackBase { >+ public: >+ ${callbackName}(PassRefPtr<Inspector::InspectorBackendDispatcher>, int id); >+ void sendSuccess(${outParameters}); >+ }; >+ virtual void ${commandName}(${inParameters}) = 0;""") >diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/models.py b/Source/JavaScriptCore/inspector/scripts/codegen/models.py >new file mode 100644 >index 0000000000000000000000000000000000000000..8753d703c2c811013a1df0c352c99ee16eea5c88 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/codegen/models.py >@@ -0,0 +1,665 @@ >+#!/usr/bin/env python >+# >+# Copyright (c) 2014 Apple Inc. All rights reserved. >+# Copyright (c) 2014 University of Washington. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+import logging >+ >+# Use a global logger, which normally only logs errors. >+# It can be configured to log debug messages from the CLI. >+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) >+log = logging.getLogger('global') >+ >+ >+_FRAMEWORK_CONFIG_MAP = { >+ "Global": { >+ "prefix": "", >+ }, >+ >+ "WTF": { >+ "prefix": "WTF", >+ }, >+ "JavaScriptCore": { >+ "prefix": "JS", >+ "export_macro": "JS_EXPORT_PRIVATE" >+ }, >+ "WebCore": { >+ "prefix": "Web", >+ }, >+ # Used for code generator tests. >+ "Test": { >+ "prefix": "Test", >+ } >+} >+ >+class ParseException(Exception): >+ pass >+ >+ >+class TypecheckException(Exception): >+ pass >+ >+ >+class Framework: >+ def __init__(self, name): >+ self._settings = _FRAMEWORK_CONFIG_MAP[name] >+ self.name = name >+ >+ def setting(self, key, default=''): >+ return self._settings.get(key, default) >+ >+ @staticmethod >+ def fromString(frameworkString): >+ if frameworkString == "Global": >+ return Frameworks.Global >+ >+ if frameworkString == "WTF": >+ return Frameworks.WTF >+ >+ if frameworkString == "JavaScriptCore": >+ return Frameworks.JavaScriptCore >+ >+ if frameworkString == "WebCore": >+ return Frameworks.WebCore >+ >+ if frameworkString == "Test": >+ return Frameworks.Test >+ >+ raise ParseException("Unknown framework: %s" % frameworkString) >+ >+ >+class Frameworks: >+ Global = Framework("Global") >+ WTF = Framework("WTF") >+ JavaScriptCore = Framework("JavaScriptCore") >+ WebCore = Framework("WebCore") >+ Test = Framework("Test") >+ >+ >+class TypeMode: >+ def __init__(self, name): >+ self._name = name >+ >+ @staticmethod >+ def fromString(modeString): >+ modeString = modeString.upper() >+ if modeString == 'SCALAR': >+ return TypeModes.SCALAR >+ if modeString == 'HEAVY_SCALAR': >+ return TypeModes.HEAVY_SCALAR >+ if modeString == 'UNIQUE': >+ return TypeModes.UNIQUE >+ if modeString == 'REFCOUNTED': >+ return TypeModes.REFCOUNTED >+ if modeString == 'VECTOR': >+ return TypeModes.VECTOR >+ >+ raise ParseException("Unknown type mode: " + modeString) >+ >+ >+class TypeModes: >+ # Copy for assignment and for getter >+ SCALAR = TypeMode("SCALAR") >+ # Copy for assignment, pass by reference for getter >+ HEAVY_SCALAR = TypeMode("HEAVY_SCALAR") >+ # Move for assignment, pass by reference for getter >+ UNIQUE = TypeMode("UNIQUE") >+ # Copy a RefPtr for assignment and getter >+ REFCOUNTED = TypeMode("REFCOUNTED") >+ # Move operator for assignment, pass by reference for getter >+ VECTOR = TypeMode("VECTOR") >+ >+ >+class TypeReference: >+ def __init__(self, type_kind, referenced_type_name, enum_values, array_items): >+ self.type_kind = type_kind >+ self.referenced_type_name = referenced_type_name >+ self.enum_values = enum_values >+ if array_items is None: >+ self.array_type_ref = None >+ else: >+ self.array_type_ref = TypeReference(array_items.get('type'), array_items.get('$ref'), array_items.get('enum', []), array_items.get('items')) >+ >+ if type_kind is not None and referenced_type_name is not None: >+ raise ParseException("Type reference cannot have both 'type' and '$ref' keys.") >+ >+ if type_kind == "array" and array_items is None: >+ raise ParseException("Type reference with type 'array' must have key 'items' to define array element type.") >+ >+ def referenced_name(self): >+ if self.referenced_type_name is not None: >+ return self.referenced_type_name >+ else: >+ return self.type_kind # integer, string, number, boolean, enum, object, array >+ >+ >+class Type: >+ def __init__(self): >+ pass >+ >+ def __eq__(self, other): >+ return self.qualified_name() == other.qualified_name() and self.type_mode() == other.type_mode() >+ >+ def __hash__(self): >+ return self.qualified_name().__hash__() >+ >+ # These methods should be overridden by subclasses. >+ def is_enum(self): >+ return False >+ >+ def type_domain(self): >+ pass >+ >+ def type_mode(self): >+ pass >+ >+ def qualified_name(self): >+ pass >+ >+ # This is used to resolve nested types after instances are created. >+ def resolve_type_references(self, protocol): >+ pass >+ >+ # Methods below are generator-related. >+ def in_parameter_type(self, is_optional): >+ pass >+ >+ def out_parameter_type(self, is_optional): >+ pass >+ >+ def type_builder_type(self): >+ pass >+ >+ >+class ObjectType(Type): >+ def __init__(self, name, domain, members): >+ self._name = name >+ self._domain = domain >+ self._members = members >+ >+ def type_domain(self): >+ return self._domain >+ >+ def type_mode(self): >+ return TypeModes.REFCOUNTED >+ >+ def qualified_name(self): >+ return ".".join([self.type_domain().domain_name, self._name]) >+ >+ def resolve_type_references(self, protocol): >+ pass >+ >+ def in_parameter_type(self, is_optional): >+ if is_optional: >+ return "const RefPtr<Inspector::InspectorObject>*" >+ else: >+ return "const RefPtr<Inspector::InspectorObject>&" >+ >+ def out_parameter_type(self, is_optional): >+ return "RefPtr<%s>&" % self.type_builder_type() >+ >+ def type_builder_type(self): >+ return "Inspector::TypeBuilder::%s::%s" % (self.type_domain().domain_name, self._name) >+ >+ >+class PrimitiveType(Type): >+ def __init__(self, name, mode): >+ self._name = name >+ self._mode = mode >+ >+ def type_domain(self): >+ return None >+ >+ def type_mode(self): >+ return self._mode >+ >+ def qualified_name(self): >+ return self._name >+ >+ def in_parameter_type(self, is_optional): >+ if is_optional: >+ return "const %s*" % self.cpp_primitive_name() >+ elif self.type_mode() is TypeModes.HEAVY_SCALAR: >+ return "const %s&" % self.cpp_primitive_name() >+ else: >+ return self.cpp_primitive_name() >+ >+ def out_parameter_type(self, is_optional): >+ if is_optional: >+ return "Inspector::TypeBuilder::OptOutput<%s>*" % self.cpp_primitive_name() >+ else: >+ return "%s*" % self.cpp_primitive_name() >+ >+ def type_builder_type(self): >+ return self.cpp_primitive_name() >+ >+ def cpp_primitive_name(self): >+ mapping = { >+ 'boolean': 'bool', >+ 'integer': 'int', >+ 'number': 'double', >+ 'string': 'String', >+ 'object': 'InspectorObject', >+ 'any': 'InspectorObject' >+ } >+ return mapping[self._name] >+ >+ >+class AliasedType(Type): >+ def __init__(self, name, domain, aliased_type_ref): >+ self._name = name >+ self._domain = domain >+ self._aliased_type_ref = aliased_type_ref >+ self._aliased_type = None >+ >+ def type_domain(self): >+ return self._domain >+ >+ def type_mode(self): >+ return self._aliased_type.type_mode() >+ >+ def qualified_name(self): >+ return ".".join([self.type_domain().domain_name, self._name]) >+ >+ def resolve_type_references(self, protocol): >+ if self._aliased_type is not None: >+ return >+ >+ self._aliased_type = protocol.lookup_type_reference(self._aliased_type_ref, self.type_domain()) >+ log.debug("< Resolved type reference for aliased type in %s: %s" % (self.qualified_name(), self._aliased_type.qualified_name())) >+ >+ def in_parameter_type(self, is_optional): >+ return self._aliased_type.in_parameter_type(is_optional) >+ >+ def out_parameter_type(self, is_optional): >+ return "%s*" % self.type_builder_type() >+ >+ def type_builder_type(self): >+ return "Inspector::TypeBuilder::%s::%s" % (self._domain.domain_name, self._name) >+ >+ >+class EnumType(Type): >+ def __init__(self, name, domain, values, primitive_type_ref): >+ self._name = name >+ self._domain = domain >+ self._values = values >+ self._primitive_type_ref = primitive_type_ref >+ self._primitive_type = None >+ >+ def is_enum(self): >+ return True >+ >+ def type_domain(self): >+ return self._domain >+ >+ def type_mode(self): >+ return self._primitive_type.type_mode() >+ >+ def enum_values(self): >+ return self._values >+ >+ def qualified_name(self): >+ return ".".join([self.type_domain().domain_name, self._name]) >+ >+ def resolve_type_references(self, protocol): >+ if self._primitive_type is not None: >+ return >+ >+ self._primitive_type = protocol.lookup_type_reference(self._primitive_type_ref, Domains.GLOBAL) >+ log.debug("< Resolved type reference for enum type in %s: %s" % (self.qualified_name(), self._primitive_type.qualified_name())) >+ log.debug("<< enum values: %s" % self._values) >+ >+ def in_parameter_type(self, is_optional): >+ return self._primitive_type.in_parameter_type(is_optional) >+ >+ def out_parameter_type(self, is_optional): >+ return self.type_builder_type() + "*" >+ >+ def type_builder_type(self): >+ return "Inspector::TypeBuilder::%s::%s::Enum" % (self._domain.domain_name, self._name) >+ >+ >+class VectorType(Type): >+ def __init__(self, element_type_ref, domain): >+ self._domain = domain >+ self._element_type_ref = element_type_ref >+ self._element_type = None >+ >+ def type_domain(self): >+ return self._domain >+ >+ def type_mode(self): >+ return TypeModes.VECTOR >+ >+ def qualified_name(self): >+ return ".".join(["vector", self._element_type.qualified_name()]) >+ >+ def resolve_type_references(self, protocol): >+ if self._element_type is not None: >+ return >+ >+ self._element_type = protocol.lookup_type_reference(self._element_type_ref, self.type_domain()) >+ log.debug("< Resolved type reference for element type in %s: %s" % (self.qualified_name(), self._element_type.qualified_name())) >+ >+ def in_parameter_type(self, is_optional): >+ if is_optional: >+ return "const RefPtr<Inspector::InspectorArray>*" >+ else: >+ return "const RefPtr<Inspector::InspectorArray>&" >+ >+ def out_parameter_type(self, is_optional): >+ return "RefPtr<%s>&" % self.type_builder_type() >+ >+ def type_builder_type(self): >+ return "Inspector::TypeBuilder::Array<%s>" % self._element_type.type_builder_type() >+ >+ >+def check_for_required_properties(props, obj, what): >+ for prop in props: >+ if prop not in obj: >+ raise ParseException("When parsing %s, required property missing: %s" % (what, prop)) >+ >+ >+class Protocol: >+ def __init__(self, framework_name): >+ self.domains = [] >+ self.types_by_name = {} >+ self.framework = Framework.fromString(framework_name) >+ >+ def parse_specification(self, json, isSupplemental): >+ log.debug("parse toplevel") >+ >+ if isinstance(json, dict) and 'domains' in json: >+ json = json['domains'] >+ if not isinstance(json, list): >+ json = [json] >+ >+ for domain in json: >+ self.parse_domain(domain, isSupplemental) >+ >+ def parse_domain(self, json, isSupplemental): >+ check_for_required_properties(['domain'], json, "domain") >+ log.debug("parse domain " + json['domain']) >+ >+ types = [] >+ commands = [] >+ events = [] >+ >+ if 'types' in json: >+ if not isinstance(json['types'], list): >+ raise ParseException("Malformed specification: types is not an array") >+ types.extend([self.parse_type_declaration(_declaration) for _declaration in json['types']]) >+ >+ if 'commands' in json: >+ if not isinstance(json['commands'], list): >+ raise ParseException("Malformed specification: commands is not an array") >+ commands.extend([self.parse_command(_command) for _command in json['commands']]) >+ >+ if 'events' in json: >+ if not isinstance(json['events'], list): >+ raise ParseException("Malformed specification: events is not an array") >+ events.extend([self.parse_event(_event) for _event in json['events']]) >+ >+ self.domains.append(Domain(json['domain'], json.get('description', ""), isSupplemental, types, commands, events)) >+ >+ def parse_type_declaration(self, json): >+ check_for_required_properties(['id', 'type'], json, "type") >+ log.debug("parse type %s" % json['id']) >+ >+ type_members = [] >+ >+ if 'properties' in json: >+ if not isinstance(json['properties'], list): >+ raise ParseException("Malformed specification: properties is not an array") >+ type_members.extend([self.parse_type_member(_member) for _member in json['properties']]) >+ >+ type_ref = TypeReference(json['type'], None, json.get('enum', []), json.get('items')) >+ return TypeDeclaration(json['id'], type_ref, json.get("description", ""), type_members) >+ >+ def parse_type_member(self, json): >+ check_for_required_properties(['name'], json, "type member") >+ log.debug("parse type member %s" % json['name']) >+ >+ type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum', []), json.get('items')) >+ return TypeMember(json['name'], type_ref, json.get('optional', False), json.get('description', "")) >+ >+ def parse_command(self, json): >+ check_for_required_properties(['name'], json, "command") >+ log.debug("parse command %s" % json['name']) >+ >+ call_parameters = [] >+ return_parameters = [] >+ >+ if 'parameters' in json: >+ if not isinstance(json['parameters'], list): >+ raise ParseException("Malformed specification: parameters is not an array") >+ call_parameters.extend([self.parse_parameter(_parameter) for _parameter in json['parameters']]) >+ >+ if 'returns' in json: >+ if not isinstance(json['returns'], list): >+ raise ParseException("Malformed specification: returns is not an array") >+ return_parameters.extend([self.parse_parameter(_parameter) for _parameter in json['returns']]) >+ >+ return Command(json['name'], call_parameters, return_parameters, json.get('description', ""), json.get('async', False)) >+ >+ def parse_event(self, json): >+ check_for_required_properties(['name'], json, "event") >+ log.debug("parse event %s" % json['name']) >+ >+ event_parameters = [] >+ >+ if 'parameters' in json: >+ if not isinstance(json['parameters'], list): >+ raise ParseException("Malformed specification: parameters is not an array") >+ event_parameters.extend([self.parse_parameter(_parameter) for _parameter in json['parameters']]) >+ >+ return Event(json['name'], event_parameters, json.get('description', "")) >+ >+ def parse_parameter(self, json): >+ check_for_required_properties(['name'], json, "parameter") >+ log.debug("parse parameter %s" % json['name']) >+ >+ type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum', []), json.get('items')) >+ return Parameter(json['name'], type_ref, json.get('optional', False), json.get('description', "")) >+ >+ def resolve_types(self): >+ qualified_declared_type_names = set(['boolean', 'string', 'integer', 'number', 'enum', 'array', 'object', 'any']) >+ >+ self.types_by_name['string'] = PrimitiveType('string', TypeModes.HEAVY_SCALAR) >+ for _primitive_type in ['boolean', 'integer', 'number']: >+ self.types_by_name[_primitive_type] = PrimitiveType(_primitive_type, TypeModes.SCALAR) >+ for _object_type in ['any', 'object']: >+ self.types_by_name[_object_type] = PrimitiveType(_object_type, TypeModes.REFCOUNTED) >+ >+ # Gather qualified type names from type declarations in each domain. >+ for _domain in self.domains: >+ for _declaration in _domain.type_declarations: >+ # Basic sanity checking. >+ if _declaration.type_ref.referenced_type_name is not None: >+ raise TypecheckException("Type declarations must name a base type, not a type reference.") >+ >+ # Find duplicate qualified type names. >+ qualified_type_name = ".".join([_domain.domain_name, _declaration.type_name]) >+ if qualified_type_name in qualified_declared_type_names: >+ raise TypecheckException("Duplicate type declaration: %s" % qualified_type_name) >+ >+ qualified_declared_type_names.add(qualified_type_name) >+ >+ type_instance = None >+ >+ kind = _declaration.type_ref.type_kind >+ if len(_declaration.type_ref.enum_values) > 0: >+ primitive_type_ref = TypeReference(_declaration.type_ref.type_kind, None, [], None) >+ type_instance = EnumType(_declaration.type_name, _domain, _declaration.type_ref.enum_values, primitive_type_ref) >+ elif kind == "array": >+ type_instance = VectorType(_declaration.type_ref.array_type_ref, _domain) >+ elif kind == "object": >+ type_instance = ObjectType(_declaration.type_name, _domain, _declaration.type_members) >+ else: >+ type_instance = AliasedType(_declaration.type_name, _domain, _declaration.type_ref) >+ >+ self.types_by_name[qualified_type_name] = type_instance >+ >+ # Resolve all type references recursively. >+ for _domain in self.domains: >+ _domain.resolve_type_references(self) >+ >+ def lookup_type_for_declaration(self, declaration, domain): >+ # This will only match a type defined in the same domain, where prefixes aren't required. >+ qualified_name = ".".join([domain.domain_name, declaration.type_name]) >+ if qualified_name in self.types_by_name: >+ found_type = self.types_by_name[qualified_name] >+ found_type.resolve_type_references(self) >+ return found_type >+ >+ raise TypecheckException("Lookup failed for type declaration: %s (referenced from domain: %s)" % (declaration.type_name, domain.domain_name)) >+ >+ def lookup_type_reference(self, type_ref, domain): >+ # If reference is to an anonymous array type, create a fresh instance. >+ if type_ref.type_kind == "array": >+ type_instance = VectorType(type_ref.array_type_ref, domain) >+ type_instance.resolve_type_references(self) >+ log.debug("< Created fresh type instance for anonymous array type: %s" % type_instance.qualified_name()) >+ return type_instance >+ >+ # If reference is to an anonymous enum type, create a fresh instance. >+ if len(type_ref.enum_values) > 0: >+ # We need to create a type reference without enum values as the enum's nested type. >+ primitive_type_ref = TypeReference(type_ref.type_kind, None, [], None) >+ type_instance = EnumType("(anonymous)", domain, type_ref.enum_values, primitive_type_ref) >+ type_instance.resolve_type_references(self) >+ log.debug("< Created fresh type instance for anonymous enum type: %s" % type_instance.qualified_name()) >+ return type_instance >+ >+ # This will match when referencing a type defined in the same domain, where prefixes aren't required. >+ qualified_name = ".".join([domain.domain_name, type_ref.referenced_name()]) >+ if qualified_name in self.types_by_name: >+ found_type = self.types_by_name[qualified_name] >+ found_type.resolve_type_references(self) >+ log.debug("< Lookup succeeded for unqualified type: %s" % found_type.qualified_name()) >+ return found_type >+ >+ # This will match primitive types and fully-qualified types from a different domain. >+ if type_ref.referenced_name() in self.types_by_name: >+ found_type = self.types_by_name[type_ref.referenced_name()] >+ found_type.resolve_type_references(self) >+ log.debug("< Lookup succeeded for primitive or qualified type: %s" % found_type.qualified_name()) >+ return found_type >+ >+ raise TypecheckException("Lookup failed for type reference: %s (referenced from domain: %s)" % (type_ref.referenced_name(), domain.domain_name)) >+ >+ >+class Domain: >+ def __init__(self, domain_name, description, isSupplemental, type_declarations, commands, events): >+ self.domain_name = domain_name >+ self.description = description >+ self.is_supplemental = isSupplemental >+ self.type_declarations = type_declarations >+ self.commands = commands >+ self.events = events >+ >+ def resolve_type_references(self, protocol): >+ log.debug("> Resolving type declarations for domain: %s" % self.domain_name) >+ for _declaration in self.type_declarations: >+ _declaration.resolve_type_references(protocol, self) >+ >+ log.debug("> Resolving types in commands for domain: %s" % self.domain_name) >+ for _command in self.commands: >+ _command.resolve_type_references(protocol, self) >+ >+ log.debug("> Resolving types in events for domain: %s" % self.domain_name) >+ for _event in self.events: >+ _event.resolve_type_references(protocol, self) >+ >+ >+class Domains: >+ GLOBAL = Domain("", "The global domain, in which primitive types are implicitly declared.", True, [], [], []) >+ >+ >+class TypeDeclaration: >+ def __init__(self, type_name, type_ref, description, type_members): >+ self.type_name = type_name >+ self.type_ref = type_ref >+ self.description = description >+ self.type_members = type_members >+ >+ def resolve_type_references(self, protocol, domain): >+ log.debug(">> Resolving type references for type declaration: %s" % self.type_name) >+ self.type = protocol.lookup_type_for_declaration(self, domain) >+ for _member in self.type_members: >+ _member.resolve_type_references(protocol, domain) >+ >+ >+class TypeMember: >+ def __init__(self, member_name, type_ref, is_optional, description): >+ self.member_name = member_name >+ self.type_ref = type_ref >+ self.is_optional = is_optional >+ self.description = description >+ >+ def resolve_type_references(self, protocol, domain): >+ log.debug(">>> Resolving type references for type member: %s" % self.member_name) >+ self.type = protocol.lookup_type_reference(self.type_ref, domain) >+ >+ >+class Parameter: >+ def __init__(self, parameter_name, type_ref, is_optional, description): >+ self.parameter_name = parameter_name >+ self.type_ref = type_ref >+ self.is_optional = is_optional >+ self.description = description >+ >+ def resolve_type_references(self, protocol, domain): >+ log.debug(">>> Resolving type references for parameter: %s" % self.parameter_name) >+ self.type = protocol.lookup_type_reference(self.type_ref, domain) >+ >+ >+class Command: >+ def __init__(self, command_name, call_parameters, return_parameters, description, is_async): >+ self.command_name = command_name >+ self.call_parameters = call_parameters >+ self.return_parameters = return_parameters >+ self.description = description >+ self.is_async = is_async >+ >+ def resolve_type_references(self, protocol, domain): >+ log.debug(">> Resolving type references for call parameters in command: %s" % self.command_name) >+ for _parameter in self.call_parameters: >+ _parameter.resolve_type_references(protocol, domain) >+ >+ log.debug(">> Resolving type references for return parameters in command: %s" % self.command_name) >+ for _parameter in self.return_parameters: >+ _parameter.resolve_type_references(protocol, domain) >+ >+ >+class Event: >+ def __init__(self, event_name, event_parameters, description): >+ self.event_name = event_name >+ self.event_parameters = event_parameters >+ self.description = description >+ >+ def resolve_type_references(self, protocol, domain): >+ log.debug(">> Resolving type references for parameters in event: %s" % self.event_name) >+ for _parameter in self.event_parameters: >+ _parameter.resolve_type_references(protocol, domain) >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-duplicate-type-declarations.json-error b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-duplicate-type-declarations.json-error >new file mode 100644 >index 0000000000000000000000000000000000000000..447cdf8e28e856610a26f8154943f36cf8b7d1f4 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-duplicate-type-declarations.json-error >@@ -0,0 +1 @@ >+ERROR: Duplicate type declaration: Runtime.RemoteObjectId >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-type-declaration-using-type-reference.json-error b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-type-declaration-using-type-reference.json-error >new file mode 100644 >index 0000000000000000000000000000000000000000..42f5753a4396144eb566c5c5968d049aec6182db >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-type-declaration-using-type-reference.json-error >@@ -0,0 +1 @@ >+ERROR: Type reference cannot have both 'type' and '$ref' keys. >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-declaration.json-error b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-declaration.json-error >new file mode 100644 >index 0000000000000000000000000000000000000000..d3c782d89db565d724e7540e32edcfdbd79a2f73 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-declaration.json-error >@@ -0,0 +1 @@ >+ERROR: Lookup failed for type reference: dragon (referenced from domain: Runtime) >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-member.json-error b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-member.json-error >new file mode 100644 >index 0000000000000000000000000000000000000000..52cb65b3a47f29276241cfd014bd6ce4ead8d42f >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-member.json-error >@@ -0,0 +1 @@ >+ERROR: Referenced type name Color does not match any type declarations. >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/expected/same-type-id-different-domain.json-error b/Source/JavaScriptCore/inspector/scripts/tests/expected/same-type-id-different-domain.json-error >new file mode 100644 >index 0000000000000000000000000000000000000000..b1304f3dbc178d56f255cb3b7c9f086f79956a06 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/expected/same-type-id-different-domain.json-error >@@ -0,0 +1 @@ >+ERROR: When parsing domain, required property missing: domain >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/fail-on-duplicate-type-declarations.json b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-duplicate-type-declarations.json >new file mode 100644 >index 0000000000000000000000000000000000000000..702fc6a3270a646a450447fdc04013995a942bf0 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-duplicate-type-declarations.json >@@ -0,0 +1,15 @@ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "string", >+ "description": "Unique object identifier." >+ }, >+ { >+ "id": "RemoteObjectId", >+ "type": "string", >+ "description": "Unique object identifier." >+ } >+ ] >+} >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json >new file mode 100644 >index 0000000000000000000000000000000000000000..19b7590ccc6f6bc3443a4a283ca6fccfdf327734 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json >@@ -0,0 +1,13 @@ >+[ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "object", >+ "$ref": "SomeType", >+ "description": "Unique object identifier." >+ } >+ ] >+} >+] >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json >new file mode 100644 >index 0000000000000000000000000000000000000000..d6887a27411900a80d50f003eac36c13a99fae58 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json >@@ -0,0 +1,12 @@ >+[ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "dragon", >+ "description": "Unique object identifier." >+ } >+ ] >+} >+] >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json >new file mode 100644 >index 0000000000000000000000000000000000000000..b817db5044dc1f28557008c1f1761f1b068f4ce6 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json >@@ -0,0 +1,15 @@ >+[ >+{ >+ "domain": "Fantasy", >+ "types": [ >+ { >+ "id": "DragonEgg", >+ "type": "object", >+ "description": "A dragon egg.", >+ "properties": [ >+ { "name": "color", "$ref": "Color" } >+ ] >+ } >+ ] >+} >+] >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/same-type-id-different-domain.json b/Source/JavaScriptCore/inspector/scripts/tests/same-type-id-different-domain.json >new file mode 100644 >index 0000000000000000000000000000000000000000..3bf4dff5ccc29d0e8c1fa4b2dd3283e771632c7d >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/same-type-id-different-domain.json >@@ -0,0 +1,22 @@ >+[ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "string", >+ "description": "Unique object identifier." >+ } >+ ] >+}, >+{ >+ "domain": "Runtime2", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "string", >+ "description": "Unique object identifier." >+ } >+ ] >+} >+] >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-aliased-primitive-type.json b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-aliased-primitive-type.json >new file mode 100644 >index 0000000000000000000000000000000000000000..cbc9d539478db495c96067ecd54a95be52f8d070 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-aliased-primitive-type.json >@@ -0,0 +1,10 @@ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "RemoteObjectId", >+ "type": "integer", >+ "description": "Unique object identifier." >+ } >+ ] >+} >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-array-type.json b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-array-type.json >new file mode 100644 >index 0000000000000000000000000000000000000000..c1677a00211377bcd581ce2875649d3361bbd24b >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-array-type.json >@@ -0,0 +1,40 @@ >+[ >+{ >+ "domain": "Debugger", >+ "types": [ >+ { >+ "id": "BreakpointId", >+ "type": "integer" >+ } >+ ] >+}, >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "LuckyNumbers", >+ "type": "array", >+ "items": { "type": "integer" } >+ }, >+ { >+ "id": "BabyNames", >+ "type": "array", >+ "items": { "type": "string" } >+ }, >+ { >+ "id": "ObjectId", >+ "type": "integer" >+ }, >+ { >+ "id": "NewObjects", >+ "type": "array", >+ "items": { "$ref": "ObjectId" } >+ }, >+ { >+ "id": "OldObjects", >+ "type": "array", >+ "items": { "$ref": "Debugger.BreakpointId" } >+ } >+ ] >+} >+] >diff --git a/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-enum-type.json b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-enum-type.json >new file mode 100644 >index 0000000000000000000000000000000000000000..cc4503d2abbb7e11d17a646d617097cb11ca3011 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/scripts/tests/type-declaration-enum-type.json >@@ -0,0 +1,15 @@ >+{ >+ "domain": "Runtime", >+ "types": [ >+ { >+ "id": "LuckyNumbers", >+ "type": "integer", >+ "enum": [0, 1, 2] >+ }, >+ { >+ "id": "AllowedAnimals", >+ "type": "string", >+ "enum": ["Pigs", "Wolves", "Cats"] >+ } >+ ] >+} >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index f1733d5c3acd6caa84f5c4b7975904d055806af3..d11cd081a69574d08bbd8a45f5b76e31405a1719 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,22 @@ >+2014-04-17 Brian J. Burg <burg@cs.washington.edu> >+ >+ Web Inspector: rewrite CodeGeneratorInspector to be modular and testable >+ https://bugs.webkit.org/show_bug.cgi?id=131596 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Scripts/run-inspector-generator-tests: Added. >+ (main): >+ * Scripts/webkitpy/inspector/__init__.py: Added. >+ * Scripts/webkitpy/inspector/main.py: Added. >+ (InspectorGeneratorTests): >+ (InspectorGeneratorTests.__init__): >+ (InspectorGeneratorTests.generate_from_json): >+ (InspectorGeneratorTests.write_error_file): >+ (InspectorGeneratorTests.detect_changes): >+ (InspectorGeneratorTests.run_tests): >+ (InspectorGeneratorTests.main): >+ > 2014-04-10 Zan Dobersek <zdobersek@igalia.com> > > [CMake] Add missing WTF unit tests >diff --git a/Tools/Scripts/run-inspector-generator-tests b/Tools/Scripts/run-inspector-generator-tests >new file mode 100755 >index 0000000000000000000000000000000000000000..aaab1800bca6f7e8a3496e5918421eeae2d38d82 >--- /dev/null >+++ b/Tools/Scripts/run-inspector-generator-tests >@@ -0,0 +1,42 @@ >+#!/usr/bin/env python >+# Copyright (C) 2014 Apple Inc. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+# THE POSSIBILITY OF SUCH DAMAGE. >+ >+import sys >+from webkitpy.common.system import executive >+ >+def main(argv): >+ """Runs replay input code generator on test specification files and compares >+ the results with reference files. >+ >+ Options: >+ --reset-results: Overwrites the reference files with the generated results. >+ >+ """ >+ reset_results = "--reset-results" in argv >+ >+ from webkitpy.inspector.main import InspectorGeneratorTests >+ return InspectorGeneratorTests(reset_results, executive.Executive()).main() >+ >+if __name__ == '__main__': >+ sys.exit(main(sys.argv)) >diff --git a/Tools/Scripts/webkitpy/inspector/__init__.py b/Tools/Scripts/webkitpy/inspector/__init__.py >new file mode 100644 >index 0000000000000000000000000000000000000000..ef65bee5bb77e96ebc7cd9c47640690fbda8ac19 >--- /dev/null >+++ b/Tools/Scripts/webkitpy/inspector/__init__.py >@@ -0,0 +1 @@ >+# Required for Python to search this directory for module files >diff --git a/Tools/Scripts/webkitpy/inspector/main.py b/Tools/Scripts/webkitpy/inspector/main.py >new file mode 100644 >index 0000000000000000000000000000000000000000..4d5b1e43b002c53a90a95bcccf63f42a5f132452 >--- /dev/null >+++ b/Tools/Scripts/webkitpy/inspector/main.py >@@ -0,0 +1,134 @@ >+# Copyright (C) 2011 Google Inc. All rights reserved. >+# Copyright (C) 2014 Apple Inc. All rights reserved. >+# >+# Redistribution and use in source and binary forms, with or without >+# modification, are permitted provided that the following conditions >+# are met: >+# >+# 1. Redistributions of source code must retain the above copyright >+# notice, this list of conditions and the following disclaimer. >+# 2. Redistributions in binary form must reproduce the above copyright >+# notice, this list of conditions and the following disclaimer in the >+# documentation and/or other materials provided with the distribution. >+# >+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS >+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED >+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A >+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ >+import os >+import os.path >+import shutil >+import sys >+import tempfile >+from webkitpy.common.checkout.scm.detection import detect_scm_system >+from webkitpy.common.system.executive import ScriptError >+ >+ >+class InspectorGeneratorTests: >+ >+ def __init__(self, reset_results, executive): >+ self.reset_results = reset_results >+ self.executive = executive >+ >+ def generate_from_json(self, json_file, output_directory): >+ cmd = ['python', >+ 'JavaScriptCore/inspector/scripts/CodeGeneratorInspector2.py', >+ '--outputDir', output_directory, >+ '--force', >+ '--framework', 'Test', >+ '--test', >+ json_file] >+ >+ exit_code = 0 >+ try: >+ stderr_output = self.executive.run_command(cmd) >+ if stderr_output: >+ self.write_error_file(json_file, output_directory, stderr_output) >+ except ScriptError, e: >+ print e.output >+ exit_code = e.exit_code >+ return exit_code >+ >+ def write_error_file(self, input_filepath, output_directory, error_output): >+ output_filepath = os.path.join(output_directory, os.path.basename(input_filepath) + '-error') >+ >+ with open(output_filepath, "w") as output_file: >+ output_file.write(error_output) >+ >+ def detect_changes(self, work_directory, reference_directory): >+ changes_found = False >+ for output_file in os.listdir(work_directory): >+ cmd = ['diff', >+ '-u', >+ '-N', >+ os.path.join(reference_directory, output_file), >+ os.path.join(work_directory, output_file)] >+ >+ exit_code = 0 >+ try: >+ output = self.executive.run_command(cmd) >+ except ScriptError, e: >+ output = e.output >+ exit_code = e.exit_code >+ >+ if exit_code or output: >+ print 'FAIL: %s' % output_file >+ print output >+ changes_found = True >+ else: >+ print 'PASS: %s' % output_file >+ return changes_found >+ >+ def run_tests(self, input_directory, reference_directory): >+ work_directory = reference_directory >+ >+ passed = True >+ for input_file in os.listdir(input_directory): >+ (name, extension) = os.path.splitext(input_file) >+ if extension != '.json': >+ continue >+ # Generate output into the work directory (either the given one or a >+ # temp one if not reset_results is performed) >+ if not self.reset_results: >+ work_directory = tempfile.mkdtemp() >+ >+ if self.generate_from_json(os.path.join(input_directory, input_file), work_directory): >+ passed = False >+ >+ if self.reset_results: >+ print "Reset results for test: %s" % (input_file) >+ continue >+ >+ # Detect changes >+ if self.detect_changes(work_directory, reference_directory): >+ passed = False >+ shutil.rmtree(work_directory) >+ >+ return passed >+ >+ def main(self): >+ current_scm = detect_scm_system(os.curdir) >+ os.chdir(os.path.join(current_scm.checkout_root, 'Source')) >+ >+ all_tests_passed = True >+ >+ input_directory = os.path.join('JavaScriptCore', 'inspector', 'scripts', 'tests') >+ reference_directory = os.path.join('JavaScriptCore', 'inspector', 'scripts', 'tests', 'expected') >+ if not self.run_tests(input_directory, reference_directory): >+ all_tests_passed = False >+ >+ print '' >+ if all_tests_passed: >+ print 'All tests PASS!' >+ return 0 >+ else: >+ print 'Some tests FAIL! (To update the reference files, execute "run-inspector-generator-tests --reset-results")' >+ return -1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 131596
:
229243
|
229624
|
229774
|
229776
|
229782
|
232019
|
232025
|
232043
|
236385
|
236611
|
236631
|
236640
|
236668