diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebKit2/Scripts | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebKit2/Scripts')
-rwxr-xr-x | Source/WebKit2/Scripts/generate-forwarding-headers.pl | 112 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/generate-message-receiver.py | 41 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/generate-messages-header.py | 41 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/__init__.py | 23 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/messages.py | 580 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/messages_unittest.py | 812 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/model.py | 60 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/parser.py | 85 |
8 files changed, 1754 insertions, 0 deletions
diff --git a/Source/WebKit2/Scripts/generate-forwarding-headers.pl b/Source/WebKit2/Scripts/generate-forwarding-headers.pl new file mode 100755 index 000000000..72cf63f20 --- /dev/null +++ b/Source/WebKit2/Scripts/generate-forwarding-headers.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl -w +# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged +# 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# A script which searches for headers included by WebKit2 files +# and generates forwarding headers for these headers. + +use strict; +use Cwd qw(abs_path realpath); +use File::Find; +use File::Basename; +use File::Path qw(mkpath); +use File::Spec::Functions; + +my $srcRoot = realpath(File::Spec->catfile(dirname(abs_path($0)), "../..")); +my $incFromRoot = abs_path($ARGV[0]); +my @platformPrefixes = ("blackberry", "cf", "chromium", "curl", "efl", "gtk", "mac", "qt", "soup", "v8", "win", "wx"); +my @frameworks = ( "JavaScriptCore", "WebCore", "WebKit2"); +my @skippedPrefixes; +my @frameworkHeaders; +my $framework; +my %neededHeaders; + +shift; +my $outputDirectory = $ARGV[0]; +shift; +my $platform = $ARGV[0]; + +foreach my $prefix (@platformPrefixes) { + push(@skippedPrefixes, $prefix) unless ($prefix =~ $platform); +} + +foreach (@frameworks) { + $framework = $_; + @frameworkHeaders = (); + %neededHeaders = (); + + find(\&collectNeededHeaders, $incFromRoot); + find(\&collectFameworkHeaderPaths, File::Spec->catfile($srcRoot, $framework)); + createForwardingHeadersForFramework(); +} + +sub collectNeededHeaders { + my $filePath = $File::Find::name; + my $file = $_; + if ($filePath =~ '\.h$|\.cpp$|\.c$|\.mm$') { + open(FILE, "<$file") or die "Could not open $filePath.\n"; + while (<FILE>) { + if (m/^#.*<$framework\/(.*\.h)/) { + $neededHeaders{$1} = 1; + } + } + close(FILE); + } +} + +sub collectFameworkHeaderPaths { + my $filePath = $File::Find::name; + my $file = $_; + if ($filePath =~ '\.h$' && $filePath !~ "ForwardingHeaders" && grep{$file eq $_} keys %neededHeaders) { + my $headerPath = substr($filePath, length(File::Spec->catfile($srcRoot, $framework)) + 1 ); + push(@frameworkHeaders, $headerPath) unless (grep($headerPath =~ "$_/", @skippedPrefixes) || $headerPath =~ "config.h"); + } +} + +sub createForwardingHeadersForFramework { + my $targetDirectory = File::Spec->catfile($outputDirectory, $framework); + mkpath($targetDirectory); + foreach my $header (@frameworkHeaders) { + my $headerName = basename($header); + + # If we found more headers with the same name, only generate a forwarding header for the current platform + if(grep($_ =~ "/$headerName\$", @frameworkHeaders) == 1 || $header =~ "/$platform/" ) { + my $forwardingHeaderPath = File::Spec->catfile($targetDirectory, $headerName); + my $expectedIncludeStatement = "#include \"$framework/$header\""; + my $foundIncludeStatement = 0; + + $foundIncludeStatement = <EXISTING_HEADER> if open(EXISTING_HEADER, "<$forwardingHeaderPath"); + chomp($foundIncludeStatement); + + if (! $foundIncludeStatement || $foundIncludeStatement ne $expectedIncludeStatement) { + print "[Creating forwarding header for $framework/$header]\n"; + open(FORWARDING_HEADER, ">$forwardingHeaderPath") or die "Could not open $forwardingHeaderPath."; + print FORWARDING_HEADER "$expectedIncludeStatement\n"; + close(FORWARDING_HEADER); + } + + close(EXISTING_HEADER); + } + } +} diff --git a/Source/WebKit2/Scripts/generate-message-receiver.py b/Source/WebKit2/Scripts/generate-message-receiver.py new file mode 100644 index 000000000..8fae2f006 --- /dev/null +++ b/Source/WebKit2/Scripts/generate-message-receiver.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# +# Copyright (C) 2010 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. + +from __future__ import with_statement +import sys + +import webkit2.messages + + +def main(argv=None): + if not argv: + argv = sys.argv + input_path = argv[1] + with open(input_path) as input_file: + # Python 3, change to: print(webkit2.messages.generate_message_handler(input_file), end='') + sys.stdout.write(webkit2.messages.generate_message_handler(input_file)) + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/Source/WebKit2/Scripts/generate-messages-header.py b/Source/WebKit2/Scripts/generate-messages-header.py new file mode 100644 index 000000000..854f0f0d4 --- /dev/null +++ b/Source/WebKit2/Scripts/generate-messages-header.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# +# Copyright (C) 2010 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. + +from __future__ import with_statement +import sys + +import webkit2.messages + + +def main(argv=None): + if not argv: + argv = sys.argv + input_path = argv[1] + with open(input_path) as input_file: + # Python 3, change to: print(webkit2.messages.generate_messages_header(input_file), end='') + sys.stdout.write(webkit2.messages.generate_messages_header(input_file)) + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/Source/WebKit2/Scripts/webkit2/__init__.py b/Source/WebKit2/Scripts/webkit2/__init__.py new file mode 100644 index 000000000..27e3fc3b1 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/__init__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2010 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. + +# Required for Python to search this directory for module files diff --git a/Source/WebKit2/Scripts/webkit2/messages.py b/Source/WebKit2/Scripts/webkit2/messages.py new file mode 100644 index 000000000..cf9d5ec01 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/messages.py @@ -0,0 +1,580 @@ +# Copyright (C) 2010, 2011 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 collections +import re + +import parser + + +DELAYED_ATTRIBUTE = 'Delayed' +DISPATCH_ON_CONNECTION_QUEUE_ATTRIBUTE = 'DispatchOnConnectionQueue' + +_license_header = """/* + * Copyright (C) 2010 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. + */ + +""" + + +def messages_header_filename(receiver): + return '%sMessages.h' % receiver.name + + +def surround_in_condition(string, condition): + if not condition: + return string + return '#if %s\n%s#endif\n' % (condition, string) + + +def messages_to_kind_enum(messages): + result = [] + result.append('enum Kind {\n') + result += [surround_in_condition(' %s,\n' % message.id(), message.condition) for message in messages] + result.append('};\n') + return ''.join(result) + + +def message_is_variadic(message): + variadic_types = frozenset([ + 'WebKit::InjectedBundleUserMessageEncoder', + 'WebKit::WebContextUserMessageEncoder', + ]) + + return len(message.parameters) and message.parameters[-1].type in variadic_types + +def function_parameter_type(type): + # Don't use references for built-in types. + builtin_types = frozenset([ + 'bool', + 'float', + 'double', + 'uint8_t', + 'uint16_t', + 'uint32_t', + 'uint64_t', + 'int8_t', + 'int16_t', + 'int32_t', + 'int64_t', + ]) + + if type in builtin_types: + return type + + return 'const %s&' % type + + +def reply_parameter_type(type): + return '%s&' % type + + +def arguments_type(parameters, parameter_type_function): + arguments_type = 'CoreIPC::Arguments%d' % len(parameters) + if len(parameters): + arguments_type = '%s<%s>' % (arguments_type, ', '.join(parameter_type_function(parameter.type) for parameter in parameters)) + return arguments_type + + +def base_class(message): + return arguments_type(message.parameters, function_parameter_type) + + +def reply_type(message): + return arguments_type(message.reply_parameters, reply_parameter_type) + + +def decode_type(message): + if message_is_variadic(message): + return arguments_type(message.parameters[:-1], reply_parameter_type) + return base_class(message) + + +def delayed_reply_type(message): + return arguments_type(message.reply_parameters, function_parameter_type) + + +def message_to_struct_declaration(message): + result = [] + function_parameters = [(function_parameter_type(x.type), x.name) for x in message.parameters] + result.append('struct %s : %s' % (message.name, base_class(message))) + result.append(' {\n') + result.append(' static const Kind messageID = %s;\n' % message.id()) + if message.reply_parameters != None: + if message.has_attribute(DELAYED_ATTRIBUTE): + send_parameters = [(function_parameter_type(x.type), x.name) for x in message.reply_parameters] + result.append(' struct DelayedReply : public ThreadSafeRefCounted<DelayedReply> {\n') + result.append(' DelayedReply(PassRefPtr<CoreIPC::Connection>, PassOwnPtr<CoreIPC::ArgumentEncoder>);\n') + result.append(' ~DelayedReply();\n') + result.append('\n') + result.append(' bool send(%s);\n' % ', '.join([' '.join(x) for x in send_parameters])) + result.append('\n') + result.append(' private:\n') + result.append(' RefPtr<CoreIPC::Connection> m_connection;\n') + result.append(' OwnPtr<CoreIPC::ArgumentEncoder> m_arguments;\n') + result.append(' };\n\n') + + result.append(' typedef %s Reply;\n' % reply_type(message)) + + result.append(' typedef %s DecodeType;\n' % decode_type(message)) + if len(function_parameters): + result.append(' %s%s(%s)' % (len(function_parameters) == 1 and 'explicit ' or '', message.name, ', '.join([' '.join(x) for x in function_parameters]))) + result.append('\n : %s(%s)\n' % (base_class(message), ', '.join([x[1] for x in function_parameters]))) + result.append(' {\n') + result.append(' }\n') + result.append('};\n') + return surround_in_condition(''.join(result), message.condition) + + +def struct_or_class(namespace, type): + structs = frozenset([ + 'WebCore::Animation', + 'WebCore::EditorCommandsForKeyEvent', + 'WebCore::CompositionUnderline', + 'WebCore::DragSession', + 'WebCore::FloatPoint3D', + 'WebCore::FileChooserSettings', + 'WebCore::GrammarDetail', + 'WebCore::IdentityTransformOperation', + 'WebCore::KeypressCommand', + 'WebCore::Length', + 'WebCore::MatrixTransformOperation', + 'WebCore::Matrix3DTransformOperation', + 'WebCore::NotificationContents', + 'WebCore::PerspectiveTransformOperation', + 'WebCore::PluginInfo', + 'WebCore::PrintInfo', + 'WebCore::RotateTransformOperation', + 'WebCore::ScaleTransformOperation', + 'WebCore::SkewTransformOperation', + 'WebCore::TimingFunction', + 'WebCore::TransformationMatrix', + 'WebCore::TransformOperation', + 'WebCore::TransformOperations', + 'WebCore::TranslateTransformOperation', + 'WebCore::ViewportArguments', + 'WebCore::WindowFeatures', + 'WebKit::AttributedString', + 'WebKit::ContextMenuState', + 'WebKit::DictionaryPopupInfo', + 'WebKit::DrawingAreaInfo', + 'WebKit::EditorState', + 'WebKit::PlatformPopupMenuData', + 'WebKit::PluginCreationParameters', + 'WebKit::PluginProcessCreationParameters', + 'WebKit::PrintInfo', + 'WebKit::SecurityOriginData', + 'WebKit::StatisticsData', + 'WebKit::TextCheckerState', + 'WebKit::WebNavigationDataStore', + 'WebKit::WebPageCreationParameters', + 'WebKit::WebPreferencesStore', + 'WebKit::WebProcessCreationParameters', + 'WebKit::WindowGeometry', + ]) + + qualified_name = '%s::%s' % (namespace, type) + if qualified_name in structs: + return 'struct %s' % type + + return 'class %s' % type + +def forward_declarations_for_namespace(namespace, types): + result = [] + result.append('namespace %s {\n' % namespace) + result += [' %s;\n' % struct_or_class(namespace, x) for x in types] + result.append('}\n') + return ''.join(result) + + +def forward_declarations_and_headers(receiver): + types_by_namespace = collections.defaultdict(set) + + headers = set([ + '"Arguments.h"', + '"MessageID.h"', + ]) + + for message in receiver.messages: + if message.reply_parameters != None and message.has_attribute(DELAYED_ATTRIBUTE): + headers.add('<wtf/ThreadSafeRefCounted.h>') + types_by_namespace['CoreIPC'].update(['ArgumentEncoder', 'Connection']) + + for parameter in receiver.iterparameters(): + type = parameter.type + + if type.find('<') != -1: + # Don't forward declare class templates. + headers.update(headers_for_type(type)) + continue + + split = type.split('::') + + if len(split) == 2: + namespace = split[0] + inner_type = split[1] + types_by_namespace[namespace].add(inner_type) + elif len(split) > 2: + # We probably have a nested struct, which means we can't forward declare it. + # Include its header instead. + headers.update(headers_for_type(type)) + + forward_declarations = '\n'.join([forward_declarations_for_namespace(namespace, types) for (namespace, types) in sorted(types_by_namespace.items())]) + headers = ['#include %s\n' % header for header in sorted(headers)] + + return (forward_declarations, headers) + +def generate_messages_header(file): + receiver = parser.parse(file) + header_guard = messages_header_filename(receiver).replace('.', '_') + + result = [] + + result.append(_license_header) + + result.append('#ifndef %s\n' % header_guard) + result.append('#define %s\n\n' % header_guard) + + if receiver.condition: + result.append('#if %s\n\n' % receiver.condition) + + forward_declarations, headers = forward_declarations_and_headers(receiver) + + result += headers + result.append('\n') + + result.append(forward_declarations) + result.append('\n') + + result.append('namespace Messages {\n\nnamespace %s {\n\n' % receiver.name) + result.append(messages_to_kind_enum(receiver.messages)) + result.append('\n') + result.append('\n'.join([message_to_struct_declaration(x) for x in receiver.messages])) + result.append('\n} // namespace %s\n\n} // namespace Messages\n' % receiver.name) + + result.append('\nnamespace CoreIPC {\n\n') + result.append('template<> struct MessageKindTraits<Messages::%s::Kind> {\n' % receiver.name) + result.append(' static const MessageClass messageClass = MessageClass%s;\n' % receiver.name) + result.append('};\n') + result.append('\n} // namespace CoreIPC\n') + + if receiver.condition: + result.append('\n#endif // %s\n' % receiver.condition) + + result.append('\n#endif // %s\n' % header_guard) + + return ''.join(result) + + +def handler_function(receiver, message): + if message.name.find('URL') == 0: + return '%s::%s' % (receiver.name, 'url' + message.name[3:]) + return '%s::%s' % (receiver.name, message.name[0].lower() + message.name[1:]) + + +def async_case_statement(receiver, message, statement_before_return=None): + dispatch_function = 'handleMessage' + if message_is_variadic(message): + dispatch_function += 'Variadic' + + result = [] + result.append(' case Messages::%s::%s:\n' % (receiver.name, message.id())) + result.append(' CoreIPC::%s<Messages::%s::%s>(arguments, this, &%s);\n' % (dispatch_function, receiver.name, message.name, handler_function(receiver, message))) + if statement_before_return: + result.append(' %s\n' % statement_before_return) + result.append(' return;\n') + return surround_in_condition(''.join(result), message.condition) + + +def sync_case_statement(receiver, message): + dispatch_function = 'handleMessage' + if message.has_attribute(DELAYED_ATTRIBUTE): + dispatch_function += 'Delayed' + if message_is_variadic(message): + dispatch_function += 'Variadic' + + result = [] + result.append(' case Messages::%s::%s:\n' % (receiver.name, message.id())) + result.append(' CoreIPC::%s<Messages::%s::%s>(%sarguments, reply%s, this, &%s);\n' % (dispatch_function, receiver.name, message.name, 'connection, ' if message.has_attribute(DELAYED_ATTRIBUTE) else '', '' if message.has_attribute(DELAYED_ATTRIBUTE) else '.get()', handler_function(receiver, message))) + result.append(' return;\n') + + return surround_in_condition(''.join(result), message.condition) + + +def argument_coder_headers_for_type(type): + # Check for Vector. + match = re.search(r'Vector<(.+)>', type) + if match: + element_type = match.groups()[0].strip() + return ['"ArgumentCoders.h"'] + argument_coder_headers_for_type(element_type) + + special_cases = { + 'WTF::String': '"ArgumentCoders.h"', + 'WebKit::InjectedBundleUserMessageEncoder': '"InjectedBundleUserMessageCoders.h"', + 'WebKit::WebContextUserMessageEncoder': '"WebContextUserMessageCoders.h"', + } + + if type in special_cases: + return [special_cases[type]] + + split = type.split('::') + if len(split) < 2: + return [] + if split[0] == 'WebCore': + return ['"WebCoreArgumentCoders.h"'] + + return [] + + +def headers_for_type(type): + # Check for Vector. + match = re.search(r'Vector<(.+)>', type) + if match: + element_type = match.groups()[0].strip() + return ['<wtf/Vector.h>'] + headers_for_type(element_type) + + special_cases = { + 'WTF::String': ['<wtf/text/WTFString.h>'], + 'WebCore::CompositionUnderline': ['<WebCore/Editor.h>'], + 'WebCore::GrammarDetail': ['<WebCore/TextCheckerClient.h>'], + 'WebCore::KeyframeValueList': ['<WebCore/GraphicsLayer.h>'], + 'WebCore::KeypressCommand': ['<WebCore/KeyboardEvent.h>'], + 'WebCore::FileChooserSettings': ['<WebCore/FileChooser.h>'], + 'WebCore::PluginInfo': ['<WebCore/PluginData.h>'], + 'WebCore::TextCheckingResult': ['<WebCore/TextCheckerClient.h>'], + 'WebKit::InjectedBundleUserMessageEncoder': [], + 'WebKit::WebContextUserMessageEncoder': [], + 'WebKit::WebGestureEvent': ['"WebEvent.h"'], + 'WebKit::WebLayerID': ['"WebLayerTreeInfo.h"'], + 'WebKit::WebLayerInfo': ['"WebLayerTreeInfo.h"'], + 'WebKit::WebKeyboardEvent': ['"WebEvent.h"'], + 'WebKit::WebMouseEvent': ['"WebEvent.h"'], + 'WebKit::WebTouchEvent': ['"WebEvent.h"'], + 'WebKit::WebWheelEvent': ['"WebEvent.h"'], + } + if type in special_cases: + return special_cases[type] + + # We assume that we must include a header for a type iff it has a scope + # resolution operator (::). + split = type.split('::') + if len(split) < 2: + return [] + if split[0] == 'WebKit' or split[0] == 'CoreIPC': + return ['"%s.h"' % split[1]] + return ['<%s/%s.h>' % tuple(split)] + + +def generate_message_handler(file): + receiver = parser.parse(file) + headers = { + '"%s"' % messages_header_filename(receiver): [None], + '"HandleMessage.h"': [None], + '"ArgumentDecoder.h"': [None], + } + + type_conditions = {} + for parameter in receiver.iterparameters(): + if not parameter.type in type_conditions: + type_conditions[parameter.type] = [] + + if not parameter.condition in type_conditions[parameter.type]: + type_conditions[parameter.type].append(parameter.condition) + + for parameter in receiver.iterparameters(): + type = parameter.type + conditions = type_conditions[type] + + argument_encoder_headers = argument_coder_headers_for_type(type) + if argument_encoder_headers: + for header in argument_encoder_headers: + if header not in headers: + headers[header] = [] + headers[header].extend(conditions) + + type_headers = headers_for_type(type) + for header in type_headers: + if header not in headers: + headers[header] = [] + headers[header].extend(conditions) + + for message in receiver.messages: + if message.reply_parameters is not None: + for reply_parameter in message.reply_parameters: + type = reply_parameter.type + argument_encoder_headers = argument_coder_headers_for_type(type) + if argument_encoder_headers: + for header in argument_encoder_headers: + if header not in headers: + headers[header] = [] + headers[header].append(message.condition) + + type_headers = headers_for_type(type) + for header in type_headers: + if header not in headers: + headers[header] = [] + headers[header].append(message.condition) + + + result = [] + + result.append(_license_header) + result.append('#include "config.h"\n') + result.append('\n') + + if receiver.condition: + result.append('#if %s\n\n' % receiver.condition) + + result.append('#include "%s.h"\n\n' % receiver.name) + for headercondition in sorted(headers): + if headers[headercondition] and not None in headers[headercondition]: + result.append('#if %s\n' % ' || '.join(set(headers[headercondition]))) + result += ['#include %s\n' % headercondition] + result.append('#endif\n') + else: + result += ['#include %s\n' % headercondition] + result.append('\n') + + sync_delayed_messages = [] + for message in receiver.messages: + if message.reply_parameters != None and message.has_attribute(DELAYED_ATTRIBUTE): + sync_delayed_messages.append(message) + + if sync_delayed_messages: + result.append('namespace Messages {\n\nnamespace %s {\n\n' % receiver.name) + + for message in sync_delayed_messages: + send_parameters = [(function_parameter_type(x.type), x.name) for x in message.reply_parameters] + + if message.condition: + result.append('#if %s\n\n' % message.condition) + + result.append('%s::DelayedReply::DelayedReply(PassRefPtr<CoreIPC::Connection> connection, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments)\n' % message.name) + result.append(' : m_connection(connection)\n') + result.append(' , m_arguments(arguments)\n') + result.append('{\n') + result.append('}\n') + result.append('\n') + result.append('%s::DelayedReply::~DelayedReply()\n' % message.name) + result.append('{\n') + result.append(' ASSERT(!m_connection);\n') + result.append('}\n') + result.append('\n') + result.append('bool %s::DelayedReply::send(%s)\n' % (message.name, ', '.join([' '.join(x) for x in send_parameters]))) + result.append('{\n') + result.append(' ASSERT(m_arguments);\n') + result += [' m_arguments->encode(%s);\n' % x.name for x in message.reply_parameters] + result.append(' bool result = m_connection->sendSyncReply(m_arguments.release());\n') + result.append(' m_connection = nullptr;\n') + result.append(' return result;\n') + result.append('}\n') + result.append('\n') + + if message.condition: + result.append('#endif\n\n') + + result.append('} // namespace %s\n\n} // namespace Messages\n\n' % receiver.name) + + result.append('namespace WebKit {\n\n') + + async_dispatch_on_connection_queue_messages = [] + sync_dispatch_on_connection_queue_messages = [] + async_messages = [] + sync_messages = [] + for message in receiver.messages: + if message.reply_parameters is not None: + if message.has_attribute(DISPATCH_ON_CONNECTION_QUEUE_ATTRIBUTE): + sync_dispatch_on_connection_queue_messages.append(message) + else: + sync_messages.append(message) + else: + if message.has_attribute(DISPATCH_ON_CONNECTION_QUEUE_ATTRIBUTE): + async_dispatch_on_connection_queue_messages.append(message) + else: + async_messages.append(message) + + if async_dispatch_on_connection_queue_messages: + result.append('void %s::didReceive%sMessageOnConnectionWorkQueue(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage)\n' % (receiver.name, receiver.name)) + result.append('{\n') + result.append('#if COMPILER(MSVC)\n') + result.append('#pragma warning(push)\n') + result.append('#pragma warning(disable: 4065)\n') + result.append('#endif\n') + result.append(' switch (messageID.get<Messages::%s::Kind>()) {\n' % receiver.name) + result += [async_case_statement(receiver, message, 'didHandleMessage = true;') for message in async_dispatch_on_connection_queue_messages] + result.append(' default:\n') + result.append(' return;\n') + result.append(' }\n') + result.append('#if COMPILER(MSVC)\n') + result.append('#pragma warning(pop)\n') + result.append('#endif\n') + result.append('}\n\n') + + if async_messages: + result.append('void %s::didReceive%sMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)\n' % (receiver.name, receiver.name)) + result.append('{\n') + result.append(' switch (messageID.get<Messages::%s::Kind>()) {\n' % receiver.name) + result += [async_case_statement(receiver, message) for message in async_messages] + result.append(' default:\n') + result.append(' break;\n') + result.append(' }\n\n') + result.append(' ASSERT_NOT_REACHED();\n') + result.append('}\n') + + if sync_messages: + result.append('\n') + result.append('void %s::didReceiveSync%sMessage(CoreIPC::Connection*%s, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)\n' % (receiver.name, receiver.name, ' connection' if sync_delayed_messages else '')) + result.append('{\n') + result.append(' switch (messageID.get<Messages::%s::Kind>()) {\n' % receiver.name) + result += [sync_case_statement(receiver, message) for message in sync_messages] + result.append(' default:\n') + result.append(' break;\n') + result.append(' }\n\n') + result.append(' ASSERT_NOT_REACHED();\n') + result.append('}\n') + + result.append('\n} // namespace WebKit\n') + + if receiver.condition: + result.append('\n#endif // %s\n' % receiver.condition) + + return ''.join(result) diff --git a/Source/WebKit2/Scripts/webkit2/messages_unittest.py b/Source/WebKit2/Scripts/webkit2/messages_unittest.py new file mode 100644 index 000000000..dc6b3aff9 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/messages_unittest.py @@ -0,0 +1,812 @@ +# Copyright (C) 2010 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 unittest +from StringIO import StringIO + +import messages +import parser + +_messages_file_contents = """# Copyright (C) 2010 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. + +#include "config.h" + +#if ENABLE(WEBKIT2) + +messages -> WebPage { + LoadURL(WTF::String url) +#if ENABLE(TOUCH_EVENTS) + TouchEvent(WebKit::WebTouchEvent event) +#endif + DidReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction) + Close() + + PreferencesDidChange(WebKit::WebPreferencesStore store) + SendDoubleAndFloat(double d, float f) + SendInts(Vector<uint64_t> ints, Vector<Vector<uint64_t> > intVectors) + + CreatePlugin(uint64_t pluginInstanceID, WebKit::Plugin::Parameters parameters) -> (bool result) + RunJavaScriptAlert(uint64_t frameID, WTF::String message) -> () + GetPlugins(bool refresh) -> (Vector<WebCore::PluginInfo> plugins) DispatchOnConnectionQueue + GetPluginProcessConnection(WTF::String pluginPath) -> (CoreIPC::Connection::Handle connectionHandle) Delayed + + TestMultipleAttributes() -> () DispatchOnConnectionQueue Delayed + TestConnectionQueue(uint64_t pluginID) DispatchOnConnectionQueue + + TestParameterAttributes([AttributeOne AttributeTwo] uint64_t foo, double bar, [AttributeThree] double baz) + +#if PLATFORM(MAC) + DidCreateWebProcessConnection(CoreIPC::MachPort connectionIdentifier) +#endif + +#if PLATFORM(MAC) + # Keyboard support + InterpretKeyEvent(uint32_t type) -> (Vector<WebCore::KeypressCommand> commandName) +#endif + +#if ENABLE(DEPRECATED_FEATURE) + DeprecatedOperation(CoreIPC::DummyType dummy) +#endif + +#if ENABLE(EXPERIMENTAL_FEATURE) + ExperimentalOperation(CoreIPC::DummyType dummy) +#endif +} + +#endif +""" + +_expected_results = { + 'name': 'WebPage', + 'conditions': ('ENABLE(WEBKIT2)'), + 'messages': ( + { + 'name': 'LoadURL', + 'parameters': ( + ('WTF::String', 'url'), + ), + 'conditions': (None), + }, + { + 'name': 'TouchEvent', + 'parameters': ( + ('WebKit::WebTouchEvent', 'event'), + ), + 'conditions': ('ENABLE(TOUCH_EVENTS)'), + }, + { + 'name': 'DidReceivePolicyDecision', + 'parameters': ( + ('uint64_t', 'frameID'), + ('uint64_t', 'listenerID'), + ('uint32_t', 'policyAction'), + ), + 'conditions': (None), + }, + { + 'name': 'Close', + 'parameters': (), + 'conditions': (None), + }, + { + 'name': 'PreferencesDidChange', + 'parameters': ( + ('WebKit::WebPreferencesStore', 'store'), + ), + 'conditions': (None), + }, + { + 'name': 'SendDoubleAndFloat', + 'parameters': ( + ('double', 'd'), + ('float', 'f'), + ), + 'conditions': (None), + }, + { + 'name': 'SendInts', + 'parameters': ( + ('Vector<uint64_t>', 'ints'), + ('Vector<Vector<uint64_t> >', 'intVectors') + ), + 'conditions': (None), + }, + { + 'name': 'CreatePlugin', + 'parameters': ( + ('uint64_t', 'pluginInstanceID'), + ('WebKit::Plugin::Parameters', 'parameters') + ), + 'reply_parameters': ( + ('bool', 'result'), + ), + 'conditions': (None), + }, + { + 'name': 'RunJavaScriptAlert', + 'parameters': ( + ('uint64_t', 'frameID'), + ('WTF::String', 'message') + ), + 'reply_parameters': (), + 'conditions': (None), + }, + { + 'name': 'GetPlugins', + 'parameters': ( + ('bool', 'refresh'), + ), + 'reply_parameters': ( + ('Vector<WebCore::PluginInfo>', 'plugins'), + ), + 'conditions': (None), + }, + { + 'name': 'GetPluginProcessConnection', + 'parameters': ( + ('WTF::String', 'pluginPath'), + ), + 'reply_parameters': ( + ('CoreIPC::Connection::Handle', 'connectionHandle'), + ), + 'conditions': (None), + }, + { + 'name': 'TestMultipleAttributes', + 'parameters': ( + ), + 'reply_parameters': ( + ), + 'conditions': (None), + }, + { + 'name': 'TestConnectionQueue', + 'parameters': ( + ('uint64_t', 'pluginID'), + ), + 'conditions': (None), + }, + { + 'name': 'TestParameterAttributes', + 'parameters': ( + ('uint64_t', 'foo', ('AttributeOne', 'AttributeTwo')), + ('double', 'bar'), + ('double', 'baz', ('AttributeThree',)), + ), + 'conditions': (None), + }, + { + 'name': 'DidCreateWebProcessConnection', + 'parameters': ( + ('CoreIPC::MachPort', 'connectionIdentifier'), + ), + 'conditions': ('PLATFORM(MAC)'), + }, + { + 'name': 'InterpretKeyEvent', + 'parameters': ( + ('uint32_t', 'type'), + ), + 'reply_parameters': ( + ('Vector<WebCore::KeypressCommand>', 'commandName'), + ), + 'conditions': ('PLATFORM(MAC)'), + }, + { + 'name': 'DeprecatedOperation', + 'parameters': ( + ('CoreIPC::DummyType', 'dummy'), + ), + 'conditions': ('ENABLE(DEPRECATED_FEATURE)'), + }, + { + 'name': 'ExperimentalOperation', + 'parameters': ( + ('CoreIPC::DummyType', 'dummy'), + ), + 'conditions': ('ENABLE(EXPERIMENTAL_FEATURE)'), + } + ), +} + + +class MessagesTest(unittest.TestCase): + def setUp(self): + self.receiver = parser.parse(StringIO(_messages_file_contents)) + + +class ParsingTest(MessagesTest): + def check_message(self, message, expected_message): + self.assertEquals(message.name, expected_message['name']) + self.assertEquals(len(message.parameters), len(expected_message['parameters'])) + for index, parameter in enumerate(message.parameters): + expected_parameter = expected_message['parameters'][index] + self.assertEquals(parameter.type, expected_parameter[0]) + self.assertEquals(parameter.name, expected_parameter[1]) + if len(expected_parameter) > 2: + self.assertEquals(parameter.attributes, frozenset(expected_parameter[2])) + for attribute in expected_parameter[2]: + self.assertTrue(parameter.has_attribute(attribute)) + else: + self.assertEquals(parameter.attributes, frozenset()) + if message.reply_parameters != None: + for index, parameter in enumerate(message.reply_parameters): + self.assertEquals(parameter.type, expected_message['reply_parameters'][index][0]) + self.assertEquals(parameter.name, expected_message['reply_parameters'][index][1]) + else: + self.assertFalse('reply_parameters' in expected_message) + self.assertEquals(message.condition, expected_message['conditions']) + + def test_receiver(self): + """Receiver should be parsed as expected""" + self.assertEquals(self.receiver.name, _expected_results['name']) + self.assertEquals(self.receiver.condition, _expected_results['conditions']) + self.assertEquals(len(self.receiver.messages), len(_expected_results['messages'])) + for index, message in enumerate(self.receiver.messages): + self.check_message(message, _expected_results['messages'][index]) + +_expected_header = """/* + * Copyright (C) 2010 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. + */ + +#ifndef WebPageMessages_h +#define WebPageMessages_h + +#if ENABLE(WEBKIT2) + +#include "Arguments.h" +#include "Connection.h" +#include "MessageID.h" +#include "Plugin.h" +#include <WebCore/KeyboardEvent.h> +#include <WebCore/PluginData.h> +#include <wtf/ThreadSafeRefCounted.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + class ArgumentEncoder; + class Connection; + class DummyType; + class MachPort; +} + +namespace WTF { + class String; +} + +namespace WebKit { + struct WebPreferencesStore; + class WebTouchEvent; +} + +namespace Messages { + +namespace WebPage { + +enum Kind { + LoadURLID, +#if ENABLE(TOUCH_EVENTS) + TouchEventID, +#endif + DidReceivePolicyDecisionID, + CloseID, + PreferencesDidChangeID, + SendDoubleAndFloatID, + SendIntsID, + CreatePluginID, + RunJavaScriptAlertID, + GetPluginsID, + GetPluginProcessConnectionID, + TestMultipleAttributesID, + TestConnectionQueueID, + TestParameterAttributesID, +#if PLATFORM(MAC) + DidCreateWebProcessConnectionID, +#endif +#if PLATFORM(MAC) + InterpretKeyEventID, +#endif +#if ENABLE(DEPRECATED_FEATURE) + DeprecatedOperationID, +#endif +#if ENABLE(EXPERIMENTAL_FEATURE) + ExperimentalOperationID, +#endif +}; + +struct LoadURL : CoreIPC::Arguments1<const WTF::String&> { + static const Kind messageID = LoadURLID; + typedef CoreIPC::Arguments1<const WTF::String&> DecodeType; + explicit LoadURL(const WTF::String& url) + : CoreIPC::Arguments1<const WTF::String&>(url) + { + } +}; + +#if ENABLE(TOUCH_EVENTS) +struct TouchEvent : CoreIPC::Arguments1<const WebKit::WebTouchEvent&> { + static const Kind messageID = TouchEventID; + typedef CoreIPC::Arguments1<const WebKit::WebTouchEvent&> DecodeType; + explicit TouchEvent(const WebKit::WebTouchEvent& event) + : CoreIPC::Arguments1<const WebKit::WebTouchEvent&>(event) + { + } +}; +#endif + +struct DidReceivePolicyDecision : CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t> { + static const Kind messageID = DidReceivePolicyDecisionID; + typedef CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t> DecodeType; + DidReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction) + : CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t>(frameID, listenerID, policyAction) + { + } +}; + +struct Close : CoreIPC::Arguments0 { + static const Kind messageID = CloseID; + typedef CoreIPC::Arguments0 DecodeType; +}; + +struct PreferencesDidChange : CoreIPC::Arguments1<const WebKit::WebPreferencesStore&> { + static const Kind messageID = PreferencesDidChangeID; + typedef CoreIPC::Arguments1<const WebKit::WebPreferencesStore&> DecodeType; + explicit PreferencesDidChange(const WebKit::WebPreferencesStore& store) + : CoreIPC::Arguments1<const WebKit::WebPreferencesStore&>(store) + { + } +}; + +struct SendDoubleAndFloat : CoreIPC::Arguments2<double, float> { + static const Kind messageID = SendDoubleAndFloatID; + typedef CoreIPC::Arguments2<double, float> DecodeType; + SendDoubleAndFloat(double d, float f) + : CoreIPC::Arguments2<double, float>(d, f) + { + } +}; + +struct SendInts : CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&> { + static const Kind messageID = SendIntsID; + typedef CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&> DecodeType; + SendInts(const Vector<uint64_t>& ints, const Vector<Vector<uint64_t> >& intVectors) + : CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&>(ints, intVectors) + { + } +}; + +struct CreatePlugin : CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&> { + static const Kind messageID = CreatePluginID; + typedef CoreIPC::Arguments1<bool&> Reply; + typedef CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&> DecodeType; + CreatePlugin(uint64_t pluginInstanceID, const WebKit::Plugin::Parameters& parameters) + : CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&>(pluginInstanceID, parameters) + { + } +}; + +struct RunJavaScriptAlert : CoreIPC::Arguments2<uint64_t, const WTF::String&> { + static const Kind messageID = RunJavaScriptAlertID; + typedef CoreIPC::Arguments0 Reply; + typedef CoreIPC::Arguments2<uint64_t, const WTF::String&> DecodeType; + RunJavaScriptAlert(uint64_t frameID, const WTF::String& message) + : CoreIPC::Arguments2<uint64_t, const WTF::String&>(frameID, message) + { + } +}; + +struct GetPlugins : CoreIPC::Arguments1<bool> { + static const Kind messageID = GetPluginsID; + typedef CoreIPC::Arguments1<Vector<WebCore::PluginInfo>&> Reply; + typedef CoreIPC::Arguments1<bool> DecodeType; + explicit GetPlugins(bool refresh) + : CoreIPC::Arguments1<bool>(refresh) + { + } +}; + +struct GetPluginProcessConnection : CoreIPC::Arguments1<const WTF::String&> { + static const Kind messageID = GetPluginProcessConnectionID; + struct DelayedReply : public ThreadSafeRefCounted<DelayedReply> { + DelayedReply(PassRefPtr<CoreIPC::Connection>, PassOwnPtr<CoreIPC::ArgumentEncoder>); + ~DelayedReply(); + + bool send(const CoreIPC::Connection::Handle& connectionHandle); + + private: + RefPtr<CoreIPC::Connection> m_connection; + OwnPtr<CoreIPC::ArgumentEncoder> m_arguments; + }; + + typedef CoreIPC::Arguments1<CoreIPC::Connection::Handle&> Reply; + typedef CoreIPC::Arguments1<const WTF::String&> DecodeType; + explicit GetPluginProcessConnection(const WTF::String& pluginPath) + : CoreIPC::Arguments1<const WTF::String&>(pluginPath) + { + } +}; + +struct TestMultipleAttributes : CoreIPC::Arguments0 { + static const Kind messageID = TestMultipleAttributesID; + struct DelayedReply : public ThreadSafeRefCounted<DelayedReply> { + DelayedReply(PassRefPtr<CoreIPC::Connection>, PassOwnPtr<CoreIPC::ArgumentEncoder>); + ~DelayedReply(); + + bool send(); + + private: + RefPtr<CoreIPC::Connection> m_connection; + OwnPtr<CoreIPC::ArgumentEncoder> m_arguments; + }; + + typedef CoreIPC::Arguments0 Reply; + typedef CoreIPC::Arguments0 DecodeType; +}; + +struct TestConnectionQueue : CoreIPC::Arguments1<uint64_t> { + static const Kind messageID = TestConnectionQueueID; + typedef CoreIPC::Arguments1<uint64_t> DecodeType; + explicit TestConnectionQueue(uint64_t pluginID) + : CoreIPC::Arguments1<uint64_t>(pluginID) + { + } +}; + +struct TestParameterAttributes : CoreIPC::Arguments3<uint64_t, double, double> { + static const Kind messageID = TestParameterAttributesID; + typedef CoreIPC::Arguments3<uint64_t, double, double> DecodeType; + TestParameterAttributes(uint64_t foo, double bar, double baz) + : CoreIPC::Arguments3<uint64_t, double, double>(foo, bar, baz) + { + } +}; + +#if PLATFORM(MAC) +struct DidCreateWebProcessConnection : CoreIPC::Arguments1<const CoreIPC::MachPort&> { + static const Kind messageID = DidCreateWebProcessConnectionID; + typedef CoreIPC::Arguments1<const CoreIPC::MachPort&> DecodeType; + explicit DidCreateWebProcessConnection(const CoreIPC::MachPort& connectionIdentifier) + : CoreIPC::Arguments1<const CoreIPC::MachPort&>(connectionIdentifier) + { + } +}; +#endif + +#if PLATFORM(MAC) +struct InterpretKeyEvent : CoreIPC::Arguments1<uint32_t> { + static const Kind messageID = InterpretKeyEventID; + typedef CoreIPC::Arguments1<Vector<WebCore::KeypressCommand>&> Reply; + typedef CoreIPC::Arguments1<uint32_t> DecodeType; + explicit InterpretKeyEvent(uint32_t type) + : CoreIPC::Arguments1<uint32_t>(type) + { + } +}; +#endif + +#if ENABLE(DEPRECATED_FEATURE) +struct DeprecatedOperation : CoreIPC::Arguments1<const CoreIPC::DummyType&> { + static const Kind messageID = DeprecatedOperationID; + typedef CoreIPC::Arguments1<const CoreIPC::DummyType&> DecodeType; + explicit DeprecatedOperation(const CoreIPC::DummyType& dummy) + : CoreIPC::Arguments1<const CoreIPC::DummyType&>(dummy) + { + } +}; +#endif + +#if ENABLE(EXPERIMENTAL_FEATURE) +struct ExperimentalOperation : CoreIPC::Arguments1<const CoreIPC::DummyType&> { + static const Kind messageID = ExperimentalOperationID; + typedef CoreIPC::Arguments1<const CoreIPC::DummyType&> DecodeType; + explicit ExperimentalOperation(const CoreIPC::DummyType& dummy) + : CoreIPC::Arguments1<const CoreIPC::DummyType&>(dummy) + { + } +}; +#endif + +} // namespace WebPage + +} // namespace Messages + +namespace CoreIPC { + +template<> struct MessageKindTraits<Messages::WebPage::Kind> { + static const MessageClass messageClass = MessageClassWebPage; +}; + +} // namespace CoreIPC + +#endif // ENABLE(WEBKIT2) + +#endif // WebPageMessages_h +""" + +_expected_receiver_implementation = """/* + * Copyright (C) 2010 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. + */ + +#include "config.h" + +#if ENABLE(WEBKIT2) + +#include "WebPage.h" + +#include "ArgumentCoders.h" +#include "ArgumentDecoder.h" +#include "Connection.h" +#if ENABLE(DEPRECATED_FEATURE) || ENABLE(EXPERIMENTAL_FEATURE) +#include "DummyType.h" +#endif +#include "HandleMessage.h" +#if PLATFORM(MAC) +#include "MachPort.h" +#endif +#include "Plugin.h" +#include "WebCoreArgumentCoders.h" +#if ENABLE(TOUCH_EVENTS) +#include "WebEvent.h" +#endif +#include "WebPageMessages.h" +#include "WebPreferencesStore.h" +#if PLATFORM(MAC) +#include <WebCore/KeyboardEvent.h> +#endif +#include <WebCore/PluginData.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace Messages { + +namespace WebPage { + +GetPluginProcessConnection::DelayedReply::DelayedReply(PassRefPtr<CoreIPC::Connection> connection, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments) + : m_connection(connection) + , m_arguments(arguments) +{ +} + +GetPluginProcessConnection::DelayedReply::~DelayedReply() +{ + ASSERT(!m_connection); +} + +bool GetPluginProcessConnection::DelayedReply::send(const CoreIPC::Connection::Handle& connectionHandle) +{ + ASSERT(m_arguments); + m_arguments->encode(connectionHandle); + bool result = m_connection->sendSyncReply(m_arguments.release()); + m_connection = nullptr; + return result; +} + +TestMultipleAttributes::DelayedReply::DelayedReply(PassRefPtr<CoreIPC::Connection> connection, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments) + : m_connection(connection) + , m_arguments(arguments) +{ +} + +TestMultipleAttributes::DelayedReply::~DelayedReply() +{ + ASSERT(!m_connection); +} + +bool TestMultipleAttributes::DelayedReply::send() +{ + ASSERT(m_arguments); + bool result = m_connection->sendSyncReply(m_arguments.release()); + m_connection = nullptr; + return result; +} + +} // namespace WebPage + +} // namespace Messages + +namespace WebKit { + +void WebPage::didReceiveWebPageMessageOnConnectionWorkQueue(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage) +{ +#if COMPILER(MSVC) +#pragma warning(push) +#pragma warning(disable: 4065) +#endif + switch (messageID.get<Messages::WebPage::Kind>()) { + case Messages::WebPage::TestConnectionQueueID: + CoreIPC::handleMessage<Messages::WebPage::TestConnectionQueue>(arguments, this, &WebPage::testConnectionQueue); + didHandleMessage = true; + return; + default: + return; + } +#if COMPILER(MSVC) +#pragma warning(pop) +#endif +} + +void WebPage::didReceiveWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) +{ + switch (messageID.get<Messages::WebPage::Kind>()) { + case Messages::WebPage::LoadURLID: + CoreIPC::handleMessage<Messages::WebPage::LoadURL>(arguments, this, &WebPage::loadURL); + return; +#if ENABLE(TOUCH_EVENTS) + case Messages::WebPage::TouchEventID: + CoreIPC::handleMessage<Messages::WebPage::TouchEvent>(arguments, this, &WebPage::touchEvent); + return; +#endif + case Messages::WebPage::DidReceivePolicyDecisionID: + CoreIPC::handleMessage<Messages::WebPage::DidReceivePolicyDecision>(arguments, this, &WebPage::didReceivePolicyDecision); + return; + case Messages::WebPage::CloseID: + CoreIPC::handleMessage<Messages::WebPage::Close>(arguments, this, &WebPage::close); + return; + case Messages::WebPage::PreferencesDidChangeID: + CoreIPC::handleMessage<Messages::WebPage::PreferencesDidChange>(arguments, this, &WebPage::preferencesDidChange); + return; + case Messages::WebPage::SendDoubleAndFloatID: + CoreIPC::handleMessage<Messages::WebPage::SendDoubleAndFloat>(arguments, this, &WebPage::sendDoubleAndFloat); + return; + case Messages::WebPage::SendIntsID: + CoreIPC::handleMessage<Messages::WebPage::SendInts>(arguments, this, &WebPage::sendInts); + return; + case Messages::WebPage::TestParameterAttributesID: + CoreIPC::handleMessage<Messages::WebPage::TestParameterAttributes>(arguments, this, &WebPage::testParameterAttributes); + return; +#if PLATFORM(MAC) + case Messages::WebPage::DidCreateWebProcessConnectionID: + CoreIPC::handleMessage<Messages::WebPage::DidCreateWebProcessConnection>(arguments, this, &WebPage::didCreateWebProcessConnection); + return; +#endif +#if ENABLE(DEPRECATED_FEATURE) + case Messages::WebPage::DeprecatedOperationID: + CoreIPC::handleMessage<Messages::WebPage::DeprecatedOperation>(arguments, this, &WebPage::deprecatedOperation); + return; +#endif +#if ENABLE(EXPERIMENTAL_FEATURE) + case Messages::WebPage::ExperimentalOperationID: + CoreIPC::handleMessage<Messages::WebPage::ExperimentalOperation>(arguments, this, &WebPage::experimentalOperation); + return; +#endif + default: + break; + } + + ASSERT_NOT_REACHED(); +} + +void WebPage::didReceiveSyncWebPageMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply) +{ + switch (messageID.get<Messages::WebPage::Kind>()) { + case Messages::WebPage::CreatePluginID: + CoreIPC::handleMessage<Messages::WebPage::CreatePlugin>(arguments, reply.get(), this, &WebPage::createPlugin); + return; + case Messages::WebPage::RunJavaScriptAlertID: + CoreIPC::handleMessage<Messages::WebPage::RunJavaScriptAlert>(arguments, reply.get(), this, &WebPage::runJavaScriptAlert); + return; + case Messages::WebPage::GetPluginProcessConnectionID: + CoreIPC::handleMessageDelayed<Messages::WebPage::GetPluginProcessConnection>(connection, arguments, reply, this, &WebPage::getPluginProcessConnection); + return; +#if PLATFORM(MAC) + case Messages::WebPage::InterpretKeyEventID: + CoreIPC::handleMessage<Messages::WebPage::InterpretKeyEvent>(arguments, reply.get(), this, &WebPage::interpretKeyEvent); + return; +#endif + default: + break; + } + + ASSERT_NOT_REACHED(); +} + +} // namespace WebKit + +#endif // ENABLE(WEBKIT2) +""" + + +class GeneratedFileContentsTest(unittest.TestCase): + def assertGeneratedFileContentsEqual(self, first, second): + first_list = first.split('\n') + second_list = second.split('\n') + + for index, first_line in enumerate(first_list): + self.assertEquals(first_line, second_list[index]) + + self.assertEquals(len(first_list), len(second_list)) + + +class HeaderTest(GeneratedFileContentsTest): + def test_header(self): + file_contents = messages.generate_messages_header(StringIO(_messages_file_contents)) + self.assertGeneratedFileContentsEqual(file_contents, _expected_header) + + +class ReceiverImplementationTest(GeneratedFileContentsTest): + def test_receiver_implementation(self): + file_contents = messages.generate_message_handler(StringIO(_messages_file_contents)) + self.assertGeneratedFileContentsEqual(file_contents, _expected_receiver_implementation) + + +if __name__ == '__main__': + unittest.main() diff --git a/Source/WebKit2/Scripts/webkit2/model.py b/Source/WebKit2/Scripts/webkit2/model.py new file mode 100644 index 000000000..b10416c96 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/model.py @@ -0,0 +1,60 @@ +# Copyright (C) 2010, 2011 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 itertools + + +class MessageReceiver(object): + def __init__(self, name, messages, condition): + self.name = name + self.messages = messages + self.condition = condition + + def iterparameters(self): + return itertools.chain((parameter for message in self.messages for parameter in message.parameters), + (reply_parameter for message in self.messages if message.reply_parameters for reply_parameter in message.reply_parameters)) + + +class Message(object): + def __init__(self, name, parameters, reply_parameters, attributes, condition): + self.name = name + self.parameters = parameters + self.reply_parameters = reply_parameters + self.attributes = frozenset(attributes or []) + self.condition = condition + + def id(self): + return '%sID' % self.name + + def has_attribute(self, attribute): + return attribute in self.attributes + + +class Parameter(object): + def __init__(self, type, name, attributes=None, condition=None): + self.type = type + self.name = name + self.attributes = frozenset(attributes or []) + self.condition = condition + + def has_attribute(self, attribute): + return attribute in self.attributes diff --git a/Source/WebKit2/Scripts/webkit2/parser.py b/Source/WebKit2/Scripts/webkit2/parser.py new file mode 100644 index 000000000..525f137ec --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/parser.py @@ -0,0 +1,85 @@ +# Copyright (C) 2010, 2011 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 re + +import model + + +def parse(file): + destination = None + messages = [] + condition = None + master_condition = None + for line in file: + match = re.search(r'messages -> ([A-Za-z_0-9]+) {', line) + if match: + if condition: + master_condition = condition + condition = None + destination = match.group(1) + continue + if line.startswith('#'): + if line.startswith('#if '): + condition = line.rstrip()[4:] + elif line.startswith('#endif'): + condition = None + continue + match = re.search(r'([A-Za-z_0-9]+)\((.*?)\)(?:(?:\s+->\s+)\((.*?)\))?(?:\s+(.*))?', line) + if match: + name, parameters_string, reply_parameters_string, attributes_string = match.groups() + if parameters_string: + parameters = parse_parameters_string(parameters_string) + for parameter in parameters: + parameter.condition = condition + else: + parameters = [] + + attributes = parse_attributes_string(attributes_string) + + if reply_parameters_string: + reply_parameters = parse_parameters_string(reply_parameters_string) + for reply_parameter in reply_parameters: + reply_parameter.condition = condition + elif reply_parameters_string == '': + reply_parameters = [] + else: + reply_parameters = None + + messages.append(model.Message(name, parameters, reply_parameters, attributes, condition)) + return model.MessageReceiver(destination, messages, master_condition) + + +def parse_attributes_string(attributes_string): + if not attributes_string: + return None + return attributes_string.split() + + +def parse_parameters_string(parameters_string): + parameters = [] + for parameter_string in parameters_string.split(', '): + match = re.search(r'\s*(?:\[(?P<attributes>.*?)\]\s+)?(?P<type_and_name>.*)', parameter_string) + attributes_string, type_and_name_string = match.group('attributes', 'type_and_name') + parameter_type, parameter_name = type_and_name_string.rsplit(' ', 1) + parameters.append(model.Parameter(type=parameter_type, name=parameter_name, attributes=parse_attributes_string(attributes_string))) + return parameters |