summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/inspector/scripts/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/inspector/scripts/codegen')
-rw-r--r--Source/JavaScriptCore/inspector/scripts/codegen/__init__.py25
-rw-r--r--Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator.py319
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/cpp_generator_templates.py258
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py93
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py217
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py324
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py116
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py125
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_header.py424
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py260
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_js_backend_commands.py145
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py106
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py210
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_header.py85
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_implementation.py147
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py154
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_header.py245
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_internal_header.py74
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_header.py165
-rw-r--r--Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_implementation.py138
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py215
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/generator.py274
-rw-r--r--Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py61
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/models.py680
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/objc_generator.py554
-rwxr-xr-xSource/JavaScriptCore/inspector/scripts/codegen/objc_generator_templates.py155
26 files changed, 5569 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py b/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py
new file mode 100644
index 000000000..37dbe9436
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/__init__.py
@@ -0,0 +1,25 @@
+# Required for Python to search this directory for module files
+
+from models import *
+from generator import *
+from cpp_generator import *
+from objc_generator import *
+
+from generate_cpp_alternate_backend_dispatcher_header import *
+from generate_cpp_backend_dispatcher_header import *
+from generate_cpp_backend_dispatcher_implementation import *
+from generate_cpp_frontend_dispatcher_header import *
+from generate_cpp_frontend_dispatcher_implementation import *
+from generate_cpp_protocol_types_header import *
+from generate_cpp_protocol_types_implementation import *
+from generate_js_backend_commands import *
+from generate_objc_backend_dispatcher_header import *
+from generate_objc_backend_dispatcher_implementation import *
+from generate_objc_configuration_header import *
+from generate_objc_configuration_implementation import *
+from generate_objc_frontend_dispatcher_implementation import *
+from generate_objc_header import *
+from generate_objc_internal_header import *
+from generate_objc_protocol_types_implementation import *
+from generate_objc_protocol_type_conversions_header import *
+from generate_objc_protocol_type_conversions_implementation import *
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator.py b/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator.py
new file mode 100644
index 000000000..c459fcac3
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator.py
@@ -0,0 +1,319 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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
+
+from generator import ucfirst, Generator
+from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks
+
+log = logging.getLogger('global')
+
+_PRIMITIVE_TO_CPP_NAME_MAP = {
+ 'boolean': 'bool',
+ 'integer': 'int',
+ 'number': 'double',
+ 'string': 'String',
+ 'object': 'Inspector::InspectorObject',
+ 'array': 'Inspector::InspectorArray',
+ 'any': 'Inspector::InspectorValue'
+}
+
+class CppGenerator(Generator):
+ def __init__(self, *args, **kwargs):
+ Generator.__init__(self, *args, **kwargs)
+
+ def protocol_name(self):
+ return self.model().framework.setting('cpp_protocol_group', '')
+
+ def helpers_namespace(self):
+ return '%sHelpers' % self.protocol_name()
+
+ # Miscellaneous text manipulation routines.
+ @staticmethod
+ def cpp_getter_method_for_type(_type):
+ if isinstance(_type, ObjectType):
+ return 'getObject'
+ if isinstance(_type, ArrayType):
+ return 'getArray'
+ if isinstance(_type, PrimitiveType):
+ if _type.raw_name() is 'integer':
+ return 'getInteger'
+ elif _type.raw_name() is 'number':
+ return 'getDouble'
+ elif _type.raw_name() is 'any':
+ return 'getValue'
+ else:
+ return 'get' + ucfirst(_type.raw_name())
+ if isinstance(_type, AliasedType):
+ return CppGenerator.cpp_getter_method_for_type(_type.aliased_type)
+ if isinstance(_type, EnumType):
+ return CppGenerator.cpp_getter_method_for_type(_type.primitive_type)
+
+ @staticmethod
+ def cpp_setter_method_for_type(_type):
+ if isinstance(_type, ObjectType):
+ return 'setObject'
+ if isinstance(_type, ArrayType):
+ return 'setArray'
+ if isinstance(_type, PrimitiveType):
+ if _type.raw_name() is 'integer':
+ return 'setInteger'
+ elif _type.raw_name() is 'number':
+ return 'setDouble'
+ elif _type.raw_name() is 'any':
+ return 'setValue'
+ else:
+ return 'set' + ucfirst(_type.raw_name())
+ if isinstance(_type, AliasedType):
+ return CppGenerator.cpp_setter_method_for_type(_type.aliased_type)
+ if isinstance(_type, EnumType):
+ return CppGenerator.cpp_setter_method_for_type(_type.primitive_type)
+
+ # Generate type representations for various situations.
+ @staticmethod
+ def cpp_protocol_type_for_type(_type):
+ if isinstance(_type, ObjectType) and len(_type.members) == 0:
+ return 'Inspector::InspectorObject'
+ if isinstance(_type, ArrayType):
+ if _type.raw_name() is None: # Otherwise, fall through and use typedef'd name.
+ return 'Inspector::Protocol::Array<%s>' % CppGenerator.cpp_protocol_type_for_type(_type.element_type)
+ if isinstance(_type, (ObjectType, AliasedType, EnumType, ArrayType)):
+ return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name())
+ if isinstance(_type, PrimitiveType):
+ return CppGenerator.cpp_name_for_primitive_type(_type)
+
+ @staticmethod
+ def cpp_protocol_type_for_type_member(type_member, object_declaration):
+ if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous:
+ return '::'.join([CppGenerator.cpp_protocol_type_for_type(object_declaration.type), ucfirst(type_member.member_name)])
+ else:
+ return CppGenerator.cpp_protocol_type_for_type(type_member.type)
+
+ @staticmethod
+ def cpp_type_for_unchecked_formal_in_parameter(parameter):
+ _type = parameter.type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through to enum or primitive.
+
+ if isinstance(_type, EnumType):
+ _type = _type.primitive_type # Fall through to primitive.
+
+ # This handles the 'any' type and objects with defined properties.
+ if isinstance(_type, ObjectType) or _type.qualified_name() is 'object':
+ cpp_name = 'Inspector::InspectorObject'
+ if parameter.is_optional:
+ return 'const %s*' % cpp_name
+ else:
+ return 'const %s&' % cpp_name
+ if isinstance(_type, ArrayType):
+ cpp_name = 'Inspector::InspectorArray'
+ if parameter.is_optional:
+ return 'const %s*' % cpp_name
+ else:
+ return 'const %s&' % cpp_name
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if parameter.is_optional:
+ return 'const %s* const' % cpp_name
+ elif _type.raw_name() in ['string']:
+ return 'const %s&' % cpp_name
+ else:
+ return cpp_name
+
+ return "unknown_unchecked_formal_in_parameter_type"
+
+ @staticmethod
+ def cpp_type_for_checked_formal_event_parameter(parameter):
+ return CppGenerator.cpp_type_for_type_with_name(parameter.type, parameter.parameter_name, parameter.is_optional)
+
+ @staticmethod
+ def cpp_type_for_type_member(member):
+ return CppGenerator.cpp_type_for_type_with_name(member.type, member.member_name, False)
+
+ @staticmethod
+ def cpp_type_for_type_with_name(_type, type_name, is_optional):
+ if isinstance(_type, (ArrayType, ObjectType)):
+ return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type)
+ if isinstance(_type, AliasedType):
+ builder_type = CppGenerator.cpp_protocol_type_for_type(_type)
+ if is_optional:
+ return 'const %s* const' % builder_type
+ elif _type.aliased_type.qualified_name() in ['integer', 'number']:
+ return CppGenerator.cpp_name_for_primitive_type(_type.aliased_type)
+ elif _type.aliased_type.qualified_name() in ['string']:
+ return 'const %s&' % builder_type
+ else:
+ return builder_type
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if _type.qualified_name() in ['object']:
+ return 'RefPtr<Inspector::InspectorObject>'
+ elif _type.qualified_name() in ['any']:
+ return 'RefPtr<Inspector::InspectorValue>'
+ elif is_optional:
+ return 'const %s* const' % cpp_name
+ elif _type.qualified_name() in ['string']:
+ return 'const %s&' % cpp_name
+ else:
+ return cpp_name
+ if isinstance(_type, EnumType):
+ if _type.is_anonymous:
+ enum_type_name = ucfirst(type_name)
+ else:
+ enum_type_name = 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name())
+
+ if is_optional:
+ return '%s*' % enum_type_name
+ else:
+ return '%s' % enum_type_name
+
+ @staticmethod
+ def cpp_type_for_formal_out_parameter(parameter):
+ _type = parameter.type
+
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through.
+
+ if isinstance(_type, (ObjectType, ArrayType)):
+ return 'RefPtr<%s>&' % CppGenerator.cpp_protocol_type_for_type(_type)
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if parameter.is_optional:
+ return "Inspector::Protocol::OptOutput<%s>*" % cpp_name
+ else:
+ return '%s*' % cpp_name
+ if isinstance(_type, EnumType):
+ if _type.is_anonymous:
+ return '%sBackendDispatcherHandler::%s*' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name))
+ else:
+ return 'Inspector::Protocol::%s::%s*' % (_type.type_domain().domain_name, _type.raw_name())
+
+ raise ValueError("unknown formal out parameter type.")
+
+ # FIXME: this is only slightly different from out parameters; they could be unified.
+ @staticmethod
+ def cpp_type_for_formal_async_parameter(parameter):
+ _type = parameter.type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through.
+
+ if isinstance(_type, EnumType):
+ _type = _type.primitive_type # Fall through.
+
+ if isinstance(_type, (ObjectType, ArrayType)):
+ return 'RefPtr<%s>&&' % CppGenerator.cpp_protocol_type_for_type(_type)
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if parameter.is_optional:
+ return "Inspector::Protocol::OptOutput<%s>*" % cpp_name
+ elif _type.qualified_name() in ['integer', 'number']:
+ return CppGenerator.cpp_name_for_primitive_type(_type)
+ elif _type.qualified_name() in ['string']:
+ return 'const %s&' % cpp_name
+ else:
+ return cpp_name
+
+ raise ValueError("Unknown formal async parameter type.")
+
+ # In-parameters don't use builder types, because they could be passed
+ # "open types" that are manually constructed out of InspectorObjects.
+
+ # FIXME: Only parameters that are actually open types should need non-builder parameter types.
+ @staticmethod
+ def cpp_type_for_stack_in_parameter(parameter):
+ _type = parameter.type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through.
+
+ if isinstance(_type, EnumType):
+ _type = _type.primitive_type # Fall through.
+
+ if isinstance(_type, ObjectType):
+ return "RefPtr<Inspector::InspectorObject>"
+ if isinstance(_type, ArrayType):
+ return "RefPtr<Inspector::InspectorArray>"
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if _type.qualified_name() in ['any', 'object']:
+ return "RefPtr<%s>" % CppGenerator.cpp_name_for_primitive_type(_type)
+ elif parameter.is_optional and _type.qualified_name() not in ['boolean', 'string', 'integer']:
+ return "Inspector::Protocol::OptOutput<%s>" % cpp_name
+ else:
+ return cpp_name
+
+ @staticmethod
+ def cpp_type_for_stack_out_parameter(parameter):
+ _type = parameter.type
+ if isinstance(_type, (ArrayType, ObjectType)):
+ return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type)
+ if isinstance(_type, AliasedType):
+ builder_type = CppGenerator.cpp_protocol_type_for_type(_type)
+ if parameter.is_optional:
+ return "Inspector::Protocol::OptOutput<%s>" % builder_type
+ return '%s' % builder_type
+ if isinstance(_type, PrimitiveType):
+ cpp_name = CppGenerator.cpp_name_for_primitive_type(_type)
+ if parameter.is_optional:
+ return "Inspector::Protocol::OptOutput<%s>" % cpp_name
+ else:
+ return cpp_name
+ if isinstance(_type, EnumType):
+ if _type.is_anonymous:
+ return '%sBackendDispatcherHandler::%s' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name))
+ else:
+ return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name())
+
+ @staticmethod
+ def cpp_assertion_method_for_type_member(type_member, object_declaration):
+
+ def assertion_method_for_type(_type):
+ return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type(_type)
+
+ if isinstance(type_member.type, AliasedType):
+ return assertion_method_for_type(type_member.type.aliased_type)
+ if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous:
+ return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type_member(type_member, object_declaration)
+
+ return assertion_method_for_type(type_member.type)
+
+ @staticmethod
+ def cpp_name_for_primitive_type(_type):
+ return _PRIMITIVE_TO_CPP_NAME_MAP.get(_type.raw_name())
+
+ # Decide whether certain helpers are necessary in a situation.
+ @staticmethod
+ def should_use_wrapper_for_return_type(_type):
+ return not isinstance(_type, (ArrayType, ObjectType))
+
+ @staticmethod
+ def should_use_references_for_type(_type):
+ return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() in ["any", "object"])
+
+ @staticmethod
+ def should_pass_by_copy_for_return_type(_type):
+ return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() == "object")
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator_templates.py b/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator_templates.py
new file mode 100755
index 000000000..b2523ffe2
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/cpp_generator_templates.py
@@ -0,0 +1,258 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2015 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 CppGeneratorTemplates:
+
+ HeaderPrelude = (
+ """#pragma once
+
+${includes}
+
+namespace Inspector {
+
+${typedefs}""")
+
+ HeaderPostlude = (
+ """} // namespace Inspector""")
+
+ ImplementationPrelude = (
+ """#include "config.h"
+#include ${primaryInclude}
+
+${secondaryIncludes}
+
+namespace Inspector {""")
+
+ ImplementationPostlude = (
+ """} // namespace Inspector
+""")
+
+ AlternateDispatchersHeaderPrelude = (
+ """#pragma once
+
+#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+
+${includes}
+
+namespace Inspector {
+
+class AlternateBackendDispatcher {
+public:
+ void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTFMove(dispatcher); }
+ BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); }
+private:
+ RefPtr<BackendDispatcher> m_backendDispatcher;
+};
+""")
+
+ AlternateDispatchersHeaderPostlude = (
+ """} // namespace Inspector
+
+#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)""")
+
+ AlternateBackendDispatcherHeaderDomainHandlerInterfaceDeclaration = (
+ """class Alternate${domainName}BackendDispatcher : public AlternateBackendDispatcher {
+public:
+ virtual ~Alternate${domainName}BackendDispatcher() { }
+${commandDeclarations}
+};""")
+
+ BackendDispatcherHeaderDomainHandlerDeclaration = (
+ """${classAndExportMacro} ${domainName}BackendDispatcherHandler {
+public:
+${commandDeclarations}
+protected:
+ virtual ~${domainName}BackendDispatcherHandler();
+};""")
+
+ BackendDispatcherHeaderDomainDispatcherDeclaration = (
+ """${classAndExportMacro} ${domainName}BackendDispatcher final : public SupplementalBackendDispatcher {
+public:
+ static Ref<${domainName}BackendDispatcher> create(BackendDispatcher&, ${domainName}BackendDispatcherHandler*);
+ void dispatch(long requestId, const String& method, Ref<InspectorObject>&& message) override;
+${commandDeclarations}
+private:
+ ${domainName}BackendDispatcher(BackendDispatcher&, ${domainName}BackendDispatcherHandler*);
+ ${domainName}BackendDispatcherHandler* m_agent { nullptr };
+};""")
+
+ BackendDispatcherHeaderDomainDispatcherAlternatesDeclaration = (
+ """#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+public:
+ void setAlternateDispatcher(Alternate${domainName}BackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; }
+private:
+ Alternate${domainName}BackendDispatcher* m_alternateDispatcher { nullptr };
+#endif""")
+
+ BackendDispatcherHeaderAsyncCommandDeclaration = (
+ """ ${classAndExportMacro} ${callbackName} : public BackendDispatcher::CallbackBase {
+ public:
+ ${callbackName}(Ref<BackendDispatcher>&&, int id);
+ void sendSuccess(${outParameters});
+ };
+ virtual void ${commandName}(${inParameters}) = 0;""")
+
+ BackendDispatcherImplementationSmallSwitch = (
+ """void ${domainName}BackendDispatcher::dispatch(long requestId, const String& method, Ref<InspectorObject>&& message)
+{
+ Ref<${domainName}BackendDispatcher> protect(*this);
+
+ RefPtr<InspectorObject> parameters;
+ message->getObject(ASCIILiteral("params"), parameters);
+
+${dispatchCases}
+ else
+ m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, makeString('\\'', "${domainName}", '.', method, "' was not found"));
+}""")
+
+ BackendDispatcherImplementationLargeSwitch = (
+"""void ${domainName}BackendDispatcher::dispatch(long requestId, const String& method, Ref<InspectorObject>&& message)
+{
+ Ref<${domainName}BackendDispatcher> protect(*this);
+
+ RefPtr<InspectorObject> parameters;
+ message->getObject(ASCIILiteral("params"), parameters);
+
+ typedef void (${domainName}BackendDispatcher::*CallHandler)(long requestId, RefPtr<InspectorObject>&& message);
+ typedef HashMap<String, CallHandler> DispatchMap;
+ static NeverDestroyed<DispatchMap> dispatchMap;
+ if (dispatchMap.get().isEmpty()) {
+ static const struct MethodTable {
+ const char* name;
+ CallHandler handler;
+ } commands[] = {
+${dispatchCases}
+ };
+ size_t length = WTF_ARRAY_LENGTH(commands);
+ for (size_t i = 0; i < length; ++i)
+ dispatchMap.get().add(commands[i].name, commands[i].handler);
+ }
+
+ auto findResult = dispatchMap.get().find(method);
+ if (findResult == dispatchMap.get().end()) {
+ m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, makeString('\\'', "${domainName}", '.', method, "' was not found"));
+ return;
+ }
+
+ ((*this).*findResult->value)(requestId, WTFMove(parameters));
+}""")
+
+ BackendDispatcherImplementationDomainConstructor = (
+ """Ref<${domainName}BackendDispatcher> ${domainName}BackendDispatcher::create(BackendDispatcher& backendDispatcher, ${domainName}BackendDispatcherHandler* agent)
+{
+ return adoptRef(*new ${domainName}BackendDispatcher(backendDispatcher, agent));
+}
+
+${domainName}BackendDispatcher::${domainName}BackendDispatcher(BackendDispatcher& backendDispatcher, ${domainName}BackendDispatcherHandler* agent)
+ : SupplementalBackendDispatcher(backendDispatcher)
+ , m_agent(agent)
+{
+ m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("${domainName}"), this);
+}""")
+
+ BackendDispatcherImplementationPrepareCommandArguments = (
+"""${inParameterDeclarations}
+ if (m_backendDispatcher->hasProtocolErrors()) {
+ m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, String::format("Some arguments of method \'%s\' can't be processed", "${domainName}.${commandName}"));
+ return;
+ }
+""")
+
+ BackendDispatcherImplementationAsyncCommand = (
+"""${domainName}BackendDispatcherHandler::${callbackName}::${callbackName}(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }
+
+void ${domainName}BackendDispatcherHandler::${callbackName}::sendSuccess(${formalParameters})
+{
+ Ref<InspectorObject> jsonMessage = InspectorObject::create();
+${outParameterAssignments}
+ CallbackBase::sendSuccess(WTFMove(jsonMessage));
+}""")
+
+ FrontendDispatcherDomainDispatcherDeclaration = (
+"""${classAndExportMacro} ${domainName}FrontendDispatcher {
+public:
+ ${domainName}FrontendDispatcher(FrontendRouter& frontendRouter) : m_frontendRouter(frontendRouter) { }
+${eventDeclarations}
+private:
+ FrontendRouter& m_frontendRouter;
+};""")
+
+ ProtocolObjectBuilderDeclarationPrelude = (
+""" template<int STATE>
+ class Builder {
+ private:
+ RefPtr<InspectorObject> m_result;
+
+ template<int STEP> Builder<STATE | STEP>& castState()
+ {
+ return *reinterpret_cast<Builder<STATE | STEP>*>(this);
+ }
+
+ Builder(Ref</*${objectType}*/InspectorObject>&& object)
+ : m_result(WTFMove(object))
+ {
+ COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state);
+ }
+ friend class ${objectType};
+ public:""")
+
+ ProtocolObjectBuilderDeclarationPostlude = (
+"""
+ Ref<${objectType}> release()
+ {
+ COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready);
+ COMPILE_ASSERT(sizeof(${objectType}) == sizeof(InspectorObject), cannot_cast);
+
+ Ref<InspectorObject> result = m_result.releaseNonNull();
+ return WTFMove(*reinterpret_cast<Ref<${objectType}>*>(&result));
+ }
+ };
+
+ /*
+ * Synthetic constructor:
+${constructorExample}
+ */
+ static Builder<NoFieldsSet> create()
+ {
+ return Builder<NoFieldsSet>(InspectorObject::create());
+ }""")
+
+ ProtocolObjectRuntimeCast = (
+"""RefPtr<${objectType}> BindingTraits<${objectType}>::runtimeCast(RefPtr<InspectorValue>&& value)
+{
+ RefPtr<InspectorObject> result;
+ bool castSucceeded = value->asObject(result);
+ ASSERT_UNUSED(castSucceeded, castSucceeded);
+#if !ASSERT_DISABLED
+ BindingTraits<${objectType}>::assertValueHasExpectedType(result.get());
+#endif // !ASSERT_DISABLED
+ COMPILE_ASSERT(sizeof(${objectType}) == sizeof(InspectorObjectBase), type_cast_problem);
+ return static_cast<${objectType}*>(static_cast<InspectorObjectBase*>(result.get()));
+}
+""")
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py
new file mode 100755
index 000000000..86e864974
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+import re
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+
+log = logging.getLogger('global')
+
+
+class CppAlternateBackendDispatcherHeaderGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sAlternateBackendDispatchers.h' % self.protocol_name()
+
+ def generate_output(self):
+ headers = [
+ '"%sProtocolTypes.h"' % self.protocol_name(),
+ '<inspector/InspectorFrontendRouter.h>',
+ '<JavaScriptCore/InspectorBackendDispatcher.h>',
+ ]
+
+ header_args = {
+ 'includes': '\n'.join(['#include ' + header for header in headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.AlternateDispatchersHeaderPrelude).substitute(None, **header_args))
+ sections.append('\n'.join(filter(None, map(self._generate_handler_declarations_for_domain, domains))))
+ sections.append(Template(CppTemplates.AlternateDispatchersHeaderPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_handler_declarations_for_domain(self, domain):
+ commands = self.commands_for_domain(domain)
+
+ if not len(commands):
+ return ''
+
+ command_declarations = []
+ for command in commands:
+ command_declarations.append(self._generate_handler_declaration_for_command(command))
+
+ handler_args = {
+ 'domainName': domain.domain_name,
+ 'commandDeclarations': '\n'.join(command_declarations),
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.AlternateBackendDispatcherHeaderDomainHandlerInterfaceDeclaration).substitute(None, **handler_args))
+
+ def _generate_handler_declaration_for_command(self, command):
+ lines = []
+ parameters = ['long callId']
+ for _parameter in command.call_parameters:
+ parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), _parameter.parameter_name))
+
+ command_args = {
+ 'commandName': command.command_name,
+ 'parameters': ', '.join(parameters),
+ }
+ lines.append(' virtual void %(commandName)s(%(parameters)s) = 0;' % command_args)
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py
new file mode 100755
index 000000000..992622bdd
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 re
+import string
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import EnumType
+
+log = logging.getLogger('global')
+
+
+class CppBackendDispatcherHeaderGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sBackendDispatchers.h" % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(lambda domain: len(self.commands_for_domain(domain)) > 0, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ headers = [
+ '"%sProtocolObjects.h"' % self.protocol_name(),
+ '<inspector/InspectorBackendDispatcher.h>',
+ '<wtf/text/WTFString.h>']
+
+ typedefs = [('String', 'ErrorString')]
+
+ header_args = {
+ 'includes': '\n'.join(['#include ' + header for header in headers]),
+ 'typedefs': '\n'.join(['typedef %s %s;' % typedef for typedef in typedefs]),
+ }
+
+ domains = self.domains_to_generate()
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args))
+ if self.model().framework.setting('alternate_dispatchers', False):
+ sections.append(self._generate_alternate_handler_forward_declarations_for_domains(domains))
+ sections.extend(map(self._generate_handler_declarations_for_domain, domains))
+ sections.extend(map(self._generate_dispatcher_declarations_for_domain, domains))
+ sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args))
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ def _generate_alternate_handler_forward_declarations_for_domains(self, domains):
+ if not domains:
+ return ''
+
+ lines = []
+ lines.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
+ for domain in domains:
+ lines.append(self.wrap_with_guard_for_domain(domain, 'class Alternate%sBackendDispatcher;' % domain.domain_name))
+ lines.append('#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
+ return '\n'.join(lines)
+
+ def _generate_handler_declarations_for_domain(self, domain):
+ classComponents = ['class']
+ exportMacro = self.model().framework.setting('export_macro', None)
+ if exportMacro is not None:
+ classComponents.append(exportMacro)
+
+ used_enum_names = set()
+
+ command_declarations = []
+ for command in self.commands_for_domain(domain):
+ command_declarations.append(self._generate_handler_declaration_for_command(command, used_enum_names))
+
+ handler_args = {
+ 'classAndExportMacro': " ".join(classComponents),
+ 'domainName': domain.domain_name,
+ 'commandDeclarations': "\n".join(command_declarations)
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.BackendDispatcherHeaderDomainHandlerDeclaration).substitute(None, **handler_args))
+
+ def _generate_anonymous_enum_for_parameter(self, parameter, command):
+ enum_args = {
+ 'parameterName': parameter.parameter_name,
+ 'commandName': command.command_name
+ }
+
+ lines = []
+ lines.append(' // Named after parameter \'%(parameterName)s\' while generating command/event %(commandName)s.' % enum_args)
+ lines.append(' enum class %s {' % ucfirst(parameter.parameter_name))
+ for enum_value in parameter.type.enum_values():
+ lines.append(' %s = %d,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value)))
+ lines.append(' }; // enum class %s' % ucfirst(parameter.parameter_name))
+ return '\n'.join(lines)
+
+ def _generate_handler_declaration_for_command(self, command, used_enum_names):
+ if command.is_async:
+ return self._generate_async_handler_declaration_for_command(command)
+
+ lines = []
+ parameters = ['ErrorString&']
+ for _parameter in command.call_parameters:
+ parameter_name = 'in_' + _parameter.parameter_name
+ if _parameter.is_optional:
+ parameter_name = 'opt_' + parameter_name
+
+ parameters.append("%s %s" % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), parameter_name))
+
+ if isinstance(_parameter.type, EnumType) and _parameter.type.is_anonymous and _parameter.parameter_name not in used_enum_names:
+ lines.append(self._generate_anonymous_enum_for_parameter(_parameter, command))
+ used_enum_names.add(_parameter.parameter_name)
+
+ for _parameter in command.return_parameters:
+ parameter_name = 'out_' + _parameter.parameter_name
+ if _parameter.is_optional:
+ parameter_name = 'opt_' + parameter_name
+ parameters.append("%s %s" % (CppGenerator.cpp_type_for_formal_out_parameter(_parameter), parameter_name))
+
+ if isinstance(_parameter.type, EnumType) and _parameter.type.is_anonymous and _parameter.parameter_name not in used_enum_names:
+ lines.append(self._generate_anonymous_enum_for_parameter(_parameter, command))
+ used_enum_names.add(_parameter.parameter_name)
+
+ command_args = {
+ 'commandName': command.command_name,
+ 'parameters': ", ".join(parameters)
+ }
+ lines.append(' virtual void %(commandName)s(%(parameters)s) = 0;' % command_args)
+ return '\n'.join(lines)
+
+ def _generate_async_handler_declaration_for_command(self, command):
+ callbackName = "%sCallback" % ucfirst(command.command_name)
+
+ in_parameters = ['ErrorString&']
+ for _parameter in command.call_parameters:
+ parameter_name = 'in_' + _parameter.parameter_name
+ if _parameter.is_optional:
+ parameter_name = 'opt_' + parameter_name
+
+ in_parameters.append("%s %s" % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), parameter_name))
+ in_parameters.append("Ref<%s>&& callback" % callbackName)
+
+ out_parameters = []
+ for _parameter in command.return_parameters:
+ out_parameters.append("%s %s" % (CppGenerator.cpp_type_for_formal_async_parameter(_parameter), _parameter.parameter_name))
+
+ class_components = ['class']
+ export_macro = self.model().framework.setting('export_macro', None)
+ if export_macro:
+ class_components.append(export_macro)
+
+ command_args = {
+ 'classAndExportMacro': ' '.join(class_components),
+ 'callbackName': callbackName,
+ 'commandName': command.command_name,
+ 'inParameters': ", ".join(in_parameters),
+ 'outParameters': ", ".join(out_parameters),
+ }
+
+ return Template(CppTemplates.BackendDispatcherHeaderAsyncCommandDeclaration).substitute(None, **command_args)
+
+ def _generate_dispatcher_declarations_for_domain(self, domain):
+ classComponents = ['class']
+ exportMacro = self.model().framework.setting('export_macro', None)
+ if exportMacro is not None:
+ classComponents.append(exportMacro)
+
+ declarations = []
+ commands = self.commands_for_domain(domain)
+ if len(commands) > 0:
+ declarations.append('private:')
+ declarations.extend(map(self._generate_dispatcher_declaration_for_command, commands))
+
+ declaration_args = {
+ 'domainName': domain.domain_name,
+ }
+
+ # Add in a few more declarations at the end if needed.
+ if self.model().framework.setting('alternate_dispatchers', False):
+ declarations.append(Template(CppTemplates.BackendDispatcherHeaderDomainDispatcherAlternatesDeclaration).substitute(None, **declaration_args))
+
+ handler_args = {
+ 'classAndExportMacro': " ".join(classComponents),
+ 'domainName': domain.domain_name,
+ 'commandDeclarations': "\n".join(declarations)
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.BackendDispatcherHeaderDomainDispatcherDeclaration).substitute(None, **handler_args))
+
+ def _generate_dispatcher_declaration_for_command(self, command):
+ return " void %s(long requestId, RefPtr<InspectorObject>&& parameters);" % command.command_name
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py
new file mode 100755
index 000000000..fccedcba7
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py
@@ -0,0 +1,324 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 string
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import ObjectType, ArrayType
+
+log = logging.getLogger('global')
+
+
+class CppBackendDispatcherImplementationGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sBackendDispatchers.cpp" % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(lambda domain: len(self.commands_for_domain(domain)) > 0, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '<inspector/InspectorFrontendRouter.h>',
+ '<inspector/InspectorValues.h>',
+ '<wtf/NeverDestroyed.h>',
+ '<wtf/text/CString.h>']
+
+ secondary_includes = ['#include %s' % header for header in secondary_headers]
+
+ if self.model().framework.setting('alternate_dispatchers', False):
+ secondary_includes.append('')
+ secondary_includes.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
+ secondary_includes.append('#include "%sAlternateBackendDispatchers.h"' % self.protocol_name())
+ secondary_includes.append('#endif')
+
+ header_args = {
+ 'primaryInclude': '"%sBackendDispatchers.h"' % self.protocol_name(),
+ 'secondaryIncludes': '\n'.join(secondary_includes),
+ }
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.append("\n".join(map(self._generate_handler_class_destructor_for_domain, self.domains_to_generate())))
+ sections.extend(map(self._generate_dispatcher_implementations_for_domain, self.domains_to_generate()))
+ sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ def _generate_handler_class_destructor_for_domain(self, domain):
+ destructor_args = {
+ 'domainName': domain.domain_name
+ }
+ destructor = '%(domainName)sBackendDispatcherHandler::~%(domainName)sBackendDispatcherHandler() { }' % destructor_args
+ return self.wrap_with_guard_for_domain(domain, destructor)
+
+ def _generate_dispatcher_implementations_for_domain(self, domain):
+ implementations = []
+
+ constructor_args = {
+ 'domainName': domain.domain_name,
+ }
+ implementations.append(Template(CppTemplates.BackendDispatcherImplementationDomainConstructor).substitute(None, **constructor_args))
+
+ commands = self.commands_for_domain(domain)
+
+ if len(commands) <= 5:
+ implementations.append(self._generate_small_dispatcher_switch_implementation_for_domain(domain))
+ else:
+ implementations.append(self._generate_large_dispatcher_switch_implementation_for_domain(domain))
+
+ for command in commands:
+ if command.is_async:
+ implementations.append(self._generate_async_dispatcher_class_for_domain(command, domain))
+ implementations.append(self._generate_dispatcher_implementation_for_command(command, domain))
+
+ return self.wrap_with_guard_for_domain(domain, '\n\n'.join(implementations))
+
+ def _generate_small_dispatcher_switch_implementation_for_domain(self, domain):
+ commands = self.commands_for_domain(domain)
+
+ cases = []
+ cases.append(' if (method == "%s")' % commands[0].command_name)
+ cases.append(' %s(requestId, WTFMove(parameters));' % commands[0].command_name)
+ for command in commands[1:]:
+ cases.append(' else if (method == "%s")' % command.command_name)
+ cases.append(' %s(requestId, WTFMove(parameters));' % command.command_name)
+
+ switch_args = {
+ 'domainName': domain.domain_name,
+ 'dispatchCases': "\n".join(cases)
+ }
+
+ return Template(CppTemplates.BackendDispatcherImplementationSmallSwitch).substitute(None, **switch_args)
+
+ def _generate_large_dispatcher_switch_implementation_for_domain(self, domain):
+ commands = self.commands_for_domain(domain)
+
+ cases = []
+ for command in commands:
+ args = {
+ 'domainName': domain.domain_name,
+ 'commandName': command.command_name
+ }
+ cases.append(' { "%(commandName)s", &%(domainName)sBackendDispatcher::%(commandName)s },' % args)
+
+ switch_args = {
+ 'domainName': domain.domain_name,
+ 'dispatchCases': "\n".join(cases)
+ }
+
+ return Template(CppTemplates.BackendDispatcherImplementationLargeSwitch).substitute(None, **switch_args)
+
+ def _generate_async_dispatcher_class_for_domain(self, command, domain):
+ out_parameter_assignments = []
+ formal_parameters = []
+
+ for parameter in command.return_parameters:
+ param_args = {
+ 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type),
+ 'parameterKey': parameter.parameter_name,
+ 'parameterName': parameter.parameter_name,
+ 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter),
+ 'helpersNamespace': self.helpers_namespace(),
+ }
+
+ formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_formal_async_parameter(parameter), parameter.parameter_name))
+
+ if parameter.is_optional:
+ if CppGenerator.should_use_wrapper_for_return_type(parameter.type):
+ out_parameter_assignments.append(' if (%(parameterName)s.isAssigned())' % param_args)
+ out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s.getValue());' % param_args)
+ else:
+ out_parameter_assignments.append(' if (%(parameterName)s)' % param_args)
+ out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args)
+ elif parameter.type.is_enum():
+ out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::%(helpersNamespace)s::getEnumConstantValue(%(parameterName)s));' % param_args)
+ else:
+ out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args)
+
+ async_args = {
+ 'domainName': domain.domain_name,
+ 'callbackName': ucfirst(command.command_name) + 'Callback',
+ 'formalParameters': ", ".join(formal_parameters),
+ 'outParameterAssignments': "\n".join(out_parameter_assignments)
+ }
+ return Template(CppTemplates.BackendDispatcherImplementationAsyncCommand).substitute(None, **async_args)
+
+ def _generate_dispatcher_implementation_for_command(self, command, domain):
+ in_parameter_declarations = []
+ out_parameter_declarations = []
+ out_parameter_assignments = []
+ alternate_dispatcher_method_parameters = ['requestId']
+ method_parameters = ['error']
+
+ for parameter in command.call_parameters:
+ parameter_name = 'in_' + parameter.parameter_name
+ if parameter.is_optional:
+ parameter_name = 'opt_' + parameter_name
+
+ out_success_argument = 'nullptr'
+ if parameter.is_optional:
+ out_success_argument = '&%s_valueFound' % parameter_name
+ in_parameter_declarations.append(' bool %s_valueFound = false;' % parameter_name)
+
+ # Now add appropriate operators.
+ parameter_expression = parameter_name
+
+ if CppGenerator.should_use_references_for_type(parameter.type):
+ if parameter.is_optional:
+ parameter_expression = '%s.get()' % parameter_expression
+ else:
+ # This assumes that we have already proved the object is non-null.
+ # If a required property is missing, InspectorBackend::getObject will
+ # append a protocol error, and the method dispatcher will return without
+ # invoking the backend method (and dereferencing the object).
+ parameter_expression = '*%s' % parameter_expression
+ elif parameter.is_optional:
+ parameter_expression = '&%s' % parameter_expression
+
+ param_args = {
+ 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter),
+ 'parameterKey': parameter.parameter_name,
+ 'parameterName': parameter_name,
+ 'parameterExpression': parameter_expression,
+ 'keyedGetMethod': CppGenerator.cpp_getter_method_for_type(parameter.type),
+ 'successOutParam': out_success_argument
+ }
+
+ in_parameter_declarations.append(' %(parameterType)s %(parameterName)s = m_backendDispatcher->%(keyedGetMethod)s(parameters.get(), ASCIILiteral("%(parameterKey)s"), %(successOutParam)s);' % param_args)
+
+ if parameter.is_optional:
+ optional_in_parameter_string = '%(parameterName)s_valueFound ? %(parameterExpression)s : nullptr' % param_args
+ alternate_dispatcher_method_parameters.append(optional_in_parameter_string)
+ method_parameters.append(optional_in_parameter_string)
+ else:
+ alternate_dispatcher_method_parameters.append(parameter_expression)
+ method_parameters.append(parameter_expression)
+
+ if command.is_async:
+ async_args = {
+ 'domainName': domain.domain_name,
+ 'callbackName': ucfirst(command.command_name) + 'Callback'
+ }
+
+ out_parameter_assignments.append(' callback->disable();')
+ out_parameter_assignments.append(' m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, error);')
+ out_parameter_assignments.append(' return;')
+ method_parameters.append('callback.copyRef()')
+
+ else:
+ for parameter in command.return_parameters:
+ param_args = {
+ 'parameterType': CppGenerator.cpp_type_for_stack_out_parameter(parameter),
+ 'parameterKey': parameter.parameter_name,
+ 'parameterName': parameter.parameter_name,
+ 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type),
+ 'helpersNamespace': self.helpers_namespace(),
+ }
+
+ out_parameter_declarations.append(' %(parameterType)s out_%(parameterName)s;' % param_args)
+ if parameter.is_optional:
+ if CppGenerator.should_use_wrapper_for_return_type(parameter.type):
+ out_parameter_assignments.append(' if (out_%(parameterName)s.isAssigned())' % param_args)
+ out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s.getValue());' % param_args)
+ else:
+ out_parameter_assignments.append(' if (out_%(parameterName)s)' % param_args)
+ out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args)
+ elif parameter.type.is_enum():
+ out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::%(helpersNamespace)s::getEnumConstantValue(out_%(parameterName)s));' % param_args)
+ else:
+ out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args)
+
+ if CppGenerator.should_pass_by_copy_for_return_type(parameter.type):
+ method_parameters.append('out_' + parameter.parameter_name)
+ else:
+ method_parameters.append('&out_' + parameter.parameter_name)
+
+ command_args = {
+ 'domainName': domain.domain_name,
+ 'callbackName': '%sCallback' % ucfirst(command.command_name),
+ 'commandName': command.command_name,
+ 'inParameterDeclarations': '\n'.join(in_parameter_declarations),
+ 'invocationParameters': ', '.join(method_parameters),
+ 'alternateInvocationParameters': ', '.join(alternate_dispatcher_method_parameters),
+ }
+
+ lines = []
+ if len(command.call_parameters) == 0:
+ lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long requestId, RefPtr<InspectorObject>&&)' % command_args)
+ else:
+ lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long requestId, RefPtr<InspectorObject>&& parameters)' % command_args)
+ lines.append('{')
+
+ if len(command.call_parameters) > 0:
+ lines.append(Template(CppTemplates.BackendDispatcherImplementationPrepareCommandArguments).substitute(None, **command_args))
+
+ if self.model().framework.setting('alternate_dispatchers', False):
+ lines.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
+ lines.append(' if (m_alternateDispatcher) {')
+ lines.append(' m_alternateDispatcher->%(commandName)s(%(alternateInvocationParameters)s);' % command_args)
+ lines.append(' return;')
+ lines.append(' }')
+ lines.append('#endif')
+ lines.append('')
+
+ lines.append(' ErrorString error;')
+ lines.append(' Ref<InspectorObject> result = InspectorObject::create();')
+ if command.is_async:
+ lines.append(' Ref<%(domainName)sBackendDispatcherHandler::%(callbackName)s> callback = adoptRef(*new %(domainName)sBackendDispatcherHandler::%(callbackName)s(m_backendDispatcher.copyRef(), requestId));' % command_args)
+ if len(command.return_parameters) > 0:
+ lines.extend(out_parameter_declarations)
+ lines.append(' m_agent->%(commandName)s(%(invocationParameters)s);' % command_args)
+ lines.append('')
+ if command.is_async:
+ lines.append(' if (error.length()) {')
+ lines.extend(out_parameter_assignments)
+ lines.append(' }')
+ elif len(command.return_parameters) > 1:
+ lines.append(' if (!error.length()) {')
+ lines.extend(out_parameter_assignments)
+ lines.append(' }')
+ elif len(command.return_parameters) == 1:
+ lines.append(' if (!error.length())')
+ lines.extend(out_parameter_assignments)
+ lines.append('')
+
+ if not command.is_async:
+ lines.append(' if (!error.length())')
+ lines.append(' m_backendDispatcher->sendResponse(requestId, WTFMove(result));')
+ lines.append(' else')
+ lines.append(' m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));')
+ lines.append('}')
+ return "\n".join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py
new file mode 100755
index 000000000..ed58b1e2f
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 re
+import string
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import EnumType
+
+log = logging.getLogger('global')
+
+
+class CppFrontendDispatcherHeaderGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sFrontendDispatchers.h" % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(lambda domain: len(self.events_for_domain(domain)) > 0, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ headers = [
+ '"%sProtocolObjects.h"' % self.protocol_name(),
+ '<inspector/InspectorValues.h>',
+ '<wtf/text/WTFString.h>']
+
+ header_args = {
+ 'includes': '\n'.join(['#include ' + header for header in headers]),
+ 'typedefs': 'class FrontendRouter;',
+ }
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args))
+ sections.extend(map(self._generate_dispatcher_declarations_for_domain, self.domains_to_generate()))
+ sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args))
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ def _generate_anonymous_enum_for_parameter(self, parameter, event):
+ enum_args = {
+ 'parameterName': parameter.parameter_name,
+ 'eventName': event.event_name
+ }
+
+ lines = []
+ lines.append(' // Named after parameter \'%(parameterName)s\' while generating command/event %(eventName)s.' % enum_args)
+ lines.append(' enum class %s {' % ucfirst(parameter.parameter_name))
+ for enum_value in parameter.type.enum_values():
+ lines.append(' %s = %d,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value)))
+ lines.append(' }; // enum class %s' % ucfirst(parameter.parameter_name))
+ return "\n".join(lines)
+
+ def _generate_dispatcher_declarations_for_domain(self, domain):
+ classComponents = ['class']
+ exportMacro = self.model().framework.setting('export_macro', None)
+ if exportMacro is not None:
+ classComponents.append(exportMacro)
+
+ used_enum_names = set([])
+
+ events = self.events_for_domain(domain)
+ event_declarations = []
+ for event in events:
+ event_declarations.append(self._generate_dispatcher_declaration_for_event(event, domain, used_enum_names))
+
+ handler_args = {
+ 'classAndExportMacro': " ".join(classComponents),
+ 'domainName': domain.domain_name,
+ 'eventDeclarations': "\n".join(event_declarations)
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.FrontendDispatcherDomainDispatcherDeclaration).substitute(None, **handler_args))
+
+ def _generate_dispatcher_declaration_for_event(self, event, domain, used_enum_names):
+ formal_parameters = []
+ lines = []
+ for parameter in event.event_parameters:
+ formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_checked_formal_event_parameter(parameter), parameter.parameter_name))
+ if isinstance(parameter.type, EnumType) and parameter.parameter_name not in used_enum_names:
+ lines.append(self._generate_anonymous_enum_for_parameter(parameter, event))
+ used_enum_names.add(parameter.parameter_name)
+
+ lines.append(" void %s(%s);" % (event.event_name, ", ".join(formal_parameters)))
+ return "\n".join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py
new file mode 100755
index 000000000..0d0806903
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 string
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import ObjectType, ArrayType
+
+log = logging.getLogger('global')
+
+
+class CppFrontendDispatcherImplementationGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sFrontendDispatchers.cpp" % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(lambda domain: len(self.events_for_domain(domain)) > 0, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '"InspectorFrontendRouter.h"',
+ '<wtf/text/CString.h>',
+ ]
+
+ header_args = {
+ 'primaryInclude': '"%sFrontendDispatchers.h"' % self.protocol_name(),
+ 'secondaryIncludes': "\n".join(['#include %s' % header for header in secondary_headers]),
+ }
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.extend(map(self._generate_dispatcher_implementations_for_domain, self.domains_to_generate()))
+ sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ def _generate_dispatcher_implementations_for_domain(self, domain):
+ implementations = []
+ events = self.events_for_domain(domain)
+ for event in events:
+ implementations.append(self._generate_dispatcher_implementation_for_event(event, domain))
+
+ return self.wrap_with_guard_for_domain(domain, '\n\n'.join(implementations))
+
+ def _generate_dispatcher_implementation_for_event(self, event, domain):
+ lines = []
+ parameter_assignments = []
+ formal_parameters = []
+
+ for parameter in event.event_parameters:
+
+ parameter_value = parameter.parameter_name
+ if parameter.is_optional and not CppGenerator.should_pass_by_copy_for_return_type(parameter.type):
+ parameter_value = '*' + parameter_value
+ if parameter.type.is_enum():
+ parameter_value = 'Inspector::Protocol::%s::getEnumConstantValue(%s)' % (self.helpers_namespace(), parameter_value)
+
+ parameter_args = {
+ 'parameterType': CppGenerator.cpp_type_for_stack_out_parameter(parameter),
+ 'parameterName': parameter.parameter_name,
+ 'parameterValue': parameter_value,
+ 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type),
+ }
+
+ if parameter.is_optional:
+ parameter_assignments.append(' if (%(parameterName)s)' % parameter_args)
+ parameter_assignments.append(' paramsObject->%(keyedSetMethod)s(ASCIILiteral("%(parameterName)s"), %(parameterValue)s);' % parameter_args)
+ else:
+ parameter_assignments.append(' paramsObject->%(keyedSetMethod)s(ASCIILiteral("%(parameterName)s"), %(parameterValue)s);' % parameter_args)
+
+ formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_checked_formal_event_parameter(parameter), parameter.parameter_name))
+
+ event_args = {
+ 'domainName': domain.domain_name,
+ 'eventName': event.event_name,
+ 'formalParameters': ", ".join(formal_parameters)
+ }
+
+ lines.append('void %(domainName)sFrontendDispatcher::%(eventName)s(%(formalParameters)s)' % event_args)
+ lines.append('{')
+ lines.append(' Ref<InspectorObject> jsonMessage = InspectorObject::create();')
+ lines.append(' jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("%(domainName)s.%(eventName)s"));' % event_args)
+
+ if len(parameter_assignments) > 0:
+ lines.append(' Ref<InspectorObject> paramsObject = InspectorObject::create();')
+ lines.extend(parameter_assignments)
+ lines.append(' jsonMessage->setObject(ASCIILiteral("params"), WTFMove(paramsObject));')
+
+ lines.append('')
+ lines.append(' m_frontendRouter.sendEvent(jsonMessage->toJSONString());')
+ lines.append('}')
+ return "\n".join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_header.py
new file mode 100755
index 000000000..1f91cdd0f
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_header.py
@@ -0,0 +1,424 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 re
+import string
+from operator import methodcaller
+from string import Template
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import EnumType, ObjectType, PrimitiveType, AliasedType, ArrayType, Frameworks
+
+log = logging.getLogger('global')
+
+
+class CppProtocolTypesHeaderGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sProtocolObjects.h" % self.protocol_name()
+
+ def generate_output(self):
+ domains = self.domains_to_generate()
+ self.calculate_types_requiring_shape_assertions(domains)
+
+ headers = set([
+ '<inspector/InspectorProtocolTypes.h>',
+ '<wtf/Assertions.h>',
+ ])
+
+ header_args = {
+ 'includes': '\n'.join(['#include ' + header for header in sorted(headers)]),
+ 'typedefs': '',
+ }
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args))
+ sections.append('namespace Protocol {')
+ sections.append(self._generate_forward_declarations(domains))
+ sections.append(self._generate_typedefs(domains))
+ sections.extend(self._generate_enum_constant_value_conversion_methods())
+ builder_sections = map(self._generate_builders_for_domain, domains)
+ sections.extend(filter(lambda section: len(section) > 0, builder_sections))
+ sections.append(self._generate_forward_declarations_for_binding_traits())
+ sections.extend(self._generate_declarations_for_enum_conversion_methods())
+ sections.append('} // namespace Protocol')
+ sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args))
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ # FIXME: move builders out of classes, uncomment forward declaration
+
+ def _generate_forward_declarations(self, domains):
+ sections = []
+
+ for domain in domains:
+ declaration_types = [decl.type for decl in self.type_declarations_for_domain(domain)]
+ object_types = filter(lambda _type: isinstance(_type, ObjectType), declaration_types)
+ enum_types = filter(lambda _type: isinstance(_type, EnumType), declaration_types)
+ sorted(object_types, key=methodcaller('raw_name'))
+ sorted(enum_types, key=methodcaller('raw_name'))
+
+ if len(object_types) + len(enum_types) == 0:
+ continue
+
+ domain_lines = []
+ domain_lines.append('namespace %s {' % domain.domain_name)
+
+ # Forward-declare all classes so the type builders won't break if rearranged.
+ domain_lines.extend('class %s;' % object_type.raw_name() for object_type in object_types)
+ domain_lines.extend('enum class %s;' % enum_type.raw_name() for enum_type in enum_types)
+ domain_lines.append('} // %s' % domain.domain_name)
+ sections.append(self.wrap_with_guard_for_domain(domain, '\n'.join(domain_lines)))
+
+ if len(sections) == 0:
+ return ''
+ else:
+ return """// Forward declarations.
+%s
+// End of forward declarations.
+""" % '\n\n'.join(sections)
+
+ def _generate_typedefs(self, domains):
+ sections = map(self._generate_typedefs_for_domain, domains)
+ sections = filter(lambda text: len(text) > 0, sections)
+
+ if len(sections) == 0:
+ return ''
+ else:
+ return """// Typedefs.
+%s
+// End of typedefs.""" % '\n\n'.join(sections)
+
+ def _generate_typedefs_for_domain(self, domain):
+ type_declarations = self.type_declarations_for_domain(domain)
+ primitive_declarations = filter(lambda decl: isinstance(decl.type, AliasedType), type_declarations)
+ array_declarations = filter(lambda decl: isinstance(decl.type, ArrayType), type_declarations)
+ if len(primitive_declarations) == 0 and len(array_declarations) == 0:
+ return ''
+
+ sections = []
+ for declaration in primitive_declarations:
+ primitive_name = CppGenerator.cpp_name_for_primitive_type(declaration.type.aliased_type)
+ typedef_lines = []
+ if len(declaration.description) > 0:
+ typedef_lines.append('/* %s */' % declaration.description)
+ typedef_lines.append('typedef %s %s;' % (primitive_name, declaration.type_name))
+ sections.append('\n'.join(typedef_lines))
+
+ for declaration in array_declarations:
+ element_type = CppGenerator.cpp_protocol_type_for_type(declaration.type.element_type)
+ typedef_lines = []
+ if len(declaration.description) > 0:
+ typedef_lines.append('/* %s */' % declaration.description)
+ typedef_lines.append('typedef Inspector::Protocol::Array<%s> %s;' % (element_type, declaration.type_name))
+ sections.append('\n'.join(typedef_lines))
+
+ lines = []
+ lines.append('namespace %s {' % domain.domain_name)
+ lines.append('\n'.join(sections))
+ lines.append('} // %s' % domain.domain_name)
+ return self.wrap_with_guard_for_domain(domain, '\n'.join(lines))
+
+ def _generate_enum_constant_value_conversion_methods(self):
+ if not self.assigned_enum_values():
+ return []
+
+ return_type = 'String'
+ return_type_with_export_macro = [return_type]
+ export_macro = self.model().framework.setting('export_macro', None)
+ if export_macro is not None:
+ return_type_with_export_macro[:0] = [export_macro]
+
+ lines = []
+ lines.append('namespace %s {' % self.helpers_namespace())
+ lines.append('\n'.join([
+ '%s getEnumConstantValue(int code);' % ' '.join(return_type_with_export_macro),
+ '',
+ 'template<typename T> %s getEnumConstantValue(T enumValue)' % return_type,
+ '{',
+ ' return getEnumConstantValue(static_cast<int>(enumValue));',
+ '}',
+ ]))
+ lines.append('} // namespace %s' % self.helpers_namespace())
+ return lines
+
+ def _generate_builders_for_domain(self, domain):
+ sections = []
+
+ type_declarations = self.type_declarations_for_domain(domain)
+ for type_declaration in type_declarations:
+ if isinstance(type_declaration.type, EnumType):
+ sections.append(self._generate_struct_for_enum_declaration(type_declaration))
+ elif isinstance(type_declaration.type, ObjectType):
+ sections.append(self._generate_class_for_object_declaration(type_declaration, domain))
+
+ sections = filter(lambda section: len(section) > 0, sections)
+ if len(sections) == 0:
+ return ''
+
+ lines = []
+ lines.append('namespace %s {' % domain.domain_name)
+ lines.append('\n'.join(sections))
+ lines.append('} // %s' % domain.domain_name)
+ return self.wrap_with_guard_for_domain(domain, '\n'.join(lines))
+
+ def _generate_class_for_object_declaration(self, type_declaration, domain):
+ if len(type_declaration.type_members) == 0:
+ return ''
+
+ enum_members = filter(lambda member: isinstance(member.type, EnumType) and member.type.is_anonymous, type_declaration.type_members)
+ required_members = filter(lambda member: not member.is_optional, type_declaration.type_members)
+ optional_members = filter(lambda member: member.is_optional, type_declaration.type_members)
+ object_name = type_declaration.type_name
+
+ lines = []
+ if len(type_declaration.description) > 0:
+ lines.append('/* %s */' % type_declaration.description)
+ base_class = 'Inspector::InspectorObject'
+ if not Generator.type_has_open_fields(type_declaration.type):
+ base_class = base_class + 'Base'
+ lines.append('class %s : public %s {' % (object_name, base_class))
+ lines.append('public:')
+ for enum_member in enum_members:
+ lines.append(' // Named after property name \'%s\' while generating %s.' % (enum_member.member_name, object_name))
+ lines.append(self._generate_struct_for_anonymous_enum_member(enum_member))
+ lines.append(self._generate_builder_state_enum(type_declaration))
+
+ constructor_example = []
+ constructor_example.append(' * Ref<%s> result = %s::create()' % (object_name, object_name))
+ for member in required_members:
+ constructor_example.append(' * .set%s(...)' % ucfirst(member.member_name))
+ constructor_example.append(' * .release()')
+
+ builder_args = {
+ 'objectType': object_name,
+ 'constructorExample': '\n'.join(constructor_example) + ';',
+ }
+
+ lines.append(Template(CppTemplates.ProtocolObjectBuilderDeclarationPrelude).substitute(None, **builder_args))
+ for type_member in required_members:
+ lines.append(self._generate_builder_setter_for_member(type_member, domain))
+ lines.append(Template(CppTemplates.ProtocolObjectBuilderDeclarationPostlude).substitute(None, **builder_args))
+ for member in optional_members:
+ lines.append(self._generate_unchecked_setter_for_member(member, domain))
+
+ if Generator.type_has_open_fields(type_declaration.type):
+ lines.append('')
+ lines.append(' // Property names for type generated as open.')
+ for type_member in type_declaration.type_members:
+ export_macro = self.model().framework.setting('export_macro', None)
+ lines.append(' %s static const char* %s;' % (export_macro, ucfirst(type_member.member_name)))
+
+ lines.append('};')
+ lines.append('')
+ return '\n'.join(lines)
+
+ def _generate_struct_for_enum_declaration(self, enum_declaration):
+ lines = []
+ lines.append('/* %s */' % enum_declaration.description)
+ lines.extend(self._generate_struct_for_enum_type(enum_declaration.type_name, enum_declaration.type))
+ return '\n'.join(lines)
+
+ def _generate_struct_for_anonymous_enum_member(self, enum_member):
+ def apply_indentation(line):
+ if line.startswith(('#', '/*', '*/', '//')) or len(line) is 0:
+ return line
+ else:
+ return ' ' + line
+
+ indented_lines = map(apply_indentation, self._generate_struct_for_enum_type(enum_member.member_name, enum_member.type))
+ return '\n'.join(indented_lines)
+
+ def _generate_struct_for_enum_type(self, enum_name, enum_type):
+ lines = []
+ enum_name = ucfirst(enum_name)
+ lines.append('enum class %s {' % enum_name)
+ for enum_value in enum_type.enum_values():
+ lines.append(' %s = %s,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value)))
+ lines.append('}; // enum class %s' % enum_name)
+ return lines # The caller may want to adjust indentation, so don't join these lines.
+
+ def _generate_builder_state_enum(self, type_declaration):
+ lines = []
+ required_members = filter(lambda member: not member.is_optional, type_declaration.type_members)
+ enum_values = []
+
+ lines.append(' enum {')
+ lines.append(' NoFieldsSet = 0,')
+ for i in range(len(required_members)):
+ enum_value = "%sSet" % ucfirst(required_members[i].member_name)
+ enum_values.append(enum_value)
+ lines.append(' %s = 1 << %d,' % (enum_value, i))
+ if len(enum_values) > 0:
+ lines.append(' AllFieldsSet = (%s)' % ' | '.join(enum_values))
+ else:
+ lines.append(' AllFieldsSet = 0')
+ lines.append(' };')
+ lines.append('')
+ return '\n'.join(lines)
+
+ def _generate_builder_setter_for_member(self, type_member, domain):
+ setter_args = {
+ 'camelName': ucfirst(type_member.member_name),
+ 'keyedSet': CppGenerator.cpp_setter_method_for_type(type_member.type),
+ 'name': type_member.member_name,
+ 'parameterType': CppGenerator.cpp_type_for_type_member(type_member),
+ 'helpersNamespace': self.helpers_namespace(),
+ }
+
+ lines = []
+ lines.append('')
+ lines.append(' Builder<STATE | %(camelName)sSet>& set%(camelName)s(%(parameterType)s value)' % setter_args)
+ lines.append(' {')
+ lines.append(' COMPILE_ASSERT(!(STATE & %(camelName)sSet), property_%(name)s_already_set);' % setter_args)
+
+ if isinstance(type_member.type, EnumType):
+ lines.append(' m_result->%(keyedSet)s(ASCIILiteral("%(name)s"), Inspector::Protocol::%(helpersNamespace)s::getEnumConstantValue(value));' % setter_args)
+ else:
+ lines.append(' m_result->%(keyedSet)s(ASCIILiteral("%(name)s"), value);' % setter_args)
+ lines.append(' return castState<%(camelName)sSet>();' % setter_args)
+ lines.append(' }')
+ return '\n'.join(lines)
+
+ def _generate_unchecked_setter_for_member(self, type_member, domain):
+ setter_args = {
+ 'camelName': ucfirst(type_member.member_name),
+ 'keyedSet': CppGenerator.cpp_setter_method_for_type(type_member.type),
+ 'name': type_member.member_name,
+ 'parameterType': CppGenerator.cpp_type_for_type_member(type_member),
+ 'helpersNamespace': self.helpers_namespace(),
+ }
+
+ lines = []
+ lines.append('')
+ lines.append(' void set%(camelName)s(%(parameterType)s value)' % setter_args)
+ lines.append(' {')
+ if isinstance(type_member.type, EnumType):
+ lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), Inspector::Protocol::%(helpersNamespace)s::getEnumConstantValue(value));' % setter_args)
+ elif CppGenerator.should_use_references_for_type(type_member.type):
+ lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), WTFMove(value));' % setter_args)
+ else:
+ lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), value);' % setter_args)
+ lines.append(' }')
+ return '\n'.join(lines)
+
+ def _generate_forward_declarations_for_binding_traits(self):
+ # A list of (builder_type, needs_runtime_cast)
+ type_arguments = []
+
+ for domain in self.domains_to_generate():
+ type_declarations = self.type_declarations_for_domain(domain)
+ declarations_to_generate = filter(lambda decl: self.type_needs_shape_assertions(decl.type), type_declarations)
+
+ for type_declaration in declarations_to_generate:
+ for type_member in type_declaration.type_members:
+ if isinstance(type_member.type, EnumType):
+ type_arguments.append((CppGenerator.cpp_protocol_type_for_type_member(type_member, type_declaration), False))
+
+ if isinstance(type_declaration.type, ObjectType):
+ type_arguments.append((CppGenerator.cpp_protocol_type_for_type(type_declaration.type), Generator.type_needs_runtime_casts(type_declaration.type)))
+
+ struct_keywords = ['struct']
+ function_keywords = ['static void']
+ export_macro = self.model().framework.setting('export_macro', None)
+ if export_macro is not None:
+ struct_keywords.append(export_macro)
+ #function_keywords[1:1] = [export_macro]
+
+ lines = []
+ for argument in type_arguments:
+ lines.append('template<> %s BindingTraits<%s> {' % (' '.join(struct_keywords), argument[0]))
+ if argument[1]:
+ lines.append('static RefPtr<%s> runtimeCast(RefPtr<Inspector::InspectorValue>&& value);' % argument[0])
+ lines.append('#if !ASSERT_DISABLED')
+ lines.append('%s assertValueHasExpectedType(Inspector::InspectorValue*);' % ' '.join(function_keywords))
+ lines.append('#endif // !ASSERT_DISABLED')
+ lines.append('};')
+ return '\n'.join(lines)
+
+ def _generate_declarations_for_enum_conversion_methods(self):
+ sections = []
+ sections.append('\n'.join([
+ 'namespace %s {' % self.helpers_namespace(),
+ '',
+ 'template<typename ProtocolEnumType>',
+ 'std::optional<ProtocolEnumType> parseEnumValueFromString(const String&);',
+ ]))
+
+ def return_type_with_export_macro(cpp_protocol_type):
+ enum_return_type = 'std::optional<%s>' % cpp_protocol_type
+ result_terms = [enum_return_type]
+ export_macro = self.model().framework.setting('export_macro', None)
+ if export_macro is not None:
+ result_terms[:0] = [export_macro]
+ return ' '.join(result_terms)
+
+ def type_member_is_anonymous_enum_type(type_member):
+ return isinstance(type_member.type, EnumType) and type_member.type.is_anonymous
+
+ for domain in self.domains_to_generate():
+ type_declarations = self.type_declarations_for_domain(domain)
+ declaration_types = [decl.type for decl in type_declarations]
+ object_types = filter(lambda _type: isinstance(_type, ObjectType), declaration_types)
+ enum_types = filter(lambda _type: isinstance(_type, EnumType), declaration_types)
+ if len(object_types) + len(enum_types) == 0:
+ continue
+
+ sorted(object_types, key=methodcaller('raw_name'))
+ sorted(enum_types, key=methodcaller('raw_name'))
+
+ domain_lines = []
+ domain_lines.append("// Enums in the '%s' Domain" % domain.domain_name)
+ for enum_type in enum_types:
+ cpp_protocol_type = CppGenerator.cpp_protocol_type_for_type(enum_type)
+ domain_lines.append('template<>')
+ domain_lines.append('%s parseEnumValueFromString<%s>(const String&);' % (return_type_with_export_macro(cpp_protocol_type), cpp_protocol_type))
+
+ for object_type in object_types:
+ for enum_member in filter(type_member_is_anonymous_enum_type, object_type.members):
+ cpp_protocol_type = CppGenerator.cpp_protocol_type_for_type_member(enum_member, object_type.declaration())
+ domain_lines.append('template<>')
+ domain_lines.append('%s parseEnumValueFromString<%s>(const String&);' % (return_type_with_export_macro(cpp_protocol_type), cpp_protocol_type))
+
+ if len(domain_lines) == 1:
+ continue # No real declarations to emit, just the domain comment. Skip.
+
+ sections.append(self.wrap_with_guard_for_domain(domain, '\n'.join(domain_lines)))
+
+ if len(sections) == 1:
+ return [] # No real sections to emit, just the namespace and template declaration. Skip.
+
+ sections.append('} // namespace %s' % self.helpers_namespace())
+
+ return ['\n\n'.join(sections)]
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py
new file mode 100755
index 000000000..f302a7342
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+from operator import methodcaller
+
+from cpp_generator import CppGenerator
+from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
+from generator import Generator, ucfirst
+from models import AliasedType, ArrayType, EnumType, ObjectType
+
+log = logging.getLogger('global')
+
+
+class CppProtocolTypesImplementationGenerator(CppGenerator):
+ def __init__(self, *args, **kwargs):
+ CppGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "%sProtocolObjects.cpp" % self.protocol_name()
+
+ def generate_output(self):
+ domains = self.domains_to_generate()
+ self.calculate_types_requiring_shape_assertions(domains)
+
+ secondary_headers = [
+ '<wtf/Optional.h>',
+ '<wtf/text/CString.h>',
+ ]
+
+ header_args = {
+ 'primaryInclude': '"%sProtocolObjects.h"' % self.protocol_name(),
+ 'secondaryIncludes': "\n".join(['#include %s' % header for header in secondary_headers]),
+ }
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.append('namespace Protocol {')
+ sections.extend(self._generate_enum_mapping_and_conversion_methods(domains))
+ sections.append(self._generate_open_field_names())
+ builder_sections = map(self._generate_builders_for_domain, domains)
+ sections.extend(filter(lambda section: len(section) > 0, builder_sections))
+ sections.append('} // namespace Protocol')
+ sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args))
+
+ return "\n\n".join(sections)
+
+ # Private methods.
+
+ def _generate_enum_mapping(self):
+ if not self.assigned_enum_values():
+ return []
+
+ lines = []
+ lines.append('static const char* const enum_constant_values[] = {')
+ lines.extend([' "%s",' % enum_value for enum_value in self.assigned_enum_values()])
+ lines.append('};')
+ lines.append('')
+ lines.append('String getEnumConstantValue(int code) {')
+ lines.append(' return enum_constant_values[code];')
+ lines.append('}')
+ return ['\n'.join(lines)]
+
+ def _generate_enum_conversion_methods_for_domain(self, domain):
+
+ def type_member_is_anonymous_enum_type(type_member):
+ return isinstance(type_member.type, EnumType) and type_member.type.is_anonymous
+
+ def generate_conversion_method_body(enum_type, cpp_protocol_type):
+ body_lines = []
+ body_lines.extend([
+ 'template<>',
+ 'std::optional<%s> parseEnumValueFromString<%s>(const String& protocolString)' % (cpp_protocol_type, cpp_protocol_type),
+ '{',
+ ' static const size_t constantValues[] = {',
+ ])
+
+ enum_values = enum_type.enum_values()
+ for enum_value in enum_values:
+ body_lines.append(' (size_t)%s::%s,' % (cpp_protocol_type, Generator.stylized_name_for_enum_value(enum_value)))
+
+ body_lines.extend([
+ ' };',
+ ' for (size_t i = 0; i < %d; ++i)' % len(enum_values),
+ ' if (protocolString == enum_constant_values[constantValues[i]])',
+ ' return (%s)constantValues[i];' % cpp_protocol_type,
+ '',
+ ' return std::nullopt;',
+ '}',
+ '',
+ ])
+ return body_lines
+
+ type_declarations = self.type_declarations_for_domain(domain)
+ declaration_types = [decl.type for decl in type_declarations]
+ object_types = filter(lambda _type: isinstance(_type, ObjectType), declaration_types)
+ enum_types = filter(lambda _type: isinstance(_type, EnumType), declaration_types)
+ if len(object_types) + len(enum_types) == 0:
+ return ''
+
+ sorted(object_types, key=methodcaller('raw_name'))
+ sorted(enum_types, key=methodcaller('raw_name'))
+
+ lines = []
+ lines.append("// Enums in the '%s' Domain" % domain.domain_name)
+ for enum_type in enum_types:
+ cpp_protocol_type = CppGenerator.cpp_protocol_type_for_type(enum_type)
+ lines.extend(generate_conversion_method_body(enum_type, cpp_protocol_type))
+
+ for object_type in object_types:
+ for enum_member in filter(type_member_is_anonymous_enum_type, object_type.members):
+ cpp_protocol_type = CppGenerator.cpp_protocol_type_for_type_member(enum_member, object_type.declaration())
+ lines.extend(generate_conversion_method_body(enum_member.type, cpp_protocol_type))
+
+ if len(lines) == 1:
+ return '' # No real declarations to emit, just the domain comment.
+
+ return self.wrap_with_guard_for_domain(domain, '\n'.join(lines))
+
+ def _generate_enum_mapping_and_conversion_methods(self, domains):
+ sections = []
+ sections.append('namespace %s {' % self.helpers_namespace())
+ sections.extend(self._generate_enum_mapping())
+ enum_parser_sections = map(self._generate_enum_conversion_methods_for_domain, domains)
+ sections.extend(filter(lambda section: len(section) > 0, enum_parser_sections))
+ if len(sections) == 1:
+ return [] # No declarations to emit, just the namespace.
+
+ sections.append('} // namespace %s' % self.helpers_namespace())
+ return sections
+
+ def _generate_open_field_names(self):
+ lines = []
+ for domain in self.domains_to_generate():
+ type_declarations = self.type_declarations_for_domain(domain)
+ for type_declaration in filter(lambda decl: Generator.type_has_open_fields(decl.type), type_declarations):
+ for type_member in sorted(type_declaration.type_members, key=lambda member: member.member_name):
+ field_name = '::'.join(['Inspector', 'Protocol', domain.domain_name, ucfirst(type_declaration.type_name), ucfirst(type_member.member_name)])
+ lines.append('const char* %s = "%s";' % (field_name, type_member.member_name))
+
+ return '\n'.join(lines)
+
+ def _generate_builders_for_domain(self, domain):
+ sections = []
+ type_declarations = self.type_declarations_for_domain(domain)
+ declarations_to_generate = filter(lambda decl: self.type_needs_shape_assertions(decl.type), type_declarations)
+
+ for type_declaration in declarations_to_generate:
+ for type_member in type_declaration.type_members:
+ if isinstance(type_member.type, EnumType):
+ sections.append(self._generate_assertion_for_enum(type_member, type_declaration))
+
+ if isinstance(type_declaration.type, ObjectType):
+ sections.append(self._generate_assertion_for_object_declaration(type_declaration))
+ if Generator.type_needs_runtime_casts(type_declaration.type):
+ sections.append(self._generate_runtime_cast_for_object_declaration(type_declaration))
+
+ return '\n\n'.join(sections)
+
+ def _generate_runtime_cast_for_object_declaration(self, object_declaration):
+ args = {
+ 'objectType': CppGenerator.cpp_protocol_type_for_type(object_declaration.type)
+ }
+ return Template(CppTemplates.ProtocolObjectRuntimeCast).substitute(None, **args)
+
+ def _generate_assertion_for_object_declaration(self, object_declaration):
+ required_members = filter(lambda member: not member.is_optional, object_declaration.type_members)
+ optional_members = filter(lambda member: member.is_optional, object_declaration.type_members)
+ should_count_properties = not Generator.type_has_open_fields(object_declaration.type)
+ lines = []
+
+ lines.append('#if !ASSERT_DISABLED')
+ lines.append('void BindingTraits<%s>::assertValueHasExpectedType(Inspector::InspectorValue* value)' % (CppGenerator.cpp_protocol_type_for_type(object_declaration.type)))
+ lines.append("""{
+ ASSERT_ARG(value, value);
+ RefPtr<InspectorObject> object;
+ bool castSucceeded = value->asObject(object);
+ ASSERT_UNUSED(castSucceeded, castSucceeded);""")
+ for type_member in required_members:
+ args = {
+ 'memberName': type_member.member_name,
+ 'assertMethod': CppGenerator.cpp_assertion_method_for_type_member(type_member, object_declaration)
+ }
+
+ lines.append(""" {
+ InspectorObject::iterator %(memberName)sPos = object->find(ASCIILiteral("%(memberName)s"));
+ ASSERT(%(memberName)sPos != object->end());
+ %(assertMethod)s(%(memberName)sPos->value.get());
+ }""" % args)
+
+ if should_count_properties:
+ lines.append('')
+ lines.append(' int foundPropertiesCount = %s;' % len(required_members))
+
+ for type_member in optional_members:
+ args = {
+ 'memberName': type_member.member_name,
+ 'assertMethod': CppGenerator.cpp_assertion_method_for_type_member(type_member, object_declaration)
+ }
+
+ lines.append(""" {
+ InspectorObject::iterator %(memberName)sPos = object->find(ASCIILiteral("%(memberName)s"));
+ if (%(memberName)sPos != object->end()) {
+ %(assertMethod)s(%(memberName)sPos->value.get());""" % args)
+
+ if should_count_properties:
+ lines.append(' ++foundPropertiesCount;')
+ lines.append(' }')
+ lines.append(' }')
+
+ if should_count_properties:
+ lines.append(' if (foundPropertiesCount != object->size())')
+ lines.append(' FATAL("Unexpected properties in object: %s\\n", object->toJSONString().ascii().data());')
+ lines.append('}')
+ lines.append('#endif // !ASSERT_DISABLED')
+ return '\n'.join(lines)
+
+ def _generate_assertion_for_enum(self, enum_member, object_declaration):
+ lines = []
+ lines.append('#if !ASSERT_DISABLED')
+ lines.append('void %s(Inspector::InspectorValue* value)' % CppGenerator.cpp_assertion_method_for_type_member(enum_member, object_declaration))
+ lines.append('{')
+ lines.append(' ASSERT_ARG(value, value);')
+ lines.append(' String result;')
+ lines.append(' bool castSucceeded = value->asString(result);')
+ lines.append(' ASSERT(castSucceeded);')
+
+ assert_condition = ' || '.join(['result == "%s"' % enum_value for enum_value in enum_member.type.enum_values()])
+ lines.append(' ASSERT(%s);' % assert_condition)
+ lines.append('}')
+ lines.append('#endif // !ASSERT_DISABLED')
+
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_js_backend_commands.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_js_backend_commands.py
new file mode 100755
index 000000000..555c12f89
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_js_backend_commands.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator, ucfirst
+from generator_templates import GeneratorTemplates as Templates
+from models import EnumType
+
+log = logging.getLogger('global')
+
+
+class JSBackendCommandsGenerator(Generator):
+ def __init__(self, *args, **kwargs):
+ Generator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return "InspectorBackendCommands.js"
+
+ def should_generate_domain(self, domain):
+ type_declarations = self.type_declarations_for_domain(domain)
+ domain_enum_types = filter(lambda declaration: isinstance(declaration.type, EnumType), type_declarations)
+ return len(self.commands_for_domain(domain)) > 0 or len(self.events_for_domain(domain)) > 0 or len(domain_enum_types) > 0
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ sections = []
+ sections.append(self.generate_license())
+ sections.extend(map(self.generate_domain, self.domains_to_generate()))
+ return "\n\n".join(sections)
+
+ def generate_domain(self, domain):
+ lines = []
+ args = {
+ 'domain': domain.domain_name
+ }
+
+ lines.append('// %(domain)s.' % args)
+
+ type_declarations = self.type_declarations_for_domain(domain)
+ commands = self.commands_for_domain(domain)
+ events = self.events_for_domain(domain)
+
+ has_async_commands = any(map(lambda command: command.is_async, commands))
+ if len(events) > 0 or has_async_commands:
+ lines.append('InspectorBackend.register%(domain)sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "%(domain)s");' % args)
+
+ for declaration in type_declarations:
+ if declaration.type.is_enum():
+ enum_args = {
+ 'domain': domain.domain_name,
+ 'enumName': declaration.type_name,
+ 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in declaration.type.enum_values()])
+ }
+ lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args)
+
+ def is_anonymous_enum_member(type_member):
+ return isinstance(type_member.type, EnumType) and type_member.type.is_anonymous
+
+ for _member in filter(is_anonymous_enum_member, declaration.type_members):
+ enum_args = {
+ 'domain': domain.domain_name,
+ 'enumName': '%s%s' % (declaration.type_name, ucfirst(_member.member_name)),
+ 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in _member.type.enum_values()])
+ }
+ lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args)
+
+ def is_anonymous_enum_param(param):
+ return isinstance(param.type, EnumType) and param.type.is_anonymous
+
+ for event in events:
+ for param in filter(is_anonymous_enum_param, event.event_parameters):
+ enum_args = {
+ 'domain': domain.domain_name,
+ 'enumName': '%s%s' % (ucfirst(event.event_name), ucfirst(param.parameter_name)),
+ 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in param.type.enum_values()])
+ }
+ lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args)
+
+ 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)
+
+ for command in commands:
+ def generate_parameter_object(parameter):
+ optional_string = "true" if parameter.is_optional else "false"
+ pairs = []
+ pairs.append('"name": "%s"' % parameter.parameter_name)
+ pairs.append('"type": "%s"' % Generator.js_name_for_parameter_type(parameter.type))
+ pairs.append('"optional": %s' % optional_string)
+ return "{%s}" % ", ".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(['"%s"' % parameter.parameter_name for parameter in command.return_parameters]),
+ }
+ lines.append('InspectorBackend.registerCommand("%(domain)s.%(commandName)s", [%(callParams)s], [%(returnParams)s]);' % command_args)
+
+ if commands or events:
+ activate_args = {
+ 'domain': domain.domain_name,
+ 'availability': domain.availability,
+ }
+ if domain.availability:
+ lines.append('InspectorBackend.activateDomain("%(domain)s", "%(availability)s");' % activate_args)
+ else:
+ lines.append('InspectorBackend.activateDomain("%(domain)s");' % activate_args)
+
+ if domain.workerSupported:
+ lines.append('InspectorBackend.workerSupportedDomain("%s");' % domain.domain_name)
+
+ return "\n".join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py
new file mode 100755
index 000000000..0531ed53b
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+import re
+from string import Template
+
+from cpp_generator import CppGenerator
+from generator import Generator
+from models import Frameworks
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCBackendDispatcherHeaderGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sBackendDispatchers.h' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_commands_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ headers = [
+ '<JavaScriptCore/InspectorAlternateBackendDispatchers.h>',
+ '<wtf/RetainPtr.h>',
+ ]
+
+ header_args = {
+ 'includes': '\n'.join(['#include ' + header for header in headers]),
+ 'forwardDeclarations': self._generate_objc_forward_declarations(),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.BackendDispatcherHeaderPrelude).substitute(None, **header_args))
+ sections.extend(map(self._generate_objc_handler_declarations_for_domain, domains))
+ sections.append(Template(ObjCTemplates.BackendDispatcherHeaderPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_objc_forward_declarations(self):
+ lines = []
+ for domain in self.domains_to_generate():
+ if self.commands_for_domain(domain):
+ lines.append('@protocol %s%sDomainHandler;' % (self.objc_prefix(), domain.domain_name))
+ return '\n'.join(lines)
+
+ def _generate_objc_handler_declarations_for_domain(self, domain):
+ commands = self.commands_for_domain(domain)
+ if not commands:
+ return ''
+
+ command_declarations = []
+ for command in commands:
+ command_declarations.append(self._generate_objc_handler_declaration_for_command(command))
+
+ handler_args = {
+ 'domainName': domain.domain_name,
+ 'commandDeclarations': '\n'.join(command_declarations),
+ 'objcPrefix': self.objc_prefix(),
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(ObjCTemplates.BackendDispatcherHeaderDomainHandlerObjCDeclaration).substitute(None, **handler_args))
+
+ def _generate_objc_handler_declaration_for_command(self, command):
+ lines = []
+ parameters = ['long requestId']
+ for _parameter in command.call_parameters:
+ parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), _parameter.parameter_name))
+
+ command_args = {
+ 'commandName': command.command_name,
+ 'parameters': ', '.join(parameters),
+ }
+ lines.append(' virtual void %(commandName)s(%(parameters)s) override;' % command_args)
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py
new file mode 100755
index 000000000..0b1055d24
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 string
+import re
+from string import Template
+
+from cpp_generator import CppGenerator
+from generator import Generator
+from models import PrimitiveType, EnumType, AliasedType, Frameworks
+from objc_generator import ObjCTypeCategory, ObjCGenerator, join_type_and_name
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCBackendDispatcherImplementationGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sBackendDispatchers.mm' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_commands_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '"%sInternal.h"' % self.protocol_name(),
+ '"%sTypeConversions.h"' % self.protocol_name(),
+ '<JavaScriptCore/InspectorValues.h>',
+ ]
+
+ header_args = {
+ 'primaryInclude': '"%sBackendDispatchers.h"' % self.protocol_name(),
+ 'secondaryIncludes': '\n'.join(['#include %s' % header for header in secondary_headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.BackendDispatcherImplementationPrelude).substitute(None, **header_args))
+ sections.extend(map(self._generate_handler_implementation_for_domain, domains))
+ sections.append(Template(ObjCTemplates.BackendDispatcherImplementationPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_handler_implementation_for_domain(self, domain):
+ commands = self.commands_for_domain(domain)
+
+ if not commands:
+ return ''
+
+ command_declarations = []
+ for command in commands:
+ command_declarations.append(self._generate_handler_implementation_for_command(domain, command))
+
+ return '\n'.join(command_declarations)
+
+ def _generate_handler_implementation_for_command(self, domain, command):
+ lines = []
+ parameters = ['long requestId']
+ for parameter in command.call_parameters:
+ parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(parameter), parameter.parameter_name))
+
+ command_args = {
+ 'domainName': domain.domain_name,
+ 'commandName': command.command_name,
+ 'parameters': ', '.join(parameters),
+ 'successCallback': self._generate_success_block_for_command(domain, command),
+ 'conversions': self._generate_conversions_for_command(domain, command),
+ 'invocation': self._generate_invocation_for_command(domain, command),
+ }
+
+ return self.wrap_with_guard_for_domain(domain, Template(ObjCTemplates.BackendDispatcherHeaderDomainHandlerImplementation).substitute(None, **command_args))
+
+ def _generate_success_block_for_command(self, domain, command):
+ lines = []
+
+ if command.return_parameters:
+ success_block_parameters = []
+ for parameter in command.return_parameters:
+ objc_type = self.objc_type_for_param(domain, command.command_name, parameter)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ success_block_parameters.append(join_type_and_name(objc_type, var_name))
+ lines.append(' id successCallback = ^(%s) {' % ', '.join(success_block_parameters))
+ else:
+ lines.append(' id successCallback = ^{')
+
+ if command.return_parameters:
+ lines.append(' Ref<InspectorObject> resultObject = InspectorObject::create();')
+
+ required_pointer_parameters = filter(lambda parameter: not parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), command.return_parameters)
+ for parameter in required_pointer_parameters:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(%s, @"%s");' % (var_name, var_name))
+ objc_array_class = self.objc_class_for_array_type(parameter.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+
+ optional_pointer_parameters = filter(lambda parameter: parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), command.return_parameters)
+ for parameter in optional_pointer_parameters:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ lines.append(' THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(%s, @"%s");' % (var_name, var_name))
+ objc_array_class = self.objc_class_for_array_type(parameter.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_OPTIONAL_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+
+ for parameter in command.return_parameters:
+ keyed_set_method = CppGenerator.cpp_setter_method_for_type(parameter.type)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ var_expression = '*%s' % var_name if parameter.is_optional else var_name
+ export_expression = self.objc_protocol_export_expression_for_variable(parameter.type, var_expression)
+ if not parameter.is_optional:
+ lines.append(' resultObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression))
+ else:
+ lines.append(' if (%s)' % var_name)
+ lines.append(' resultObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression))
+ lines.append(' backendDispatcher()->sendResponse(requestId, WTFMove(resultObject));')
+ else:
+ lines.append(' backendDispatcher()->sendResponse(requestId, InspectorObject::create());')
+
+ lines.append(' };')
+ return '\n'.join(lines)
+
+ def _generate_conversions_for_command(self, domain, command):
+ lines = []
+ if command.call_parameters:
+ lines.append('')
+
+ def in_param_expression(param_name, parameter):
+ _type = parameter.type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through to enum or primitive.
+ if isinstance(_type, EnumType):
+ _type = _type.primitive_type # Fall through to primitive.
+ if isinstance(_type, PrimitiveType):
+ if _type.raw_name() in ['array', 'any', 'object']:
+ return '&%s' % param_name if not parameter.is_optional else param_name
+ return '*%s' % param_name if parameter.is_optional else param_name
+ return '&%s' % param_name if not parameter.is_optional else param_name
+
+ for parameter in command.call_parameters:
+ in_param_name = 'in_%s' % parameter.parameter_name
+ objc_in_param_name = 'o_%s' % in_param_name
+ objc_type = self.objc_type_for_param(domain, command.command_name, parameter, False)
+ if isinstance(parameter.type, EnumType):
+ objc_type = 'std::optional<%s>' % objc_type
+ param_expression = in_param_expression(in_param_name, parameter)
+ import_expression = self.objc_protocol_import_expression_for_parameter(param_expression, domain, command.command_name, parameter)
+ if not parameter.is_optional:
+ lines.append(' %s = %s;' % (join_type_and_name(objc_type, objc_in_param_name), import_expression))
+
+ if isinstance(parameter.type, EnumType):
+ lines.append(' if (!%s) {' % objc_in_param_name)
+ lines.append(' backendDispatcher()->reportProtocolError(BackendDispatcher::InvalidParams, String::format("Parameter \'%%s\' of method \'%%s\' cannot be processed", "%s", "%s.%s"));' % (parameter.parameter_name, domain.domain_name, command.command_name))
+ lines.append(' return;')
+ lines.append(' }')
+
+ else:
+ lines.append(' %s;' % join_type_and_name(objc_type, objc_in_param_name))
+ lines.append(' if (%s)' % in_param_name)
+ lines.append(' %s = %s;' % (objc_in_param_name, import_expression))
+
+ if lines:
+ lines.append('')
+ return '\n'.join(lines)
+
+ def _generate_invocation_for_command(self, domain, command):
+ pairs = []
+ pairs.append('WithErrorCallback:errorCallback')
+ pairs.append('successCallback:successCallback')
+ for parameter in command.call_parameters:
+ in_param_name = 'in_%s' % parameter.parameter_name
+ objc_in_param_expression = 'o_%s' % in_param_name
+ if not parameter.is_optional:
+ # FIXME: we don't handle optional enum values in commands here because it isn't used anywhere yet.
+ # We'd need to change the delegate's signature to take std::optional for optional enum values.
+ if isinstance(parameter.type, EnumType):
+ objc_in_param_expression = '%s.value()' % objc_in_param_expression
+
+ pairs.append('%s:%s' % (parameter.parameter_name, objc_in_param_expression))
+ else:
+ optional_expression = '(%s ? &%s : nil)' % (in_param_name, objc_in_param_expression)
+ pairs.append('%s:%s' % (parameter.parameter_name, optional_expression))
+ return ' [m_delegate %s%s];' % (command.command_name, ' '.join(pairs))
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_header.py
new file mode 100755
index 000000000..a232e2ce4
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_header.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCConfigurationHeaderGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sConfiguration.h' % self.protocol_name()
+
+ def generate_output(self):
+ headers = [
+ '<WebInspector/%s.h>' % self.protocol_name(),
+ ]
+
+ header_args = {
+ 'includes': '\n'.join(['#import ' + header for header in headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.GenericHeaderPrelude).substitute(None, **header_args))
+ sections.append(self._generate_configuration_interface_for_domains(domains))
+ sections.append(Template(ObjCTemplates.GenericHeaderPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_configuration_interface_for_domains(self, domains):
+ lines = []
+ lines.append('__attribute__((visibility ("default")))')
+ lines.append('@interface %sConfiguration : NSObject' % self.protocol_name())
+ for domain in domains:
+ lines.extend(self._generate_properties_for_domain(domain))
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_properties_for_domain(self, domain):
+ property_args = {
+ 'objcPrefix': self.objc_prefix(),
+ 'domainName': domain.domain_name,
+ 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain),
+ }
+
+ lines = []
+
+ if self.should_generate_commands_for_domain(domain):
+ lines.append(Template(ObjCTemplates.ConfigurationCommandProperty).substitute(None, **property_args))
+ if self.should_generate_events_for_domain(domain):
+ lines.append(Template(ObjCTemplates.ConfigurationEventProperty).substitute(None, **property_args))
+ return lines
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_implementation.py
new file mode 100755
index 000000000..910bcbab1
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_configuration_implementation.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCConfigurationImplementationGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sConfiguration.mm' % self.protocol_name()
+
+ def generate_output(self):
+ secondary_headers = [
+ '"%sInternal.h"' % self.protocol_name(),
+ '"%sBackendDispatchers.h"' % self.protocol_name(),
+ '<JavaScriptCore/AlternateDispatchableAgent.h>',
+ '<JavaScriptCore/AugmentableInspectorController.h>',
+ '<JavaScriptCore/InspectorAlternateBackendDispatchers.h>',
+ '<JavaScriptCore/InspectorBackendDispatchers.h>',
+ ]
+
+ header_args = {
+ 'primaryInclude': '"%sConfiguration.h"' % self.protocol_name(),
+ 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.append(self._generate_configuration_implementation_for_domains(domains))
+ sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_configuration_implementation_for_domains(self, domains):
+ lines = []
+ lines.append('@implementation %sConfiguration' % self.protocol_name())
+ lines.append('{')
+ lines.append(' AugmentableInspectorController* _controller;')
+ lines.extend(self._generate_ivars(domains))
+ lines.append('}')
+ lines.append('')
+ lines.append('- (instancetype)initWithController:(AugmentableInspectorController*)controller')
+ lines.append('{')
+ lines.append(' self = [super init];')
+ lines.append(' if (!self)')
+ lines.append(' return nil;')
+ lines.append(' ASSERT(controller);')
+ lines.append(' _controller = controller;')
+ lines.append(' return self;')
+ lines.append('}')
+ lines.append('')
+ lines.extend(self._generate_dealloc(domains))
+ lines.append('')
+ for domain in domains:
+ if self.should_generate_commands_for_domain(domain):
+ lines.append(self._generate_handler_setter_for_domain(domain))
+ lines.append('')
+ if self.should_generate_events_for_domain(domain):
+ lines.append(self._generate_event_dispatcher_getter_for_domain(domain))
+ lines.append('')
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_ivars(self, domains):
+ lines = []
+ for domain in domains:
+ if self.should_generate_commands_for_domain(domain):
+ objc_class_name = '%s%sDomainHandler' % (self.objc_prefix(), domain.domain_name)
+ ivar_name = '_%sHandler' % ObjCGenerator.variable_name_prefix_for_domain(domain)
+ lines.append(' id<%s> %s;' % (objc_class_name, ivar_name))
+ if self.should_generate_events_for_domain(domain):
+ objc_class_name = '%s%sDomainEventDispatcher' % (self.objc_prefix(), domain.domain_name)
+ ivar_name = '_%sEventDispatcher' % ObjCGenerator.variable_name_prefix_for_domain(domain)
+ lines.append(' %s *%s;' % (objc_class_name, ivar_name))
+ return lines
+
+ def _generate_dealloc(self, domains):
+ lines = []
+ lines.append('- (void)dealloc')
+ lines.append('{')
+ for domain in domains:
+ if self.should_generate_commands_for_domain(domain):
+ lines.append(' [_%sHandler release];' % ObjCGenerator.variable_name_prefix_for_domain(domain))
+ if self.should_generate_events_for_domain(domain):
+ lines.append(' [_%sEventDispatcher release];' % ObjCGenerator.variable_name_prefix_for_domain(domain))
+ lines.append(' [super dealloc];')
+ lines.append('}')
+ return lines
+
+ def _generate_handler_setter_for_domain(self, domain):
+ setter_args = {
+ 'objcPrefix': self.objc_prefix(),
+ 'domainName': domain.domain_name,
+ 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain),
+ }
+ return Template(ObjCTemplates.ConfigurationCommandPropertyImplementation).substitute(None, **setter_args)
+
+ def _generate_event_dispatcher_getter_for_domain(self, domain):
+ getter_args = {
+ 'objcPrefix': self.objc_prefix(),
+ 'domainName': domain.domain_name,
+ 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain),
+ }
+ return Template(ObjCTemplates.ConfigurationGetterImplementation).substitute(None, **getter_args)
+
+ def _variable_name_prefix_for_domain(self, domain):
+ domain_name = domain.domain_name
+ if domain_name.startswith('DOM'):
+ return 'dom' + domain_name[3:]
+ if domain_name.startswith('CSS'):
+ return 'css' + domain_name[3:]
+ return domain_name[:1].lower() + domain_name[1:]
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py
new file mode 100755
index 000000000..722d5d392
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014-2016 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 string
+from string import Template
+
+from cpp_generator import CppGenerator
+from generator import Generator, ucfirst
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCFrontendDispatcherImplementationGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sEventDispatchers.mm' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_events_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '"%sTypeConversions.h"' % self.protocol_name(),
+ '<JavaScriptCore/InspectorValues.h>',
+ ]
+
+ header_args = {
+ 'primaryInclude': '"%sInternal.h"' % self.protocol_name(),
+ 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.extend(map(self._generate_event_dispatcher_implementations, domains))
+ sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_event_dispatcher_implementations(self, domain):
+ if not self.should_generate_events_for_domain(domain):
+ return ''
+
+ lines = []
+ objc_name = '%s%sDomainEventDispatcher' % (self.objc_prefix(), domain.domain_name)
+ lines.append('@implementation %s' % objc_name)
+ lines.append('{')
+ lines.append(' AugmentableInspectorController* _controller;')
+ lines.append('}')
+ lines.append('')
+ lines.append('- (instancetype)initWithController:(AugmentableInspectorController*)controller;')
+ lines.append('{')
+ lines.append(' self = [super init];')
+ lines.append(' if (!self)')
+ lines.append(' return nil;')
+ lines.append(' ASSERT(controller);')
+ lines.append(' _controller = controller;')
+ lines.append(' return self;')
+ lines.append('}')
+ lines.append('')
+ for event in self.events_for_domain(domain):
+ lines.append(self._generate_event(domain, event))
+ lines.append('')
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_event(self, domain, event):
+ lines = []
+ lines.append(self._generate_event_signature(domain, event))
+ lines.append('{')
+ lines.append(' const FrontendRouter& router = _controller->frontendRouter();')
+ lines.append('')
+
+ required_pointer_parameters = filter(lambda parameter: not parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), event.event_parameters)
+ for parameter in required_pointer_parameters:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(%s, @"%s");' % (var_name, var_name))
+ objc_array_class = self.objc_class_for_array_type(parameter.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+
+ optional_pointer_parameters = filter(lambda parameter: parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), event.event_parameters)
+ for parameter in optional_pointer_parameters:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name)
+ lines.append(' THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(%s, @"%s");' % (var_name, var_name))
+ objc_array_class = self.objc_class_for_array_type(parameter.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_OPTIONAL_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+
+ if required_pointer_parameters or optional_pointer_parameters:
+ lines.append('')
+
+ lines.append(' Ref<InspectorObject> jsonMessage = InspectorObject::create();')
+ lines.append(' jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("%s.%s"));' % (domain.domain_name, event.event_name))
+ if event.event_parameters:
+ lines.extend(self._generate_event_out_parameters(domain, event))
+ lines.append(' router.sendEvent(jsonMessage->toJSONString());')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_event_signature(self, domain, event):
+ if not event.event_parameters:
+ return '- (void)%s' % event.event_name
+ pairs = []
+ for parameter in event.event_parameters:
+ param_name = parameter.parameter_name
+ pairs.append('%s:(%s)%s' % (param_name, self.objc_type_for_param(domain, event.event_name, parameter), param_name))
+ pairs[0] = ucfirst(pairs[0])
+ return '- (void)%sWith%s' % (event.event_name, ' '.join(pairs))
+
+ def _generate_event_out_parameters(self, domain, event):
+ lines = []
+ lines.append(' Ref<InspectorObject> paramsObject = InspectorObject::create();')
+ for parameter in event.event_parameters:
+ keyed_set_method = CppGenerator.cpp_setter_method_for_type(parameter.type)
+ var_name = parameter.parameter_name
+ safe_var_name = '(*%s)' % var_name if parameter.is_optional else var_name
+ export_expression = self.objc_protocol_export_expression_for_variable(parameter.type, safe_var_name)
+ if not parameter.is_optional:
+ lines.append(' paramsObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression))
+ else:
+ lines.append(' if (%s)' % (parameter.parameter_name))
+ lines.append(' paramsObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression))
+ lines.append(' jsonMessage->setObject(ASCIILiteral("params"), WTFMove(paramsObject));')
+ return lines
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_header.py
new file mode 100755
index 000000000..801f40a86
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_header.py
@@ -0,0 +1,245 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator, ucfirst
+from models import ObjectType, EnumType, Platforms
+from objc_generator import ObjCGenerator, join_type_and_name
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+def add_newline(lines):
+ if lines and lines[-1] == '':
+ return
+ lines.append('')
+
+
+class ObjCHeaderGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%s.h' % self.protocol_name()
+
+ def generate_output(self):
+ headers = set([
+ '<WebInspector/%sJSONObject.h>' % ObjCGenerator.OBJC_STATIC_PREFIX,
+ ])
+
+ header_args = {
+ 'includes': '\n'.join(['#import ' + header for header in sorted(headers)]),
+ }
+
+ domains = self.domains_to_generate()
+ type_domains = filter(self.should_generate_types_for_domain, domains)
+ command_domains = filter(self.should_generate_commands_for_domain, domains)
+ event_domains = filter(self.should_generate_events_for_domain, domains)
+
+ # FIXME: <https://webkit.org/b/138222> Web Inspector: Reduce unnecessary enums/types generated in ObjC Protocol Interfaces
+ # Currently we generate enums/types for all types in the type_domains. For the built-in
+ # JSC domains (Debugger, Runtime) this produces extra unused types. We only need to
+ # generate these types if they are referenced by the command_domains or event_domains.
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.HeaderPrelude).substitute(None, **header_args))
+ sections.append('\n'.join(filter(None, map(self._generate_forward_declarations, type_domains))))
+ sections.append(self._generate_enum_for_platforms())
+ sections.append('\n'.join(filter(None, map(self._generate_enums, type_domains))))
+ sections.append('\n'.join(filter(None, map(self._generate_types, type_domains))))
+
+ if self.get_generator_setting('generate_backend', False):
+ sections.append('\n\n'.join(filter(None, map(self._generate_command_protocols, command_domains))))
+ sections.append('\n\n'.join(filter(None, map(self._generate_event_interfaces, event_domains))))
+
+ sections.append(Template(ObjCTemplates.HeaderPostlude).substitute(None))
+ return '\n\n'.join(sections)
+
+ def _generate_forward_declarations(self, domain):
+ lines = []
+ for declaration in self.type_declarations_for_domain(domain):
+ if (isinstance(declaration.type, ObjectType)):
+ objc_name = self.objc_name_for_type(declaration.type)
+ lines.append('@class %s;' % objc_name)
+ return '\n'.join(lines)
+
+ def _generate_enums(self, domain):
+ lines = []
+
+ # Type enums and member enums.
+ for declaration in self.type_declarations_for_domain(domain):
+ if isinstance(declaration.type, EnumType):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_for_declaration(domain, declaration))
+ else:
+ for member in declaration.type_members:
+ if isinstance(member.type, EnumType) and member.type.is_anonymous:
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_for_member(domain, declaration, member))
+
+ # Anonymous command enums.
+ for command in self.commands_for_domain(domain):
+ for parameter in command.call_parameters:
+ if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous:
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_for_parameter(domain, command.command_name, parameter))
+ for parameter in command.return_parameters:
+ if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous:
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_for_parameter(domain, command.command_name, parameter))
+
+ # Anonymous event enums.
+ for event in self.events_for_domain(domain):
+ for parameter in event.event_parameters:
+ if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous:
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_for_parameter(domain, event.event_name, parameter))
+
+ return '\n'.join(lines)
+
+ def _generate_types(self, domain):
+ lines = []
+ # Type interfaces.
+ for declaration in self.type_declarations_for_domain(domain):
+ if isinstance(declaration.type, ObjectType):
+ add_newline(lines)
+ lines.append(self._generate_type_interface(domain, declaration))
+ return '\n'.join(lines)
+
+ def _generate_enum_for_platforms(self):
+ objc_enum_name = '%sPlatform' % self.objc_prefix()
+ enum_values = [platform.name for platform in Platforms]
+ return self._generate_enum(objc_enum_name, enum_values)
+
+ def _generate_anonymous_enum_for_declaration(self, domain, declaration):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_declaration(declaration)
+ return self._generate_enum(objc_enum_name, declaration.type.enum_values())
+
+ def _generate_anonymous_enum_for_member(self, domain, declaration, member):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_member(declaration, member)
+ return self._generate_enum(objc_enum_name, member.type.enum_values())
+
+ def _generate_anonymous_enum_for_parameter(self, domain, event_or_command_name, parameter):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter)
+ return self._generate_enum(objc_enum_name, parameter.type.enum_values())
+
+ def _generate_enum(self, enum_name, enum_values):
+ lines = []
+ lines.append('typedef NS_ENUM(NSInteger, %s) {' % enum_name)
+ for enum_value in enum_values:
+ lines.append(' %s%s,' % (enum_name, Generator.stylized_name_for_enum_value(enum_value)))
+ lines.append('};')
+ return '\n'.join(lines)
+
+ def _generate_type_interface(self, domain, declaration):
+ lines = []
+ objc_name = self.objc_name_for_type(declaration.type)
+ lines.append('__attribute__((visibility ("default")))')
+ lines.append('@interface %s : %sJSONObject' % (objc_name, ObjCGenerator.OBJC_STATIC_PREFIX))
+
+ # The initializers that take a payload or inspector object are only needed by the frontend.
+ if self.get_generator_setting('generate_frontend', False):
+ lines.append('- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;')
+ lines.append('- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject;')
+
+ required_members = filter(lambda member: not member.is_optional, declaration.type_members)
+ optional_members = filter(lambda member: member.is_optional, declaration.type_members)
+ if required_members:
+ lines.append(self._generate_init_method_for_required_members(domain, declaration, required_members))
+ for member in required_members:
+ lines.append('/* required */ ' + self._generate_member_property(declaration, member))
+ for member in optional_members:
+ lines.append('/* optional */ ' + self._generate_member_property(declaration, member))
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_init_method_for_required_members(self, domain, declaration, required_members):
+ pairs = []
+ for member in required_members:
+ objc_type = self.objc_type_for_member(declaration, member)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ pairs.append('%s:(%s)%s' % (var_name, objc_type, var_name))
+ pairs[0] = ucfirst(pairs[0])
+ return '- (instancetype)initWith%s;' % ' '.join(pairs)
+
+ def _generate_member_property(self, declaration, member):
+ accessor_type = self.objc_accessor_type_for_member(member)
+ objc_type = self.objc_type_for_member(declaration, member)
+ return '@property (nonatomic, %s) %s;' % (accessor_type, join_type_and_name(objc_type, ObjCGenerator.identifier_to_objc_identifier(member.member_name)))
+
+ def _generate_command_protocols(self, domain):
+ lines = []
+ if self.commands_for_domain(domain):
+ objc_name = '%s%sDomainHandler' % (self.objc_prefix(), domain.domain_name)
+ lines.append('@protocol %s <NSObject>' % objc_name)
+ lines.append('@required')
+ for command in self.commands_for_domain(domain):
+ lines.append(self._generate_single_command_protocol(domain, command))
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_single_command_protocol(self, domain, command):
+ pairs = []
+ pairs.append('ErrorCallback:(void(^)(NSString *error))errorCallback')
+ pairs.append('successCallback:(%s)successCallback' % self._callback_block_for_command(domain, command))
+ for parameter in command.call_parameters:
+ param_name = parameter.parameter_name
+ pairs.append('%s:(%s)%s' % (param_name, self.objc_type_for_param(domain, command.command_name, parameter), param_name))
+ return '- (void)%sWith%s;' % (command.command_name, ' '.join(pairs))
+
+ def _callback_block_for_command(self, domain, command):
+ pairs = []
+ for parameter in command.return_parameters:
+ pairs.append(join_type_and_name(self.objc_type_for_param(domain, command.command_name, parameter), parameter.parameter_name))
+ return 'void(^)(%s)' % ', '.join(pairs)
+
+ def _generate_event_interfaces(self, domain):
+ lines = []
+ events = self.events_for_domain(domain)
+ if len(events):
+ objc_name = '%s%sDomainEventDispatcher' % (self.objc_prefix(), domain.domain_name)
+ lines.append('__attribute__((visibility ("default")))')
+ lines.append('@interface %s : NSObject' % objc_name)
+ for event in events:
+ lines.append(self._generate_single_event_interface(domain, event))
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_single_event_interface(self, domain, event):
+ if not event.event_parameters:
+ return '- (void)%s;' % event.event_name
+ pairs = []
+ for parameter in event.event_parameters:
+ param_name = parameter.parameter_name
+ pairs.append('%s:(%s)%s' % (param_name, self.objc_type_for_param(domain, event.event_name, parameter), param_name))
+ pairs[0] = ucfirst(pairs[0])
+ return '- (void)%sWith%s;' % (event.event_name, ' '.join(pairs))
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_internal_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_internal_header.py
new file mode 100755
index 000000000..9f06ced40
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_internal_header.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator, ucfirst
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+class ObjCInternalHeaderGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sInternal.h' % self.protocol_name()
+
+ def generate_output(self):
+ headers = set([
+ '"%s.h"' % self.protocol_name(),
+ '"%sJSONObjectPrivate.h"' % self.protocol_name(),
+ '<JavaScriptCore/InspectorValues.h>',
+ '<JavaScriptCore/AugmentableInspectorController.h>',
+ ])
+
+ header_args = {
+ 'includes': '\n'.join(['#import ' + header for header in sorted(headers)]),
+ }
+
+ event_domains = filter(self.should_generate_events_for_domain, self.domains_to_generate())
+
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.GenericHeaderPrelude).substitute(None, **header_args))
+ sections.append('\n\n'.join(filter(None, map(self._generate_event_dispatcher_private_interfaces, event_domains))))
+ sections.append(Template(ObjCTemplates.GenericHeaderPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_event_dispatcher_private_interfaces(self, domain):
+ lines = []
+ if len(self.events_for_domain(domain)):
+ objc_name = '%s%sDomainEventDispatcher' % (self.objc_prefix(), domain.domain_name)
+ lines.append('@interface %s (Private)' % objc_name)
+ lines.append('- (instancetype)initWithController:(Inspector::AugmentableInspectorController*)controller;')
+ lines.append('@end')
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_header.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_header.py
new file mode 100755
index 000000000..ea9e6e2d7
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_header.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator
+from models import EnumType, Frameworks, Platforms
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+def add_newline(lines):
+ if lines and lines[-1] == '':
+ return
+ lines.append('')
+
+
+class ObjCProtocolTypeConversionsHeaderGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sTypeConversions.h' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_types_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ headers = [
+ '"%s.h"' % self.protocol_name(),
+ Generator.string_for_file_include('%sArrayConversions.h' % ObjCGenerator.OBJC_STATIC_PREFIX, Frameworks.WebInspector, self.model().framework),
+ ]
+ headers.sort()
+
+ header_args = {
+ 'includes': '\n'.join(['#import ' + header for header in headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.TypeConversionsHeaderPrelude).substitute(None, **header_args))
+ sections.append(Template(ObjCTemplates.TypeConversionsHeaderStandard).substitute(None))
+ sections.append(self._generate_enum_conversion_for_platforms())
+ sections.extend(map(self._generate_enum_conversion_functions, domains))
+ sections.append(Template(ObjCTemplates.TypeConversionsHeaderPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_enum_conversion_functions(self, domain):
+ lines = []
+
+ # Type enums and member enums.
+ for declaration in self.type_declarations_for_domain(domain):
+ if isinstance(declaration.type, EnumType):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_conversion_for_declaration(domain, declaration))
+ else:
+ for member in declaration.type_members:
+ if (isinstance(member.type, EnumType) and member.type.is_anonymous):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_conversion_for_member(domain, declaration, member))
+
+ # Anonymous command enums.
+ for command in self.commands_for_domain(domain):
+ for parameter in command.call_parameters:
+ if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, command.command_name, parameter))
+ for parameter in command.return_parameters:
+ if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, command.command_name, parameter))
+
+ # Anonymous event enums.
+ for event in self.events_for_domain(domain):
+ for parameter in event.event_parameters:
+ if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous):
+ add_newline(lines)
+ lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, event.event_name, parameter))
+
+ return '\n'.join(lines)
+
+ def _generate_enum_conversion_for_platforms(self):
+ objc_enum_name = '%sPlatform' % self.objc_prefix()
+ enum_values = [platform.name for platform in Platforms]
+ lines = []
+ lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values))
+ lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values))
+ return '\n\n'.join(lines)
+
+ def _generate_anonymous_enum_conversion_for_declaration(self, domain, declaration):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_declaration(declaration)
+ enum_values = declaration.type.enum_values()
+ lines = []
+ lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values))
+ lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values))
+ return '\n\n'.join(lines)
+
+ def _generate_anonymous_enum_conversion_for_member(self, domain, declaration, member):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_member(declaration, member)
+ enum_values = member.type.enum_values()
+ lines = []
+ lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values))
+ lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values))
+ return '\n\n'.join(lines)
+
+ def _generate_anonymous_enum_conversion_for_parameter(self, domain, event_or_command_name, parameter):
+ objc_enum_name = self.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter)
+ enum_values = parameter.type.enum_values()
+ lines = []
+ lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values))
+ lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values))
+ return '\n\n'.join(lines)
+
+ def _generate_enum_objc_to_protocol_string(self, objc_enum_name, enum_values):
+ lines = []
+ lines.append('inline String toProtocolString(%s value)' % objc_enum_name)
+ lines.append('{')
+ lines.append(' switch(value) {')
+ for enum_value in enum_values:
+ lines.append(' case %s%s:' % (objc_enum_name, Generator.stylized_name_for_enum_value(enum_value)))
+ lines.append(' return ASCIILiteral("%s");' % enum_value)
+ lines.append(' }')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_enum_from_protocol_string(self, objc_enum_name, enum_values):
+ lines = []
+ lines.append('template<>')
+ lines.append('inline std::optional<%s> fromProtocolString(const String& value)' % objc_enum_name)
+ lines.append('{')
+ for enum_value in enum_values:
+ lines.append(' if (value == "%s")' % enum_value)
+ lines.append(' return %s%s;' % (objc_enum_name, Generator.stylized_name_for_enum_value(enum_value)))
+ lines.append(' return std::nullopt;')
+ lines.append('}')
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_implementation.py
new file mode 100644
index 000000000..4293e3bd8
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_type_conversions_implementation.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 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 logging
+import string
+from string import Template
+
+from generator import Generator
+from models import EnumType, ObjectType, ArrayType, AliasedType, PrimitiveType, Frameworks
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+def add_newline(lines):
+ if lines and lines[-1] == '':
+ return
+ lines.append('')
+
+
+class ObjCProtocolTypeConversionsImplementationGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sTypeConversions.mm' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_types_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '"%s.h"' % self.protocol_name(),
+ '"%sTypeParser.h"' % self.protocol_name(),
+ Generator.string_for_file_include('%sJSONObjectPrivate.h' % ObjCGenerator.OBJC_STATIC_PREFIX, Frameworks.WebInspector, self.model().framework),
+ ]
+ secondary_headers.sort()
+
+ header_args = {
+ 'primaryInclude': '"%sTypeConversions.h"' % self.protocol_name(),
+ 'secondaryIncludes': '\n'.join(['#import ' + header for header in secondary_headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.append(self._generate_type_factory_category_interface(domains))
+ sections.append(self._generate_type_factory_category_implementation(domains))
+ sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def _generate_type_factory_category_interface(self, domains):
+ lines = []
+ for domain in domains:
+ lines.append('@interface %sTypeConversions (%sDomain)' % (self.protocol_name(), domain.domain_name))
+ lines.append('')
+
+ for declaration in self.type_declarations_for_domain(domain):
+ lines.append(self._generate_type_factory_method_declaration(domain, declaration))
+
+ add_newline(lines)
+ lines.append('@end')
+
+ return '\n'.join(lines)
+
+ def _generate_type_factory_method_declaration(self, domain, declaration):
+ resolved_type = declaration.type
+ if isinstance(resolved_type, AliasedType):
+ resolved_type = resolved_type.aliased_type
+ if isinstance(resolved_type, (ObjectType, ArrayType, PrimitiveType)):
+ objc_type = self.objc_class_for_type(resolved_type)
+ return '+ (void)_parse%s:(%s **)outValue fromPayload:(id)payload;' % (declaration.type.raw_name(), objc_type)
+ if isinstance(resolved_type, EnumType):
+ return '+ (void)_parse%s:(NSNumber **)outValue fromPayload:(id)payload;' % declaration.type.raw_name()
+
+ def _generate_type_factory_category_implementation(self, domains):
+ lines = []
+ for domain in domains:
+ lines.append('@implementation %sTypeConversions (%sDomain)' % (self.protocol_name(), domain.domain_name))
+ lines.append('')
+
+ for declaration in self.type_declarations_for_domain(domain):
+ lines.append(self._generate_type_factory_method_implementation(domain, declaration))
+ add_newline(lines)
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_type_factory_method_implementation(self, domain, declaration):
+ lines = []
+ resolved_type = declaration.type
+ if isinstance(resolved_type, AliasedType):
+ resolved_type = resolved_type.aliased_type
+
+ objc_class = self.objc_class_for_type(resolved_type)
+ if isinstance(resolved_type, (ObjectType, ArrayType, PrimitiveType)):
+ lines.append('+ (void)_parse%s:(%s **)outValue fromPayload:(id)payload' % (declaration.type.raw_name(), objc_class))
+ if isinstance(resolved_type, EnumType):
+ lines.append('+ (void)_parse%s:(NSNumber **)outValue fromPayload:(id)payload' % declaration.type.raw_name())
+
+ lines.append('{')
+ if isinstance(resolved_type, EnumType):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE(payload, [NSString class]);')
+ lines.append(' std::optional<%(type)s> result = Inspector::fromProtocolString<%(type)s>(payload);' % {'type': self.objc_name_for_type(resolved_type)})
+ lines.append(' THROW_EXCEPTION_FOR_BAD_ENUM_VALUE(result, @"%s");' % declaration.type.raw_name())
+ lines.append(' *outValue = @(result.value());')
+ elif isinstance(resolved_type, (ArrayType, PrimitiveType)):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE(payload, [%s class]);' % objc_class)
+ lines.append(' *outValue = (%s *)payload;' % objc_class)
+ elif isinstance(resolved_type, ObjectType):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE(payload, [NSDictionary class]);')
+ lines.append(' *outValue = [[%s alloc] initWithPayload:payload];' % (objc_class))
+ lines.append('}')
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py
new file mode 100755
index 000000000..a319c94d7
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 string
+from string import Template
+
+from generator import Generator, ucfirst
+from models import ObjectType, EnumType, Frameworks
+from objc_generator import ObjCGenerator
+from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates
+
+log = logging.getLogger('global')
+
+
+def add_newline(lines):
+ if lines and lines[-1] == '':
+ return
+ lines.append('')
+
+
+class ObjCProtocolTypesImplementationGenerator(ObjCGenerator):
+ def __init__(self, *args, **kwargs):
+ ObjCGenerator.__init__(self, *args, **kwargs)
+
+ def output_filename(self):
+ return '%sTypes.mm' % self.protocol_name()
+
+ def domains_to_generate(self):
+ return filter(self.should_generate_types_for_domain, Generator.domains_to_generate(self))
+
+ def generate_output(self):
+ secondary_headers = [
+ '"%sTypeConversions.h"' % self.protocol_name(),
+ Generator.string_for_file_include('%sJSONObjectPrivate.h' % ObjCGenerator.OBJC_STATIC_PREFIX, Frameworks.WebInspector, self.model().framework),
+ '<JavaScriptCore/InspectorValues.h>',
+ '<wtf/Assertions.h>',
+ ]
+
+ # The FooProtocolInternal.h header is only needed to declare the backend-side event dispatcher bindings.
+ primaryIncludeName = self.protocol_name()
+ if self.get_generator_setting('generate_backend', False):
+ primaryIncludeName += 'Internal'
+
+ header_args = {
+ 'primaryInclude': '"%s.h"' % primaryIncludeName,
+ 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]),
+ }
+
+ domains = self.domains_to_generate()
+ sections = []
+ sections.append(self.generate_license())
+ sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args))
+ sections.extend(map(self.generate_type_implementations, domains))
+ sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args))
+ return '\n\n'.join(sections)
+
+ def generate_type_implementations(self, domain):
+ lines = []
+ for declaration in self.type_declarations_for_domain(domain):
+ if (isinstance(declaration.type, ObjectType)):
+ add_newline(lines)
+ lines.append(self.generate_type_implementation(domain, declaration))
+ return '\n'.join(lines)
+
+ def generate_type_implementation(self, domain, declaration):
+ lines = []
+ lines.append('@implementation %s' % self.objc_name_for_type(declaration.type))
+ # The initializer that takes a payload is only needed by the frontend.
+ if self.get_generator_setting('generate_frontend', False):
+ lines.append('')
+ lines.append(self._generate_init_method_for_payload(domain, declaration))
+ lines.append(self._generate_init_method_for_json_object(domain, declaration))
+ required_members = filter(lambda member: not member.is_optional, declaration.type_members)
+ if required_members:
+ lines.append('')
+ lines.append(self._generate_init_method_for_required_members(domain, declaration, required_members))
+ for member in declaration.type_members:
+ lines.append('')
+ lines.append(self._generate_setter_for_member(domain, declaration, member))
+ lines.append('')
+ lines.append(self._generate_getter_for_member(domain, declaration, member))
+ lines.append('')
+ lines.append('@end')
+ return '\n'.join(lines)
+
+ def _generate_init_method_for_json_object(self, domain, declaration):
+ lines = []
+ lines.append('- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject')
+ lines.append('{')
+ lines.append(' if (!(self = [super initWithInspectorObject:[jsonObject toInspectorObject].get()]))')
+ lines.append(' return nil;')
+ lines.append('')
+ lines.append(' return self;')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_init_method_for_payload(self, domain, declaration):
+ lines = []
+ lines.append('- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload')
+ lines.append('{')
+ lines.append(' if (!(self = [super init]))')
+ lines.append(' return nil;')
+ lines.append('')
+
+ for member in declaration.type_members:
+ member_name = member.member_name
+
+ if not member.is_optional:
+ lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"%s"], @"%s");' % (member_name, member_name))
+
+ objc_type = self.objc_type_for_member(declaration, member)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member_name)
+ conversion_expression = self.payload_to_objc_expression_for_member(declaration, member)
+ if isinstance(member.type, EnumType):
+ lines.append(' std::optional<%s> %s = %s;' % (objc_type, var_name, conversion_expression))
+ if not member.is_optional:
+ lines.append(' THROW_EXCEPTION_FOR_BAD_ENUM_VALUE(%s, @"%s");' % (var_name, member_name))
+ lines.append(' self.%s = %s.value();' % (var_name, var_name))
+ else:
+ lines.append(' if (%s)' % var_name)
+ lines.append(' self.%s = %s.value();' % (var_name, var_name))
+ else:
+ lines.append(' self.%s = %s;' % (var_name, conversion_expression))
+
+ lines.append('')
+
+ lines.append(' return self;')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_init_method_for_required_members(self, domain, declaration, required_members):
+ pairs = []
+ for member in required_members:
+ objc_type = self.objc_type_for_member(declaration, member)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ pairs.append('%s:(%s)%s' % (var_name, objc_type, var_name))
+ pairs[0] = ucfirst(pairs[0])
+ lines = []
+ lines.append('- (instancetype)initWith%s' % ' '.join(pairs))
+ lines.append('{')
+ lines.append(' if (!(self = [super init]))')
+ lines.append(' return nil;')
+ lines.append('')
+
+ required_pointer_members = filter(lambda member: ObjCGenerator.is_type_objc_pointer_type(member.type), required_members)
+ if required_pointer_members:
+ for member in required_pointer_members:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(%s, @"%s");' % (var_name, var_name))
+ objc_array_class = self.objc_class_for_array_type(member.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+ lines.append('')
+
+ for member in required_members:
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ lines.append(' self.%s = %s;' % (var_name, var_name))
+
+ lines.append('')
+ lines.append(' return self;')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_setter_for_member(self, domain, declaration, member):
+ objc_type = self.objc_type_for_member(declaration, member)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ setter_method = ObjCGenerator.objc_setter_method_for_member(declaration, member)
+ conversion_expression = self.objc_to_protocol_expression_for_member(declaration, member, var_name)
+ lines = []
+ lines.append('- (void)set%s:(%s)%s' % (ucfirst(var_name), objc_type, var_name))
+ lines.append('{')
+ objc_array_class = self.objc_class_for_array_type(member.type)
+ if objc_array_class and objc_array_class.startswith(self.objc_prefix()):
+ lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class))
+ lines.append(' [super %s:%s forKey:@"%s"];' % (setter_method, conversion_expression, member.member_name))
+ lines.append('}')
+ return '\n'.join(lines)
+
+ def _generate_getter_for_member(self, domain, declaration, member):
+ objc_type = self.objc_type_for_member(declaration, member)
+ var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+ getter_method = ObjCGenerator.objc_getter_method_for_member(declaration, member)
+ basic_expression = '[super %s:@"%s"]' % (getter_method, member.member_name)
+ conversion_expression = self.protocol_to_objc_expression_for_member(declaration, member, basic_expression)
+ lines = []
+ lines.append('- (%s)%s' % (objc_type, var_name))
+ lines.append('{')
+ lines.append(' return %s;' % conversion_expression)
+ lines.append('}')
+ return '\n'.join(lines)
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/generator.py b/Source/JavaScriptCore/inspector/scripts/codegen/generator.py
new file mode 100755
index 000000000..2d33b94ea
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generator.py
@@ -0,0 +1,274 @@
+#!/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
+from string import Template
+
+from generator_templates import GeneratorTemplates as Templates
+from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks, Platforms
+
+log = logging.getLogger('global')
+
+
+def ucfirst(str):
+ return str[:1].upper() + str[1:]
+
+_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS = set(['API', 'CSS', 'DOM', 'HTML', 'JIT', 'XHR', 'XML', 'IOS', 'MacOS'])
+_ALWAYS_SPECIALCASED_ENUM_VALUE_LOOKUP_TABLE = dict([(s.upper(), s) for s in _ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS])
+
+# These objects are built manually by creating and setting InspectorValues.
+# Before sending these over the protocol, their shapes are checked against the specification.
+# So, any types referenced by these types require debug-only assertions that check values.
+# Calculating necessary assertions is annoying, and adds a lot of complexity to the generator.
+
+# FIXME: This should be converted into a property in JSON.
+_TYPES_NEEDING_RUNTIME_CASTS = set([
+ "Runtime.ObjectPreview",
+ "Runtime.RemoteObject",
+ "Runtime.PropertyDescriptor",
+ "Runtime.InternalPropertyDescriptor",
+ "Runtime.CollectionEntry",
+ "Debugger.FunctionDetails",
+ "Debugger.CallFrame",
+ "Canvas.TraceLog",
+ "Canvas.ResourceInfo",
+ "Canvas.ResourceState",
+ # This should be a temporary hack. TimelineEvent should be created via generated C++ API.
+ "Timeline.TimelineEvent",
+ # For testing purposes only.
+ "Test.TypeNeedingCast"
+])
+
+# FIXME: This should be converted into a property in JSON.
+_TYPES_WITH_OPEN_FIELDS = set([
+ "Timeline.TimelineEvent",
+ # InspectorStyleSheet not only creates this property but wants to read it and modify it.
+ "CSS.CSSProperty",
+ # InspectorNetworkAgent needs to update mime-type.
+ "Network.Response",
+ # For testing purposes only.
+ "Test.OpenParameterBundle"
+])
+
+
+class Generator:
+ def __init__(self, model, platform, input_filepath):
+ self._model = model
+ self._platform = platform
+ self._input_filepath = input_filepath
+ self._settings = {}
+
+ def model(self):
+ return self._model
+
+ def platform(self):
+ return self._platform
+
+ def set_generator_setting(self, key, value):
+ self._settings[key] = value
+
+ def can_generate_platform(self, model_platform):
+ return model_platform is Platforms.Generic or self._platform is Platforms.All or model_platform is self._platform
+
+ def type_declarations_for_domain(self, domain):
+ return [type_declaration for type_declaration in domain.all_type_declarations() if self.can_generate_platform(type_declaration.platform)]
+
+ def commands_for_domain(self, domain):
+ return [command for command in domain.all_commands() if self.can_generate_platform(command.platform)]
+
+ def events_for_domain(self, domain):
+ return [event for event in domain.all_events() if self.can_generate_platform(event.platform)]
+
+ # The goofy name is to disambiguate generator settings from framework settings.
+ def get_generator_setting(self, key, default=None):
+ return self._settings.get(key, default)
+
+ def generate_license(self):
+ return Template(Templates.CopyrightBlock).substitute(None, inputFilename=os.path.basename(self._input_filepath))
+
+ # These methods are overridden by subclasses.
+ def non_supplemental_domains(self):
+ return filter(lambda domain: not domain.is_supplemental, self.model().domains)
+
+ def domains_to_generate(self):
+ return self.non_supplemental_domains()
+
+ def generate_output(self):
+ pass
+
+ def output_filename(self):
+ pass
+
+ def encoding_for_enum_value(self, enum_value):
+ if not hasattr(self, "_assigned_enum_values"):
+ self._traverse_and_assign_enum_values()
+
+ return self._enum_value_encodings[enum_value]
+
+ def assigned_enum_values(self):
+ if not hasattr(self, "_assigned_enum_values"):
+ self._traverse_and_assign_enum_values()
+
+ return self._assigned_enum_values[:] # Slice.
+
+ @staticmethod
+ def type_needs_runtime_casts(_type):
+ return _type.qualified_name() in _TYPES_NEEDING_RUNTIME_CASTS
+
+ @staticmethod
+ def type_has_open_fields(_type):
+ return _type.qualified_name() in _TYPES_WITH_OPEN_FIELDS
+
+ def type_needs_shape_assertions(self, _type):
+ if not hasattr(self, "_types_needing_shape_assertions"):
+ self.calculate_types_requiring_shape_assertions(self.model().domains)
+
+ return _type in self._types_needing_shape_assertions
+
+ # To restrict the domains over which we compute types needing assertions, call this method
+ # before generating any output with the desired domains parameter. The computed
+ # set of types will not be automatically regenerated on subsequent calls to
+ # Generator.types_needing_shape_assertions().
+ def calculate_types_requiring_shape_assertions(self, domains):
+ domain_names = map(lambda domain: domain.domain_name, domains)
+ log.debug("> Calculating types that need shape assertions (eligible domains: %s)" % ", ".join(domain_names))
+
+ # Mutates the passed-in set; this simplifies checks to prevent infinite recursion.
+ def gather_transitively_referenced_types(_type, gathered_types):
+ if _type in gathered_types:
+ return
+
+ if isinstance(_type, ObjectType):
+ log.debug("> Adding type %s to list of types needing shape assertions." % _type.qualified_name())
+ gathered_types.add(_type)
+ for type_member in _type.members:
+ gather_transitively_referenced_types(type_member.type, gathered_types)
+ elif isinstance(_type, EnumType):
+ log.debug("> Adding type %s to list of types needing shape assertions." % _type.qualified_name())
+ gathered_types.add(_type)
+ elif isinstance(_type, AliasedType):
+ gather_transitively_referenced_types(_type.aliased_type, gathered_types)
+ elif isinstance(_type, ArrayType):
+ gather_transitively_referenced_types(_type.element_type, gathered_types)
+
+ found_types = set()
+ for domain in domains:
+ for declaration in self.type_declarations_for_domain(domain):
+ if declaration.type.qualified_name() in _TYPES_NEEDING_RUNTIME_CASTS:
+ log.debug("> Gathering types referenced by %s to generate shape assertions." % declaration.type.qualified_name())
+ gather_transitively_referenced_types(declaration.type, found_types)
+
+ self._types_needing_shape_assertions = found_types
+
+ # Private helper instance methods.
+ def _traverse_and_assign_enum_values(self):
+ self._enum_value_encodings = {}
+ self._assigned_enum_values = []
+ all_types = []
+
+ domains = self.non_supplemental_domains()
+
+ for domain in domains:
+ for type_declaration in self.type_declarations_for_domain(domain):
+ all_types.append(type_declaration.type)
+ for type_member in type_declaration.type_members:
+ all_types.append(type_member.type)
+
+ for domain in domains:
+ for event in self.events_for_domain(domain):
+ all_types.extend([parameter.type for parameter in event.event_parameters])
+
+ for domain in domains:
+ for command in self.commands_for_domain(domain):
+ all_types.extend([parameter.type for parameter in command.call_parameters])
+ all_types.extend([parameter.type for parameter in command.return_parameters])
+
+ for _type in all_types:
+ if not isinstance(_type, EnumType):
+ continue
+ map(self._assign_encoding_for_enum_value, _type.enum_values())
+
+ def _assign_encoding_for_enum_value(self, enum_value):
+ if enum_value in self._enum_value_encodings:
+ return
+
+ self._enum_value_encodings[enum_value] = len(self._assigned_enum_values)
+ self._assigned_enum_values.append(enum_value)
+
+ # Miscellaneous text manipulation routines.
+ def wrap_with_guard_for_domain(self, domain, text):
+ if self.model().framework is Frameworks.WebInspector:
+ return text
+ guard = domain.feature_guard
+ if guard:
+ return Generator.wrap_with_guard(guard, text)
+ return text
+
+ @staticmethod
+ def wrap_with_guard(guard, text):
+ return '\n'.join([
+ '#if %s' % guard,
+ text,
+ '#endif // %s' % guard,
+ ])
+
+ @staticmethod
+ def stylized_name_for_enum_value(enum_value):
+ regex = '(%s)' % "|".join(_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS)
+
+ def replaceCallback(match):
+ return _ALWAYS_SPECIALCASED_ENUM_VALUE_LOOKUP_TABLE[match.group(1).upper()]
+
+ # Split on hyphen, introduce camelcase, and force uppercasing of acronyms.
+ subwords = map(ucfirst, enum_value.split('-'))
+ return re.sub(re.compile(regex, re.IGNORECASE), replaceCallback, "".join(subwords))
+
+ @staticmethod
+ def js_name_for_parameter_type(_type):
+ _type = _type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type # Fall through.
+ if isinstance(_type, EnumType):
+ _type = _type.primitive_type # Fall through.
+
+ if isinstance(_type, (ArrayType, ObjectType)):
+ return 'object'
+ if isinstance(_type, PrimitiveType):
+ if _type.qualified_name() in ['object', 'any']:
+ return 'object'
+ elif _type.qualified_name() in ['integer', 'number']:
+ return 'number'
+ else:
+ return _type.qualified_name()
+
+ @staticmethod
+ def string_for_file_include(filename, file_framework, target_framework):
+ if file_framework is target_framework:
+ return '"%s"' % filename
+ else:
+ return '<%s/%s>' % (file_framework.name, filename)
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 000000000..891681ffd
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from ${inputFilename}
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py""")
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/models.py b/Source/JavaScriptCore/inspector/scripts/codegen/models.py
new file mode 100755
index 000000000..b286a5c40
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/models.py
@@ -0,0 +1,680 @@
+#!/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 collections
+
+log = logging.getLogger('global')
+
+
+def ucfirst(str):
+ return str[:1].upper() + str[1:]
+
+
+def find_duplicates(l):
+ return [key for key, count in collections.Counter(l).items() if count > 1]
+
+
+_FRAMEWORK_CONFIG_MAP = {
+ "Global": {
+ },
+ "JavaScriptCore": {
+ "cpp_protocol_group": "Inspector",
+ "export_macro": "JS_EXPORT_PRIVATE",
+ "alternate_dispatchers": True,
+ },
+ "WebKit": {
+ "cpp_protocol_group": "Automation",
+ "objc_protocol_group": "WD",
+ "objc_prefix": "WD",
+ },
+ "WebInspector": {
+ "objc_protocol_group": "RWI",
+ "objc_prefix": "RWI",
+ },
+ # Used for code generator tests.
+ "Test": {
+ "alternate_dispatchers": True,
+ "cpp_protocol_group": "Test",
+ "objc_protocol_group": "Test",
+ "objc_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 == "JavaScriptCore":
+ return Frameworks.JavaScriptCore
+
+ if frameworkString == "WebKit":
+ return Frameworks.WebKit
+
+ if frameworkString == "WebInspector":
+ return Frameworks.WebInspector
+
+ if frameworkString == "Test":
+ return Frameworks.Test
+
+ raise ParseException("Unknown framework: %s" % frameworkString)
+
+
+class Frameworks:
+ Global = Framework("Global")
+ JavaScriptCore = Framework("JavaScriptCore")
+ WebKit = Framework("WebKit")
+ WebInspector = Framework("WebInspector")
+ Test = Framework("Test")
+
+
+class Platform:
+ def __init__(self, name):
+ self.name = name
+
+ @staticmethod
+ def fromString(platformString):
+ platformString = platformString.lower()
+ if platformString == "ios":
+ return Platforms.iOS
+
+ if platformString == "macos":
+ return Platforms.macOS
+
+ if platformString == "all":
+ return Platforms.All
+
+ if platformString == "generic" or not platformString:
+ return Platforms.Generic
+
+ raise ParseException("Unknown platform: %s" % platformString)
+
+
+class Platforms:
+ All = Platform("all")
+ Generic = Platform("generic")
+ iOS = Platform("ios")
+ macOS = Platform("macos")
+
+ # Allow iteration over all platforms. See <http://stackoverflow.com/questions/5434400/>.
+ class __metaclass__(type):
+ def __iter__(self):
+ for attr in dir(Platforms):
+ if not attr.startswith("__"):
+ yield getattr(Platforms, attr)
+
+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.")
+
+ all_primitive_types = ["integer", "number", "string", "boolean", "enum", "object", "array", "any"]
+ if type_kind is not None and type_kind not in all_primitive_types:
+ raise ParseException("Type reference '%s' is not a primitive type. Allowed values: %s" % (type_kind, ', '.join(all_primitive_types)))
+
+ 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.")
+
+ if enum_values is not None and len(enum_values) == 0:
+ raise ParseException("Type reference with enum values must have at least one enum value.")
+
+ def referenced_name(self):
+ if self.referenced_type_name is not None:
+ return self.referenced_type_name
+ else:
+ return self.type_kind # one of all_primitive_types
+
+
+class Type:
+ def __init__(self):
+ pass
+
+ def __eq__(self, other):
+ return self.qualified_name() == other.qualified_name()
+
+ def __hash__(self):
+ return self.qualified_name().__hash__()
+
+ def raw_name(self):
+ return self._name
+
+ # These methods should be overridden by subclasses.
+ def is_enum(self):
+ return False
+
+ def type_domain(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
+
+
+class PrimitiveType(Type):
+ def __init__(self, name):
+ self._name = name
+
+ def __repr__(self):
+ return 'PrimitiveType[%s]' % self.qualified_name()
+
+ def type_domain(self):
+ return None
+
+ def qualified_name(self):
+ return self.raw_name()
+
+
+class AliasedType(Type):
+ def __init__(self, declaration, domain, aliased_type_ref):
+ self._name = declaration.type_name
+ self._declaration = declaration
+ self._domain = domain
+ self._aliased_type_ref = aliased_type_ref
+ self.aliased_type = None
+
+ def __repr__(self):
+ if self.aliased_type is not None:
+ return 'AliasedType[%s -> %r]' % (self.qualified_name(), self.aliased_type)
+ else:
+ return 'AliasedType[%s -> (unresolved)]' % self.qualified_name()
+
+ def is_enum(self):
+ return self.aliased_type.is_enum()
+
+ def type_domain(self):
+ return self._domain
+
+ def qualified_name(self):
+ return ".".join([self.type_domain().domain_name, self.raw_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()))
+
+
+class EnumType(Type):
+ def __init__(self, declaration, domain, values, primitive_type_ref, is_anonymous=False):
+ self._name = "(anonymous)" if declaration is None else declaration.type_name
+ self._declaration = declaration
+ self._domain = domain
+ self._values = values
+ self._primitive_type_ref = primitive_type_ref
+ self.primitive_type = None
+ self.is_anonymous = is_anonymous
+
+ def __repr__(self):
+ return 'EnumType[value_type=%s; values=%s]' % (self.qualified_name(), ', '.join(map(str, self.enum_values())))
+
+ def is_enum(self):
+ return True
+
+ def enum_values(self):
+ return self._values
+
+ def type_domain(self):
+ return self._domain
+
+ def declaration(self):
+ return self._declaration
+
+ def qualified_name(self):
+ return ".".join([self.type_domain().domain_name, self.raw_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.enum_values())
+
+
+class ArrayType(Type):
+ def __init__(self, declaration, element_type_ref, domain):
+ self._name = None if declaration is None else declaration.type_name
+ self._declaration = declaration
+ self._domain = domain
+ self._element_type_ref = element_type_ref
+ self.element_type = None
+
+ def __repr__(self):
+ if self.element_type is not None:
+ return 'ArrayType[element_type=%r]' % self.element_type
+ else:
+ return 'ArrayType[element_type=(unresolved)]'
+
+ def declaration(self):
+ return self._declaration
+
+ def type_domain(self):
+ return self._domain
+
+ def qualified_name(self):
+ return ".".join(["array", 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()))
+
+
+class ObjectType(Type):
+ def __init__(self, declaration, domain):
+ self._name = declaration.type_name
+ self._declaration = declaration
+ self._domain = domain
+ self.members = declaration.type_members
+
+ def __repr__(self):
+ return 'ObjectType[%s]' % self.qualified_name()
+
+ def declaration(self):
+ return self._declaration
+
+ def type_domain(self):
+ return self._domain
+
+ def qualified_name(self):
+ return ".".join([self.type_domain().domain_name, self.raw_name()])
+
+
+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 domain 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 domain 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 domain specification: events is not an array")
+ events.extend([self.parse_event(event) for event in json['events']])
+
+ if 'availability' in json:
+ if not commands and not events:
+ raise ParseException("Malformed domain specification: availability should only be included if there are commands or events.")
+ allowed_activation_strings = set(['web'])
+ if json['availability'] not in allowed_activation_strings:
+ raise ParseException('Malformed domain specification: availability is an unsupported string. Was: "%s", Allowed values: %s' % (json['availability'], ', '.join(allowed_activation_strings)))
+
+ if 'workerSupported' in json:
+ if not isinstance(json['workerSupported'], bool):
+ raise ParseException('Malformed domain specification: workerSupported is not a boolean. Was: "%s"' % json['availability'])
+
+ self.domains.append(Domain(json['domain'], json.get('description', ''), json.get('featureGuard'), json.get('availability'), json.get('workerSupported', False), 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 type specification: properties is not an array")
+ type_members.extend([self.parse_type_member(member) for member in json['properties']])
+
+ duplicate_names = find_duplicates([member.member_name for member in type_members])
+ if len(duplicate_names) > 0:
+ raise ParseException("Malformed domain specification: type declaration for %s has duplicate member names" % json['id'])
+
+ type_ref = TypeReference(json['type'], json.get('$ref'), json.get('enum'), json.get('items'))
+ platform = Platform.fromString(json.get('platform', 'generic'))
+ return TypeDeclaration(json['id'], type_ref, json.get("description", ""), platform, 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 command specification: parameters is not an array")
+ call_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']])
+
+ duplicate_names = find_duplicates([param.parameter_name for param in call_parameters])
+ if len(duplicate_names) > 0:
+ raise ParseException("Malformed domain specification: call parameter list for command %s has duplicate parameter names" % json['name'])
+
+ if 'returns' in json:
+ if not isinstance(json['returns'], list):
+ raise ParseException("Malformed command specification: returns is not an array")
+ return_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['returns']])
+
+ duplicate_names = find_duplicates([param.parameter_name for param in return_parameters])
+ if len(duplicate_names) > 0:
+ raise ParseException("Malformed domain specification: return parameter list for command %s has duplicate parameter names" % json['name'])
+
+ platform = Platform.fromString(json.get('platform', 'generic'))
+ return Command(json['name'], call_parameters, return_parameters, json.get('description', ""), platform, 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 event specification: parameters is not an array")
+ event_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']])
+
+ duplicate_names = find_duplicates([param.parameter_name for param in event_parameters])
+ if len(duplicate_names) > 0:
+ raise ParseException("Malformed domain specification: parameter list for event %s has duplicate parameter names" % json['name'])
+
+ platform = Platform.fromString(json.get('platform', 'generic'))
+ return Event(json['name'], event_parameters, json.get('description', ""), platform)
+
+ def parse_call_or_return_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')
+ for _primitive_type in ['boolean', 'integer', 'number']:
+ self.types_by_name[_primitive_type] = PrimitiveType(_primitive_type)
+ for _object_type in ['any', 'object']:
+ self.types_by_name[_object_type] = PrimitiveType(_object_type)
+
+ # Gather qualified type names from type declarations in each domain.
+ for domain in self.domains:
+ for declaration in domain.all_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 declaration.type_ref.enum_values is not None:
+ primitive_type_ref = TypeReference(declaration.type_ref.type_kind, None, None, None)
+ type_instance = EnumType(declaration, domain, declaration.type_ref.enum_values, primitive_type_ref)
+ elif kind == "array":
+ type_instance = ArrayType(declaration, declaration.type_ref.array_type_ref, domain)
+ elif kind == "object":
+ type_instance = ObjectType(declaration, domain)
+ else:
+ type_instance = AliasedType(declaration, domain, declaration.type_ref)
+
+ log.debug("< Created fresh type %r for declaration %s" % (type_instance, qualified_type_name))
+ 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 = ArrayType(None, 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 type_ref.enum_values is not None:
+ # 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, None)
+ type_instance = EnumType(None, domain, type_ref.enum_values, primitive_type_ref, True)
+ 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, feature_guard, availability, workerSupported, isSupplemental, type_declarations, commands, events):
+ self.domain_name = domain_name
+ self.description = description
+ self.feature_guard = feature_guard
+ self.availability = availability
+ self.workerSupported = workerSupported
+ self.is_supplemental = isSupplemental
+ self._type_declarations = type_declarations
+ self._commands = commands
+ self._events = events
+
+ def all_type_declarations(self):
+ return self._type_declarations
+
+ def all_commands(self):
+ return self._commands
+
+ def all_events(self):
+ return self._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.", None, None, True, False, [], [], [])
+
+
+class TypeDeclaration:
+ def __init__(self, type_name, type_ref, description, platform, type_members):
+ self.type_name = type_name
+ self.type_ref = type_ref
+ self.description = description
+ self.platform = platform
+ self.type_members = type_members
+
+ if self.type_name != ucfirst(self.type_name):
+ raise ParseException("Types must begin with an uppercase character.")
+
+ 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
+
+ if not isinstance(self.is_optional, bool):
+ raise ParseException("The 'optional' flag for a type member must be a boolean literal.")
+
+ 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
+
+ if not isinstance(self.is_optional, bool):
+ raise ParseException("The 'optional' flag for a parameter must be a boolean literal.")
+
+ 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, platform, is_async):
+ self.command_name = command_name
+ self.call_parameters = call_parameters
+ self.return_parameters = return_parameters
+ self.description = description
+ self.platform = platform
+ 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, platform):
+ self.event_name = event_name
+ self.event_parameters = event_parameters
+ self.description = description
+ self.platform = platform
+
+ 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/codegen/objc_generator.py b/Source/JavaScriptCore/inspector/scripts/codegen/objc_generator.py
new file mode 100755
index 000000000..21e179148
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/objc_generator.py
@@ -0,0 +1,554 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 2016 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 logging
+from generator import Generator, ucfirst
+from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks
+
+log = logging.getLogger('global')
+
+
+def join_type_and_name(type_str, name_str):
+ if type_str.endswith('*'):
+ return type_str + name_str
+ return type_str + ' ' + name_str
+
+
+def strip_block_comment_markers(str):
+ return str.replace('/*', '').replace('*/', '')
+
+
+def remove_duplicate_from_str(str, possible_duplicate):
+ return str.replace(possible_duplicate + possible_duplicate, possible_duplicate)
+
+
+_OBJC_IDENTIFIER_RENAME_MAP = {
+ 'this': 'thisObject', # Debugger.CallFrame.this
+ 'description': 'stringRepresentation', # Runtime.RemoteObject.description
+ 'id': 'identifier', # Page.Frame.id, Runtime.ExecutionContextDescription.id, Debugger.BreakpointAction.id
+}
+
+_OBJC_IDENTIFIER_REVERSE_RENAME_MAP = dict((v, k) for k, v in _OBJC_IDENTIFIER_RENAME_MAP.iteritems())
+
+
+class ObjCTypeCategory:
+ Simple = 0
+ String = 1
+ Object = 2
+ Array = 3
+
+ @staticmethod
+ def category_for_type(_type):
+ if (isinstance(_type, PrimitiveType)):
+ if _type.raw_name() is 'string':
+ return ObjCTypeCategory.String
+ if _type.raw_name() in ['object', 'any']:
+ return ObjCTypeCategory.Object
+ if _type.raw_name() is 'array':
+ return ObjCTypeCategory.Array
+ return ObjCTypeCategory.Simple
+ if (isinstance(_type, ObjectType)):
+ return ObjCTypeCategory.Object
+ if (isinstance(_type, ArrayType)):
+ return ObjCTypeCategory.Array
+ if (isinstance(_type, AliasedType)):
+ return ObjCTypeCategory.category_for_type(_type.aliased_type)
+ if (isinstance(_type, EnumType)):
+ return ObjCTypeCategory.category_for_type(_type.primitive_type)
+ return None
+
+# Almost all Objective-C class names require the use of a prefix that depends on the
+# target framework's 'objc_prefix' setting. So, most helpers are instance methods.
+
+class ObjCGenerator(Generator):
+ # Do not use a dynamic prefix for RWIProtocolJSONObject since it's used as a common
+ # base class and needs a consistent Objective-C prefix to be in a reusable framework.
+ OBJC_HELPER_PREFIX = 'RWI'
+ OBJC_SHARED_PREFIX = 'Protocol'
+ OBJC_STATIC_PREFIX = '%s%s' % (OBJC_HELPER_PREFIX, OBJC_SHARED_PREFIX)
+
+ def __init__(self, *args, **kwargs):
+ Generator.__init__(self, *args, **kwargs)
+
+ # The 'protocol name' is used to prefix filenames for a protocol group (a set of domains generated together).
+ def protocol_name(self):
+ protocol_group = self.model().framework.setting('objc_protocol_group', '')
+ return '%s%s' % (protocol_group, ObjCGenerator.OBJC_SHARED_PREFIX)
+
+ # The 'ObjC prefix' is used to prefix Objective-C class names and enums with a
+ # framework-specific prefix. It is separate from filename prefixes.
+ def objc_prefix(self):
+ framework_prefix = self.model().framework.setting('objc_prefix', None)
+ if not framework_prefix:
+ return ''
+ else:
+ return '%s%s' % (framework_prefix, ObjCGenerator.OBJC_SHARED_PREFIX)
+
+ # Adjust identifier names that collide with ObjC keywords.
+
+ @staticmethod
+ def identifier_to_objc_identifier(name):
+ return _OBJC_IDENTIFIER_RENAME_MAP.get(name, name)
+
+ @staticmethod
+ def objc_identifier_to_identifier(name):
+ return _OBJC_IDENTIFIER_REVERSE_RENAME_MAP.get(name, name)
+
+ # Generate ObjC types, command handlers, and event dispatchers for a subset of domains.
+
+ DOMAINS_TO_GENERATE = ['CSS', 'DOM', 'DOMStorage', 'Network', 'Page', 'Automation', 'GenericTypes']
+
+ def should_generate_types_for_domain(self, domain):
+ if not len(self.type_declarations_for_domain(domain)):
+ return False
+
+ if self.model().framework is Frameworks.Test:
+ return True
+
+ whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE)
+ whitelist.update(set(['Console', 'Debugger', 'Runtime']))
+ return domain.domain_name in whitelist
+
+ def should_generate_commands_for_domain(self, domain):
+ if not len(self.commands_for_domain(domain)):
+ return False
+
+ if self.model().framework is Frameworks.Test:
+ return True
+
+ whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE)
+ return domain.domain_name in whitelist
+
+ def should_generate_events_for_domain(self, domain):
+ if not len(self.events_for_domain(domain)):
+ return False
+
+ if self.model().framework is Frameworks.Test:
+ return True
+
+ whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE)
+ whitelist.add('Console')
+ return domain.domain_name in whitelist
+
+ # ObjC enum and type names.
+
+ def objc_name_for_type(self, type):
+ name = type.qualified_name().replace('.', '')
+ name = remove_duplicate_from_str(name, type.type_domain().domain_name)
+ return '%s%s' % (self.objc_prefix(), name)
+
+ def objc_enum_name_for_anonymous_enum_declaration(self, declaration):
+ domain_name = declaration.type.type_domain().domain_name
+ name = '%s%s' % (domain_name, declaration.type.raw_name())
+ name = remove_duplicate_from_str(name, domain_name)
+ return '%s%s' % (self.objc_prefix(), name)
+
+ def objc_enum_name_for_anonymous_enum_member(self, declaration, member):
+ domain_name = member.type.type_domain().domain_name
+ name = '%s%s%s' % (domain_name, declaration.type.raw_name(), ucfirst(member.member_name))
+ name = remove_duplicate_from_str(name, domain_name)
+ return '%s%s' % (self.objc_prefix(), name)
+
+ def objc_enum_name_for_anonymous_enum_parameter(self, domain, event_or_command_name, parameter):
+ domain_name = domain.domain_name
+ name = '%s%s%s' % (domain_name, ucfirst(event_or_command_name), ucfirst(parameter.parameter_name))
+ name = remove_duplicate_from_str(name, domain_name)
+ return '%s%s' % (self.objc_prefix(), name)
+
+ def objc_enum_name_for_non_anonymous_enum(self, _type):
+ domain_name = _type.type_domain().domain_name
+ name = _type.qualified_name().replace('.', '')
+ name = remove_duplicate_from_str(name, domain_name)
+ return '%s%s' % (self.objc_prefix(), name)
+
+ # Miscellaneous name handling.
+
+ @staticmethod
+ def variable_name_prefix_for_domain(domain):
+ domain_name = domain.domain_name
+ if domain_name.startswith('DOM'):
+ return 'dom' + domain_name[3:]
+ if domain_name.startswith('CSS'):
+ return 'css' + domain_name[3:]
+ return domain_name[:1].lower() + domain_name[1:]
+
+ # Type basics.
+
+ @staticmethod
+ def objc_accessor_type_for_raw_name(raw_name):
+ if raw_name in ['string', 'array']:
+ return 'copy'
+ if raw_name in ['integer', 'number', 'boolean']:
+ return 'assign'
+ if raw_name in ['any', 'object']:
+ return 'retain'
+ return None
+
+ @staticmethod
+ def objc_type_for_raw_name(raw_name):
+ if raw_name is 'string':
+ return 'NSString *'
+ if raw_name is 'array':
+ return 'NSArray *'
+ if raw_name is 'integer':
+ return 'int'
+ if raw_name is 'number':
+ return 'double'
+ if raw_name is 'boolean':
+ return 'BOOL'
+ if raw_name in ['any', 'object']:
+ return '%sJSONObject *' % ObjCGenerator.OBJC_STATIC_PREFIX
+ return None
+
+ @staticmethod
+ def objc_class_for_raw_name(raw_name):
+ if raw_name is 'string':
+ return 'NSString'
+ if raw_name is 'array':
+ return 'NSArray'
+ if raw_name in ['integer', 'number', 'boolean']:
+ return 'NSNumber'
+ if raw_name in ['any', 'object']:
+ return '%sJSONObject' % ObjCGenerator.OBJC_STATIC_PREFIX
+ return None
+
+ # FIXME: Can these protocol_type functions be removed in favor of C++ generators functions?
+
+ @staticmethod
+ def protocol_type_for_raw_name(raw_name):
+ if raw_name is 'string':
+ return 'String'
+ if raw_name is 'integer':
+ return 'int'
+ if raw_name is 'number':
+ return 'double'
+ if raw_name is 'boolean':
+ return 'bool'
+ if raw_name in ['any', 'object']:
+ return 'InspectorObject'
+ return None
+
+ @staticmethod
+ def protocol_type_for_type(_type):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return ObjCGenerator.protocol_type_for_raw_name(_type.raw_name())
+ if (isinstance(_type, EnumType)):
+ return ObjCGenerator.protocol_type_for_type(_type.primitive_type)
+ if (isinstance(_type, ObjectType)):
+ return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name())
+ if (isinstance(_type, ArrayType)):
+ sub_type = ObjCGenerator.protocol_type_for_type(_type.element_type)
+ return 'Inspector::Protocol::Array<%s>' % sub_type
+ return None
+
+ @staticmethod
+ def is_type_objc_pointer_type(_type):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return _type.raw_name() in ['string', 'array', 'any', 'object']
+ if (isinstance(_type, EnumType)):
+ return False
+ if (isinstance(_type, ObjectType)):
+ return True
+ if (isinstance(_type, ArrayType)):
+ return True
+ return None
+
+ def objc_class_for_type(self, _type):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return ObjCGenerator.objc_class_for_raw_name(_type.raw_name())
+ if (isinstance(_type, EnumType)):
+ return ObjCGenerator.objc_class_for_raw_name(_type.primitive_type.raw_name())
+ if (isinstance(_type, ObjectType)):
+ return self.objc_name_for_type(_type)
+ if (isinstance(_type, ArrayType)):
+ sub_type = strip_block_comment_markers(self.objc_class_for_type(_type.element_type))
+ return 'NSArray/*<%s>*/' % sub_type
+ return None
+
+ def objc_class_for_array_type(self, _type):
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type
+ if isinstance(_type, ArrayType):
+ return self.objc_class_for_type(_type.element_type)
+ return None
+
+ def objc_accessor_type_for_member(self, member):
+ return self.objc_accessor_type_for_member_internal(member.type)
+
+ def objc_accessor_type_for_member_internal(self, _type):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return self.objc_accessor_type_for_raw_name(_type.raw_name())
+ if (isinstance(_type, EnumType)):
+ return 'assign'
+ if (isinstance(_type, ObjectType)):
+ return 'retain'
+ if (isinstance(_type, ArrayType)):
+ return 'copy'
+ return None
+
+ def objc_type_for_member(self, declaration, member):
+ return self.objc_type_for_member_internal(member.type, declaration, member)
+
+ def objc_type_for_member_internal(self, _type, declaration, member):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return self.objc_type_for_raw_name(_type.raw_name())
+ if (isinstance(_type, EnumType)):
+ if (_type.is_anonymous):
+ return self.objc_enum_name_for_anonymous_enum_member(declaration, member)
+ return self.objc_enum_name_for_non_anonymous_enum(_type)
+ if (isinstance(_type, ObjectType)):
+ return self.objc_name_for_type(_type) + ' *'
+ if (isinstance(_type, ArrayType)):
+ sub_type = strip_block_comment_markers(self.objc_class_for_type(_type.element_type))
+ return 'NSArray/*<%s>*/ *' % sub_type
+ return None
+
+ def objc_type_for_param(self, domain, event_or_command_name, parameter, respect_optional=True):
+ objc_type = self.objc_type_for_param_internal(parameter.type, domain, event_or_command_name, parameter)
+ if respect_optional and parameter.is_optional:
+ if objc_type.endswith('*'):
+ return objc_type + '*'
+ return objc_type + ' *'
+ return objc_type
+
+ def objc_type_for_param_internal(self, _type, domain, event_or_command_name, parameter):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ return self.objc_type_for_raw_name(_type.raw_name())
+ if (isinstance(_type, EnumType)):
+ if _type.is_anonymous:
+ return self.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter)
+ return self.objc_enum_name_for_non_anonymous_enum(_type)
+ if (isinstance(_type, ObjectType)):
+ return self.objc_name_for_type(_type) + ' *'
+ if (isinstance(_type, ArrayType)):
+ sub_type = strip_block_comment_markers(self.objc_class_for_type(_type.element_type))
+ return 'NSArray/*<%s>*/ *' % sub_type
+ return None
+
+ # ObjC <-> Protocol conversion for commands and events.
+ # - convert a command call parameter received from Protocol to ObjC for handler
+ # - convert a command return parameter in callback block from ObjC to Protocol to send
+ # - convert an event parameter from ObjC API to Protocol to send
+
+ def objc_protocol_export_expression_for_variable(self, var_type, var_name):
+ category = ObjCTypeCategory.category_for_type(var_type)
+ if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]:
+ if isinstance(var_type, EnumType):
+ return 'toProtocolString(%s)' % var_name
+ return var_name
+ if category is ObjCTypeCategory.Object:
+ return '[%s toInspectorObject]' % var_name
+ if category is ObjCTypeCategory.Array:
+ protocol_type = ObjCGenerator.protocol_type_for_type(var_type.element_type)
+ objc_class = self.objc_class_for_type(var_type.element_type)
+ if protocol_type == 'Inspector::Protocol::Array<String>':
+ return 'inspectorStringArrayArray(%s)' % var_name
+ if protocol_type is 'String' and objc_class is 'NSString':
+ return 'inspectorStringArray(%s)' % var_name
+ if protocol_type is 'int' and objc_class is 'NSNumber':
+ return 'inspectorIntegerArray(%s)' % var_name
+ if protocol_type is 'double' and objc_class is 'NSNumber':
+ return 'inspectorDoubleArray(%s)' % var_name
+ return 'inspectorObjectArray(%s)' % var_name
+
+ def objc_protocol_import_expression_for_member(self, name, declaration, member):
+ if isinstance(member.type, EnumType):
+ if member.type.is_anonymous:
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_anonymous_enum_member(declaration, member), name)
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_non_anonymous_enum(member.type), name)
+ return self.objc_protocol_import_expression_for_variable(member.type, name)
+
+ def objc_protocol_import_expression_for_parameter(self, name, domain, event_or_command_name, parameter):
+ if isinstance(parameter.type, EnumType):
+ if parameter.type.is_anonymous:
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter), name)
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_non_anonymous_enum(parameter.type), name)
+ return self.objc_protocol_import_expression_for_variable(parameter.type, name)
+
+ def objc_protocol_import_expression_for_variable(self, var_type, var_name):
+ category = ObjCTypeCategory.category_for_type(var_type)
+ if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]:
+ return var_name
+ if category is ObjCTypeCategory.Object:
+ objc_class = self.objc_class_for_type(var_type)
+ return '[[[%s alloc] initWithInspectorObject:%s] autorelease]' % (objc_class, var_name)
+ if category is ObjCTypeCategory.Array:
+ objc_class = self.objc_class_for_type(var_type.element_type)
+ if objc_class is 'NSString':
+ return 'objcStringArray(%s)' % var_name
+ if objc_class is 'NSNumber': # FIXME: Integer or Double?
+ return 'objcIntegerArray(%s)' % var_name
+ return 'objcArray<%s>(%s)' % (objc_class, var_name)
+
+ # ObjC <-> JSON object conversion for types getters/setters.
+ # - convert a member setter from ObjC API to JSON object setter
+ # - convert a member getter from JSON object to ObjC API
+
+ def objc_to_protocol_expression_for_member(self, declaration, member, sub_expression):
+ category = ObjCTypeCategory.category_for_type(member.type)
+ if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]:
+ if isinstance(member.type, EnumType):
+ return 'toProtocolString(%s)' % sub_expression
+ return sub_expression
+ if category is ObjCTypeCategory.Object:
+ return sub_expression
+ if category is ObjCTypeCategory.Array:
+ objc_class = self.objc_class_for_type(member.type.element_type)
+ if objc_class is 'NSString':
+ return 'inspectorStringArray(%s)' % sub_expression
+ if objc_class is 'NSNumber':
+ protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type)
+ if protocol_type is 'double':
+ return 'inspectorDoubleArray(%s)' % sub_expression
+ return 'inspectorIntegerArray(%s)' % sub_expression
+ return 'inspectorObjectArray(%s)' % sub_expression
+
+ def protocol_to_objc_expression_for_member(self, declaration, member, sub_expression):
+ category = ObjCTypeCategory.category_for_type(member.type)
+ if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]:
+ if isinstance(member.type, EnumType):
+ if member.type.is_anonymous:
+ return 'fromProtocolString<%s>(%s).value()' % (self.objc_enum_name_for_anonymous_enum_member(declaration, member), sub_expression)
+ return 'fromProtocolString<%s>(%s).value()' % (self.objc_enum_name_for_non_anonymous_enum(member.type), sub_expression)
+ return sub_expression
+ if category is ObjCTypeCategory.Object:
+ objc_class = self.objc_class_for_type(member.type)
+ return '[[%s alloc] initWithInspectorObject:[%s toInspectorObject].get()]' % (objc_class, sub_expression)
+ if category is ObjCTypeCategory.Array:
+ protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type)
+ objc_class = self.objc_class_for_type(member.type.element_type)
+ if objc_class is 'NSString':
+ return 'objcStringArray(%s)' % sub_expression
+ if objc_class is 'NSNumber':
+ protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type)
+ if protocol_type is 'double':
+ return 'objcDoubleArray(%s)' % sub_expression
+ return 'objcIntegerArray(%s)' % sub_expression
+ return 'objcArray<%s>(%s)' % (objc_class, sub_expression)
+
+ def payload_to_objc_expression_for_member(self, declaration, member):
+ _type = member.type
+ if isinstance(_type, AliasedType):
+ _type = _type.aliased_type
+ if isinstance(_type, PrimitiveType):
+ sub_expression = 'payload[@"%s"]' % member.member_name
+ raw_name = _type.raw_name()
+ if raw_name is 'boolean':
+ return '[%s boolValue]' % sub_expression
+ if raw_name is 'integer':
+ return '[%s integerValue]' % sub_expression
+ if raw_name is 'number':
+ return '[%s doubleValue]' % sub_expression
+ if raw_name in ['any', 'object', 'array', 'string']:
+ return sub_expression # The setter will check the incoming value.
+ return None
+ if isinstance(member.type, EnumType):
+ sub_expression = 'payload[@"%s"]' % member.member_name
+ if member.type.is_anonymous:
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_anonymous_enum_member(declaration, member), sub_expression)
+ else:
+ return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_non_anonymous_enum(member.type), sub_expression)
+ if isinstance(_type, ObjectType):
+ objc_class = self.objc_class_for_type(member.type)
+ return '[[%s alloc] initWithPayload:payload[@"%s"]]' % (objc_class, member.member_name)
+ if isinstance(_type, ArrayType):
+ objc_class = self.objc_class_for_type(member.type.element_type)
+ return 'objcArrayFromPayload<%s>(payload[@"%s"])' % (objc_class, member.member_name)
+
+ # JSON object setter/getter selectors for types.
+
+ @staticmethod
+ def objc_setter_method_for_member(declaration, member):
+ return ObjCGenerator.objc_setter_method_for_member_internal(member.type, declaration, member)
+
+ @staticmethod
+ def objc_setter_method_for_member_internal(_type, declaration, member):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ raw_name = _type.raw_name()
+ if raw_name is 'boolean':
+ return 'setBool'
+ if raw_name is 'integer':
+ return 'setInteger'
+ if raw_name is 'number':
+ return 'setDouble'
+ if raw_name is 'string':
+ return 'setString'
+ if raw_name in ['any', 'object']:
+ return 'setObject'
+ if raw_name is 'array':
+ return 'setInspectorArray'
+ return None
+ if (isinstance(_type, EnumType)):
+ return 'setString'
+ if (isinstance(_type, ObjectType)):
+ return 'setObject'
+ if (isinstance(_type, ArrayType)):
+ return 'setInspectorArray'
+ return None
+
+ @staticmethod
+ def objc_getter_method_for_member(declaration, member):
+ return ObjCGenerator.objc_getter_method_for_member_internal(member.type, declaration, member)
+
+ @staticmethod
+ def objc_getter_method_for_member_internal(_type, declaration, member):
+ if (isinstance(_type, AliasedType)):
+ _type = _type.aliased_type
+ if (isinstance(_type, PrimitiveType)):
+ raw_name = _type.raw_name()
+ if raw_name is 'boolean':
+ return 'boolForKey'
+ if raw_name is 'integer':
+ return 'integerForKey'
+ if raw_name is 'number':
+ return 'doubleForKey'
+ if raw_name is 'string':
+ return 'stringForKey'
+ if raw_name in ['any', 'object']:
+ return 'objectForKey'
+ if raw_name is 'array':
+ return 'inspectorArrayForKey'
+ return None
+ if (isinstance(_type, EnumType)):
+ return 'stringForKey'
+ if (isinstance(_type, ObjectType)):
+ return 'objectForKey'
+ if (isinstance(_type, ArrayType)):
+ return 'inspectorArrayForKey'
+ return None
diff --git a/Source/JavaScriptCore/inspector/scripts/codegen/objc_generator_templates.py b/Source/JavaScriptCore/inspector/scripts/codegen/objc_generator_templates.py
new file mode 100755
index 000000000..1c30c40d4
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/scripts/codegen/objc_generator_templates.py
@@ -0,0 +1,155 @@
+#!/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 ObjCGeneratorTemplates:
+
+ HeaderPrelude = (
+ """#import <Foundation/Foundation.h>
+
+${includes}
+""")
+
+ HeaderPostlude = (
+ """""")
+
+ TypeConversionsHeaderPrelude = (
+ """${includes}
+
+namespace Inspector {""")
+
+ TypeConversionsHeaderPostlude = (
+ """} // namespace Inspector
+""")
+
+ GenericHeaderPrelude = (
+ """${includes}""")
+
+ GenericHeaderPostlude = (
+ """""")
+
+ TypeConversionsHeaderStandard = (
+ """template<typename ObjCEnumType>
+std::optional<ObjCEnumType> fromProtocolString(const String& value);""")
+
+ BackendDispatcherHeaderPrelude = (
+ """${includes}
+
+${forwardDeclarations}
+
+namespace Inspector {
+""")
+
+ BackendDispatcherHeaderPostlude = (
+ """} // namespace Inspector
+""")
+
+ BackendDispatcherImplementationPrelude = (
+ """#import "config.h"
+#import ${primaryInclude}
+
+${secondaryIncludes}
+
+namespace Inspector {""")
+
+ BackendDispatcherImplementationPostlude = (
+ """} // namespace Inspector
+""")
+
+ ImplementationPrelude = (
+ """#import ${primaryInclude}
+
+${secondaryIncludes}
+
+using namespace Inspector;""")
+
+ ImplementationPostlude = (
+ """""")
+
+ BackendDispatcherHeaderDomainHandlerInterfaceDeclaration = (
+ """class Alternate${domainName}BackendDispatcher : public AlternateBackendDispatcher {
+public:
+ virtual ~Alternate${domainName}BackendDispatcher() { }
+${commandDeclarations}
+};""")
+
+ BackendDispatcherHeaderDomainHandlerObjCDeclaration = (
+ """class ObjCInspector${domainName}BackendDispatcher final : public Alternate${domainName}BackendDispatcher {
+public:
+ ObjCInspector${domainName}BackendDispatcher(id<${objcPrefix}${domainName}DomainHandler> handler) { m_delegate = handler; }
+${commandDeclarations}
+private:
+ RetainPtr<id<${objcPrefix}${domainName}DomainHandler>> m_delegate;
+};""")
+
+ BackendDispatcherHeaderDomainHandlerImplementation = (
+ """void ObjCInspector${domainName}BackendDispatcher::${commandName}(${parameters})
+{
+ id errorCallback = ^(NSString *error) {
+ backendDispatcher()->reportProtocolError(requestId, BackendDispatcher::ServerError, error);
+ backendDispatcher()->sendPendingErrors();
+ };
+
+${successCallback}
+${conversions}
+${invocation}
+}
+""")
+
+ ConfigurationCommandProperty = (
+ """@property (nonatomic, retain, setter=set${domainName}Handler:) id<${objcPrefix}${domainName}DomainHandler> ${variableNamePrefix}Handler;""")
+
+ ConfigurationEventProperty = (
+ """@property (nonatomic, readonly) ${objcPrefix}${domainName}DomainEventDispatcher *${variableNamePrefix}EventDispatcher;""")
+
+ ConfigurationCommandPropertyImplementation = (
+ """- (void)set${domainName}Handler:(id<${objcPrefix}${domainName}DomainHandler>)handler
+{
+ if (handler == _${variableNamePrefix}Handler)
+ return;
+
+ [_${variableNamePrefix}Handler release];
+ _${variableNamePrefix}Handler = [handler retain];
+
+ auto alternateDispatcher = std::make_unique<ObjCInspector${domainName}BackendDispatcher>(handler);
+ auto alternateAgent = std::make_unique<AlternateDispatchableAgent<${domainName}BackendDispatcher, Alternate${domainName}BackendDispatcher>>(ASCIILiteral("${domainName}"), *_controller, WTFMove(alternateDispatcher));
+ _controller->appendExtraAgent(WTFMove(alternateAgent));
+}
+
+- (id<${objcPrefix}${domainName}DomainHandler>)${variableNamePrefix}Handler
+{
+ return _${variableNamePrefix}Handler;
+}""")
+
+ ConfigurationGetterImplementation = (
+ """- (${objcPrefix}${domainName}DomainEventDispatcher *)${variableNamePrefix}EventDispatcher
+{
+ if (!_${variableNamePrefix}EventDispatcher)
+ _${variableNamePrefix}EventDispatcher = [[${objcPrefix}${domainName}DomainEventDispatcher alloc] initWithController:_controller];
+ return _${variableNamePrefix}EventDispatcher;
+}""")