1# Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
6# 1.  Redistributions of source code must retain the above copyright
7#     notice, this list of conditions and the following disclaimer.
8# 2.  Redistributions in binary form must reproduce the above copyright
9#     notice, this list of conditions and the following disclaimer in the
10#     documentation and/or other materials provided with the distribution.
11#
12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23import re
24
25from webkit2 import model
26
27
28def parse(file):
29    receiver_attributes = None
30    destination = None
31    messages = []
32    condition = None
33    master_condition = None
34    for line in file:
35        match = re.search(r'messages -> (?P<destination>[A-Za-z_0-9]+) \s*(?:(?P<attributes>.*?)\s+)?{', line)
36        if match:
37            receiver_attributes = parse_attributes_string(match.group('attributes'))
38
39            if condition:
40                master_condition = condition
41                condition = None
42            destination = match.group('destination')
43            continue
44        if line.startswith('#'):
45            if line.startswith('#if '):
46                condition = line.rstrip()[4:]
47            elif line.startswith('#endif'):
48                condition = None
49            continue
50        match = re.search(r'([A-Za-z_0-9]+)\((.*?)\)(?:(?:\s+->\s+)\((.*?)\))?(?:\s+(.*))?', line)
51        if match:
52            name, parameters_string, reply_parameters_string, attributes_string = match.groups()
53            if parameters_string:
54                parameters = parse_parameters_string(parameters_string)
55                for parameter in parameters:
56                    parameter.condition = condition
57            else:
58                parameters = []
59
60            attributes = parse_attributes_string(attributes_string)
61
62            if reply_parameters_string:
63                reply_parameters = parse_parameters_string(reply_parameters_string)
64                for reply_parameter in reply_parameters:
65                    reply_parameter.condition = condition
66            elif reply_parameters_string == '':
67                reply_parameters = []
68            else:
69                reply_parameters = None
70
71            messages.append(model.Message(name, parameters, reply_parameters, attributes, condition))
72    return model.MessageReceiver(destination, receiver_attributes, messages, master_condition)
73
74
75def parse_attributes_string(attributes_string):
76    if not attributes_string:
77        return None
78    return attributes_string.split()
79
80
81def split_parameters_string(parameters_string):
82    parameters = []
83    current_parameter_string = ''
84
85    nest_level = 0
86    for character in parameters_string:
87        if character == ',' and nest_level == 0:
88            parameters.append(current_parameter_string)
89            current_parameter_string = ''
90            continue
91
92        if character == '<':
93            nest_level += 1
94        elif character == '>':
95            nest_level -= 1
96
97        current_parameter_string += character
98
99    parameters.append(current_parameter_string)
100    return parameters
101
102def parse_parameters_string(parameters_string):
103    parameters = []
104
105    for parameter_string in split_parameters_string(parameters_string):
106        match = re.search(r'\s*(?:\[(?P<attributes>.*?)\]\s+)?(?P<type_and_name>.*)', parameter_string)
107        attributes_string, type_and_name_string = match.group('attributes', 'type_and_name')
108        parameter_type, parameter_name = type_and_name_string.rsplit(' ', 1)
109        parameters.append(model.Parameter(type=parameter_type, name=parameter_name, attributes=parse_attributes_string(attributes_string)))
110    return parameters
111