]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env python | |
2 | # | |
3 | # Copyright (c) 2014 Apple Inc. All rights reserved. | |
4 | # Copyright (c) 2014 University of Washington. All rights reserved. | |
5 | # | |
6 | # Redistribution and use in source and binary forms, with or without | |
7 | # modification, are permitted provided that the following conditions | |
8 | # are met: | |
9 | # 1. Redistributions of source code must retain the above copyright | |
10 | # notice, this list of conditions and the following disclaimer. | |
11 | # 2. Redistributions in binary form must reproduce the above copyright | |
12 | # notice, this list of conditions and the following disclaimer in the | |
13 | # documentation and/or other materials provided with the distribution. | |
14 | # | |
15 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
17 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
18 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
19 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
20 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
21 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
22 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
23 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
24 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
25 | # THE POSSIBILITY OF SUCH DAMAGE. | |
26 | ||
27 | import logging | |
28 | import os.path | |
29 | import re | |
30 | ||
31 | from generator import ucfirst | |
32 | from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks | |
33 | ||
34 | log = logging.getLogger('global') | |
35 | ||
36 | _PRIMITIVE_TO_CPP_NAME_MAP = { | |
37 | 'boolean': 'bool', | |
38 | 'integer': 'int', | |
39 | 'number': 'double', | |
40 | 'string': 'String', | |
41 | 'object': 'Inspector::InspectorObject', | |
42 | 'array': 'Inspector::InspectorArray', | |
43 | 'any': 'Inspector::InspectorValue' | |
44 | } | |
45 | ||
46 | # This class contains extra static methods used for generation, but does | |
47 | # not participate in any inheritance hierarchy. File generators should | |
48 | # extend the generic "Generator" class instead. | |
49 | class CppGenerator: | |
50 | ||
51 | # Miscellaneous text manipulation routines. | |
52 | @staticmethod | |
53 | def cpp_getter_method_for_type(_type): | |
54 | if isinstance(_type, ObjectType): | |
55 | return 'getObject' | |
56 | if isinstance(_type, ArrayType): | |
57 | return 'getArray' | |
58 | if isinstance(_type, PrimitiveType): | |
59 | if _type.raw_name() is 'integer': | |
60 | return 'getInteger' | |
61 | elif _type.raw_name() is 'number': | |
62 | return 'getDouble' | |
63 | elif _type.raw_name() is 'any': | |
64 | return 'getValue' | |
65 | else: | |
66 | return 'get' + ucfirst(_type.raw_name()) | |
67 | if isinstance(_type, AliasedType): | |
68 | return CppGenerator.cpp_getter_method_for_type(_type.aliased_type) | |
69 | if isinstance(_type, EnumType): | |
70 | return CppGenerator.cpp_getter_method_for_type(_type.primitive_type) | |
71 | ||
72 | @staticmethod | |
73 | def cpp_setter_method_for_type(_type): | |
74 | if isinstance(_type, ObjectType): | |
75 | return 'setObject' | |
76 | if isinstance(_type, ArrayType): | |
77 | return 'setArray' | |
78 | if isinstance(_type, PrimitiveType): | |
79 | if _type.raw_name() is 'integer': | |
80 | return 'setInteger' | |
81 | elif _type.raw_name() is 'number': | |
82 | return 'setDouble' | |
83 | elif _type.raw_name() is 'any': | |
84 | return 'setValue' | |
85 | else: | |
86 | return 'set' + ucfirst(_type.raw_name()) | |
87 | if isinstance(_type, AliasedType): | |
88 | return CppGenerator.cpp_setter_method_for_type(_type.aliased_type) | |
89 | if isinstance(_type, EnumType): | |
90 | return CppGenerator.cpp_setter_method_for_type(_type.primitive_type) | |
91 | ||
92 | # Generate type representations for various situations. | |
93 | @staticmethod | |
94 | def cpp_protocol_type_for_type(_type): | |
95 | if isinstance(_type, ObjectType) and len(_type.members) == 0: | |
96 | return 'Inspector::InspectorObject' | |
97 | if isinstance(_type, ArrayType): | |
98 | if _type.raw_name() is None: # Otherwise, fall through and use typedef'd name. | |
99 | return 'Inspector::Protocol::Array<%s>' % CppGenerator.cpp_protocol_type_for_type(_type.element_type) | |
100 | if isinstance(_type, (ObjectType, AliasedType, EnumType, ArrayType)): | |
101 | return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) | |
102 | if isinstance(_type, PrimitiveType): | |
103 | return CppGenerator.cpp_name_for_primitive_type(_type) | |
104 | ||
105 | @staticmethod | |
106 | def cpp_protocol_type_for_type_member(type_member, object_declaration): | |
107 | if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous: | |
108 | return '::'.join([CppGenerator.cpp_protocol_type_for_type(object_declaration.type), ucfirst(type_member.member_name)]) | |
109 | else: | |
110 | return CppGenerator.cpp_protocol_type_for_type(type_member.type) | |
111 | ||
112 | @staticmethod | |
113 | def cpp_type_for_unchecked_formal_in_parameter(parameter): | |
114 | _type = parameter.type | |
115 | if isinstance(_type, AliasedType): | |
116 | _type = _type.aliased_type # Fall through to enum or primitive. | |
117 | ||
118 | if isinstance(_type, EnumType): | |
119 | _type = _type.primitive_type # Fall through to primitive. | |
120 | ||
121 | # This handles the 'any' type and objects with defined properties. | |
122 | if isinstance(_type, ObjectType) or _type.qualified_name() is 'object': | |
123 | cpp_name = 'Inspector::InspectorObject' | |
124 | if parameter.is_optional: | |
125 | return 'const %s*' % cpp_name | |
126 | else: | |
127 | return 'const %s&' % cpp_name | |
128 | if isinstance(_type, ArrayType): | |
129 | cpp_name = 'Inspector::InspectorArray' | |
130 | if parameter.is_optional: | |
131 | return 'const %s*' % cpp_name | |
132 | else: | |
133 | return 'const %s&' % cpp_name | |
134 | if isinstance(_type, PrimitiveType): | |
135 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
136 | if parameter.is_optional: | |
137 | return 'const %s*' % cpp_name | |
138 | elif _type.raw_name() in ['string']: | |
139 | return 'const %s&' % cpp_name | |
140 | else: | |
141 | return cpp_name | |
142 | ||
143 | return "unknown_unchecked_formal_in_parameter_type" | |
144 | ||
145 | @staticmethod | |
146 | def cpp_type_for_checked_formal_event_parameter(parameter): | |
147 | return CppGenerator.cpp_type_for_type_with_name(parameter.type, parameter.parameter_name, parameter.is_optional) | |
148 | ||
149 | @staticmethod | |
150 | def cpp_type_for_type_member(member): | |
151 | return CppGenerator.cpp_type_for_type_with_name(member.type, member.member_name, False) | |
152 | ||
153 | @staticmethod | |
154 | def cpp_type_for_type_with_name(_type, type_name, is_optional): | |
155 | if isinstance(_type, (ArrayType, ObjectType)): | |
156 | return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type) | |
157 | if isinstance(_type, AliasedType): | |
158 | builder_type = CppGenerator.cpp_protocol_type_for_type(_type) | |
159 | if is_optional: | |
160 | return 'const %s* const' % builder_type | |
161 | elif _type.aliased_type.qualified_name() in ['integer', 'number']: | |
162 | return CppGenerator.cpp_name_for_primitive_type(_type.aliased_type) | |
163 | elif _type.aliased_type.qualified_name() in ['string']: | |
164 | return 'const %s&' % builder_type | |
165 | else: | |
166 | return builder_type | |
167 | if isinstance(_type, PrimitiveType): | |
168 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
169 | if _type.qualified_name() in ['object']: | |
170 | return 'RefPtr<Inspector::InspectorObject>' | |
171 | elif _type.qualified_name() in ['any']: | |
172 | return 'RefPtr<Inspector::InspectorValue>' | |
173 | elif is_optional: | |
174 | return 'const %s* const' % cpp_name | |
175 | elif _type.qualified_name() in ['string']: | |
176 | return 'const %s&' % cpp_name | |
177 | else: | |
178 | return cpp_name | |
179 | if isinstance(_type, EnumType): | |
180 | if _type.is_anonymous: | |
181 | enum_type_name = ucfirst(type_name) | |
182 | else: | |
183 | enum_type_name = 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) | |
184 | ||
185 | if is_optional: | |
186 | return '%s*' % enum_type_name | |
187 | else: | |
188 | return '%s' % enum_type_name | |
189 | ||
190 | @staticmethod | |
191 | def cpp_type_for_formal_out_parameter(parameter): | |
192 | _type = parameter.type | |
193 | ||
194 | if isinstance(_type, AliasedType): | |
195 | _type = _type.aliased_type # Fall through. | |
196 | ||
197 | if isinstance(_type, (ObjectType, ArrayType)): | |
198 | return 'RefPtr<%s>&' % CppGenerator.cpp_protocol_type_for_type(_type) | |
199 | if isinstance(_type, PrimitiveType): | |
200 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
201 | if parameter.is_optional: | |
202 | return "Inspector::Protocol::OptOutput<%s>*" % cpp_name | |
203 | else: | |
204 | return '%s*' % cpp_name | |
205 | if isinstance(_type, EnumType): | |
206 | if _type.is_anonymous: | |
207 | return '%sBackendDispatcherHandler::%s*' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name)) | |
208 | else: | |
209 | return 'Inspector::Protocol::%s::%s*' % (_type.type_domain().domain_name, _type.raw_name()) | |
210 | ||
211 | raise ValueError("unknown formal out parameter type.") | |
212 | ||
213 | # FIXME: this is only slightly different from out parameters; they could be unified. | |
214 | @staticmethod | |
215 | def cpp_type_for_formal_async_parameter(parameter): | |
216 | _type = parameter.type | |
217 | if isinstance(_type, AliasedType): | |
218 | _type = _type.aliased_type # Fall through. | |
219 | ||
220 | if isinstance(_type, EnumType): | |
221 | _type = _type.primitive_type # Fall through. | |
222 | ||
223 | if isinstance(_type, (ObjectType, ArrayType)): | |
224 | return 'RefPtr<%s>&&' % CppGenerator.cpp_protocol_type_for_type(_type) | |
225 | if isinstance(_type, PrimitiveType): | |
226 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
227 | if parameter.is_optional: | |
228 | return "Inspector::Protocol::OptOutput<%s>*" % cpp_name | |
229 | elif _type.qualified_name() in ['integer', 'number']: | |
230 | return CppGenerator.cpp_name_for_primitive_type(_type) | |
231 | elif _type.qualified_name() in ['string']: | |
232 | return 'const %s&' % cpp_name | |
233 | else: | |
234 | return cpp_name | |
235 | ||
236 | raise ValueError("Unknown formal async parameter type.") | |
237 | ||
238 | # In-parameters don't use builder types, because they could be passed | |
239 | # "open types" that are manually constructed out of InspectorObjects. | |
240 | ||
241 | # FIXME: Only parameters that are actually open types should need non-builder parameter types. | |
242 | @staticmethod | |
243 | def cpp_type_for_stack_in_parameter(parameter): | |
244 | _type = parameter.type | |
245 | if isinstance(_type, AliasedType): | |
246 | _type = _type.aliased_type # Fall through. | |
247 | ||
248 | if isinstance(_type, EnumType): | |
249 | _type = _type.primitive_type # Fall through. | |
250 | ||
251 | if isinstance(_type, ObjectType): | |
252 | return "RefPtr<Inspector::InspectorObject>" | |
253 | if isinstance(_type, ArrayType): | |
254 | return "RefPtr<Inspector::InspectorArray>" | |
255 | if isinstance(_type, PrimitiveType): | |
256 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
257 | if _type.qualified_name() in ['any', 'object']: | |
258 | return "RefPtr<%s>" % CppGenerator.cpp_name_for_primitive_type(_type) | |
259 | elif parameter.is_optional and _type.qualified_name() not in ['boolean', 'string', 'integer']: | |
260 | return "Inspector::Protocol::OptOutput<%s>" % cpp_name | |
261 | else: | |
262 | return cpp_name | |
263 | ||
264 | @staticmethod | |
265 | def cpp_type_for_stack_out_parameter(parameter): | |
266 | _type = parameter.type | |
267 | if isinstance(_type, (ArrayType, ObjectType)): | |
268 | return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type) | |
269 | if isinstance(_type, AliasedType): | |
270 | builder_type = CppGenerator.cpp_protocol_type_for_type(_type) | |
271 | if parameter.is_optional: | |
272 | return "Inspector::Protocol::OptOutput<%s>" % builder_type | |
273 | return '%s' % builder_type | |
274 | if isinstance(_type, PrimitiveType): | |
275 | cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) | |
276 | if parameter.is_optional: | |
277 | return "Inspector::Protocol::OptOutput<%s>" % cpp_name | |
278 | else: | |
279 | return cpp_name | |
280 | if isinstance(_type, EnumType): | |
281 | if _type.is_anonymous: | |
282 | return '%sBackendDispatcherHandler::%s' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name)) | |
283 | else: | |
284 | return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) | |
285 | ||
286 | @staticmethod | |
287 | def cpp_assertion_method_for_type_member(type_member, object_declaration): | |
288 | ||
289 | def assertion_method_for_type(_type): | |
290 | return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type(_type) | |
291 | ||
292 | if isinstance(type_member.type, AliasedType): | |
293 | return assertion_method_for_type(type_member.type.aliased_type) | |
294 | if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous: | |
295 | return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type_member(type_member, object_declaration) | |
296 | ||
297 | return assertion_method_for_type(type_member.type) | |
298 | ||
299 | @staticmethod | |
300 | def cpp_name_for_primitive_type(_type): | |
301 | return _PRIMITIVE_TO_CPP_NAME_MAP.get(_type.raw_name()) | |
302 | ||
303 | # Decide whether certain helpers are necessary in a situation. | |
304 | @staticmethod | |
305 | def should_use_wrapper_for_return_type(_type): | |
306 | return not isinstance(_type, (ArrayType, ObjectType)) | |
307 | ||
308 | @staticmethod | |
309 | def should_use_references_for_type(_type): | |
310 | return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() in ["any", "object"]) | |
311 | ||
312 | @staticmethod | |
313 | def should_pass_by_copy_for_return_type(_type): | |
314 | return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() == "object") |