Commit | Line | Data |
---|---|---|
d44e3c4f | 1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * Balasko, Jeno | |
10 | * Baranyi, Botond | |
11 | * Delic, Adam | |
12 | * Kovacs, Ferenc | |
13 | * Raduly, Csaba | |
14 | * Szabados, Kristof | |
15 | * Zalanyi, Balazs Andor | |
16 | * | |
17 | ******************************************************************************/ | |
970ed795 EL |
18 | #include "Ttcnstuff.hh" |
19 | #include "../Int.hh" | |
20 | #include "../CompilerError.hh" | |
21 | #include "AST_ttcn3.hh" | |
22 | #include "../main.hh" | |
23 | #include "Attributes.hh" | |
24 | #include <errno.h> | |
25 | ||
26 | // implemented in coding_attrib_p.y | |
27 | extern Ttcn::ExtensionAttributes * parse_extattributes( | |
28 | Ttcn::WithAttribPath *w_attrib_path); | |
29 | ||
30 | namespace Ttcn { | |
31 | ||
32 | // ================================= | |
33 | // ===== ErrorBehaviorSetting | |
34 | // ================================= | |
35 | ||
36 | ErrorBehaviorSetting *ErrorBehaviorSetting::clone() const | |
37 | { | |
38 | FATAL_ERROR("ErrorBehaviorSetting::clone"); | |
39 | } | |
40 | ||
41 | void ErrorBehaviorSetting::dump(unsigned level) const | |
42 | { | |
43 | DEBUG(level, "%s : %s", error_type.c_str(), error_handling.c_str()); | |
44 | } | |
45 | ||
46 | // ================================= | |
47 | // ===== ErrorBehaviorList | |
48 | // ================================= | |
49 | ||
50 | ErrorBehaviorList::~ErrorBehaviorList() | |
51 | { | |
52 | for (size_t i = 0; i < ebs_v.size(); i++) | |
53 | delete ebs_v[i]; | |
54 | ebs_v.clear(); | |
55 | ebs_m.clear(); | |
56 | } | |
57 | ||
58 | ErrorBehaviorList *ErrorBehaviorList::clone() const | |
59 | { | |
60 | FATAL_ERROR("ErrorBehaviorList::clone"); | |
61 | } | |
62 | ||
63 | void ErrorBehaviorList::set_fullname(const string& p_fullname) | |
64 | { | |
65 | Node::set_fullname(p_fullname); | |
66 | for (size_t i = 0; i < ebs_v.size(); i++) | |
67 | ebs_v[i]->set_fullname(p_fullname | |
68 | + ".<setting" + Common::Int2string(i + 1) + ">"); | |
69 | } | |
70 | ||
71 | void ErrorBehaviorList::add_ebs(ErrorBehaviorSetting *p_ebs) | |
72 | { | |
73 | if (!p_ebs || checked) FATAL_ERROR("ErrorBehaviorList::add_ebs()"); | |
74 | ebs_v.add(p_ebs); | |
75 | } | |
76 | ||
77 | void ErrorBehaviorList::steal_ebs(ErrorBehaviorList *p_eblist) | |
78 | { | |
79 | if (!p_eblist || checked || p_eblist->checked) | |
80 | FATAL_ERROR("ErrorBehaviorList::steal_ebs()"); | |
81 | for (size_t i = 0; i < p_eblist->ebs_v.size(); i++) | |
82 | ebs_v.add(p_eblist->ebs_v[i]); | |
83 | p_eblist->ebs_v.clear(); | |
84 | join_location(*p_eblist); | |
85 | } | |
86 | ||
87 | bool ErrorBehaviorList::has_setting(const string& p_error_type) | |
88 | { | |
89 | if (!checked) chk(); | |
90 | return ebs_all != 0 || ebs_m.has_key(p_error_type); | |
91 | } | |
92 | ||
93 | string ErrorBehaviorList::get_handling(const string& p_error_type) | |
94 | { | |
95 | if (!checked) chk(); | |
96 | if (ebs_m.has_key(p_error_type)) | |
97 | return ebs_m[p_error_type]->get_error_handling(); | |
98 | else if (ebs_all) return ebs_all->get_error_handling(); | |
99 | else return string("DEFAULT"); | |
100 | } | |
101 | ||
102 | void ErrorBehaviorList::chk() | |
103 | { | |
104 | if (checked) return; | |
105 | const string all_str("ALL"); | |
106 | Common::Error_Context cntxt(this, "In error behavior list"); | |
107 | for (size_t i = 0; i < ebs_v.size(); i++) { | |
108 | ErrorBehaviorSetting *ebs = ebs_v[i]; | |
109 | const string& error_type = ebs->get_error_type(); | |
110 | if (error_type == all_str) { | |
111 | if (ebs_all) { | |
112 | ebs->warning("Duplicate setting for error type `ALL'"); | |
113 | ebs_all->warning("The previous setting is ignored"); | |
114 | } | |
115 | ebs_all = ebs; | |
116 | if (!ebs_m.empty()) { | |
117 | ebs->warning("All settings before `ALL' are ignored"); | |
118 | ebs_m.clear(); | |
119 | } | |
120 | } else { | |
121 | if (ebs_m.has_key(error_type)) { | |
122 | ebs->warning("Duplicate setting for error type `%s'", | |
123 | error_type.c_str()); | |
124 | ErrorBehaviorSetting*& ebs_ref = ebs_m[error_type]; | |
125 | ebs_ref->warning("The previous setting is ignored"); | |
126 | // replace the previous setting in the map | |
127 | ebs_ref = ebs; | |
128 | } else ebs_m.add(error_type, ebs); | |
129 | static const char * const valid_types[] = { | |
130 | "UNBOUND", "INCOMPL_ANY", "ENC_ENUM", "INCOMPL_MSG", "LEN_FORM", | |
131 | "INVAL_MSG", "REPR", "CONSTRAINT", "TAG", "SUPERFL", "EXTENSION", | |
132 | "DEC_ENUM", "DEC_DUPFLD", "DEC_MISSFLD", "DEC_OPENTYPE", "DEC_UCSTR", | |
133 | "LEN_ERR", "SIGN_ERR", "INCOMP_ORDER", "TOKEN_ERR", "LOG_MATCHING", | |
134 | "FLOAT_TR", "FLOAT_NAN", "OMITTED_TAG", "NEGTEST_CONFL", NULL }; | |
135 | bool type_found = false; | |
136 | for (const char * const *str = valid_types; *str; str++) { | |
137 | if (error_type == *str) { | |
138 | type_found = true; | |
139 | break; | |
140 | } | |
141 | } | |
142 | if (!type_found) { | |
143 | ebs->warning("String `%s' is not a valid error type", | |
144 | error_type.c_str()); | |
145 | } | |
146 | } | |
147 | const string& error_handling = ebs->get_error_handling(); | |
148 | static const char * const valid_handlings[] = { | |
149 | "DEFAULT", "ERROR", "WARNING", "IGNORE", NULL }; | |
150 | bool handling_found = false; | |
151 | for (const char * const *str = valid_handlings; *str; str++) { | |
152 | if (error_handling == *str) { | |
153 | handling_found = true; | |
154 | break; | |
155 | } | |
156 | } | |
157 | if (!handling_found) { | |
158 | ebs->warning("String `%s' is not a valid error handling", | |
159 | error_handling.c_str()); | |
160 | } | |
161 | } | |
162 | checked = true; | |
163 | } | |
164 | ||
165 | char *ErrorBehaviorList::generate_code(char *str) | |
166 | { | |
167 | if (!checked) FATAL_ERROR("ErrorBehaviorList::generate_code()"); | |
168 | const string all_str("ALL"); | |
169 | if (ebs_all) { | |
170 | str = mputprintf(str, "TTCN_EncDec::set_error_behavior(" | |
171 | "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_%s);\n", | |
172 | ebs_all->get_error_handling().c_str()); | |
173 | } else { | |
174 | // reset all error behavior to default | |
175 | str = mputstr(str, "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " | |
176 | "TTCN_EncDec::EB_DEFAULT);\n"); | |
177 | } | |
178 | for (size_t i = 0; i < ebs_m.size(); i++) { | |
179 | ErrorBehaviorSetting *ebs = ebs_m.get_nth_elem(i); | |
180 | str = mputprintf(str, "TTCN_EncDec::set_error_behavior(" | |
181 | "TTCN_EncDec::ET_%s, TTCN_EncDec::EB_%s);\n", | |
182 | ebs->get_error_type().c_str(), ebs->get_error_handling().c_str()); | |
183 | } | |
184 | return str; | |
185 | } | |
186 | ||
187 | void ErrorBehaviorList::dump(unsigned level) const | |
188 | { | |
189 | DEBUG(level, "Error behavior: (%lu pcs.)", (unsigned long) ebs_v.size()); | |
190 | for (size_t i = 0; i < ebs_v.size(); i++) | |
191 | ebs_v[i]->dump(level + 1); | |
192 | } | |
193 | ||
194 | // ================================= | |
195 | // ===== PrintingType | |
196 | // ================================= | |
197 | ||
198 | PrintingType *PrintingType::clone() const | |
199 | { | |
200 | FATAL_ERROR("PrintingType::clone"); | |
201 | } | |
202 | ||
203 | char *PrintingType::generate_code(char *str) | |
204 | { | |
205 | return mputprintf(str, ", %d", (PT_PRETTY == printing) ? 1 : 0); | |
206 | } | |
207 | ||
208 | // ================================= | |
209 | // ===== TypeMappingTarget | |
210 | // ================================= | |
211 | ||
212 | TypeMappingTarget::TypeMappingTarget(Common::Type *p_target_type, | |
213 | TypeMappingType_t p_mapping_type) | |
214 | : Node(), Location(), target_type(p_target_type), | |
215 | mapping_type(p_mapping_type), checked(false) | |
216 | { | |
217 | if (p_mapping_type == TM_SIMPLE && p_target_type != NULL) { // acceptable | |
218 | target_type->set_ownertype(Type::OT_TYPE_MAP_TARGET, this); | |
219 | } | |
220 | else if (p_mapping_type == TM_DISCARD && p_target_type == NULL) | |
221 | {} // also acceptable but nothing to do | |
222 | else FATAL_ERROR("TypeMappingTarget::TypeMappingTarget()"); | |
223 | } | |
224 | ||
225 | TypeMappingTarget::TypeMappingTarget(Common::Type *p_target_type, | |
226 | TypeMappingType_t p_mapping_type, Ttcn::Reference *p_function_ref) | |
227 | : Node(), Location(), target_type(p_target_type), | |
228 | mapping_type(p_mapping_type), checked(false) | |
229 | { | |
230 | if (!p_target_type || p_mapping_type != TM_FUNCTION || !p_function_ref) | |
231 | FATAL_ERROR("TypeMappingTarget::TypeMappingTarget()"); | |
232 | u.func.function_ref = p_function_ref; | |
233 | u.func.function_ptr = 0; | |
234 | target_type->set_ownertype(Type::OT_TYPE_MAP_TARGET, this); | |
235 | } | |
236 | ||
237 | TypeMappingTarget::TypeMappingTarget(Common::Type *p_target_type, | |
238 | TypeMappingType_t p_mapping_type, | |
239 | Common::Type::MessageEncodingType_t p_coding_type, string *p_coding_options, | |
240 | ErrorBehaviorList *p_eb_list) | |
241 | : Node(), Location(), target_type(p_target_type), | |
242 | mapping_type(p_mapping_type), checked(false) | |
243 | { | |
244 | if (!p_target_type || (p_mapping_type != TM_ENCODE && | |
245 | p_mapping_type != TM_DECODE)) | |
246 | FATAL_ERROR("TypeMappingTarget::TypeMappingTarget()"); | |
247 | u.encdec.coding_type = p_coding_type; | |
248 | u.encdec.coding_options = p_coding_options; | |
249 | u.encdec.eb_list = p_eb_list; | |
250 | target_type->set_ownertype(Type::OT_TYPE_MAP_TARGET, this); | |
251 | } | |
252 | ||
253 | TypeMappingTarget::~TypeMappingTarget() | |
254 | { | |
255 | delete target_type; | |
256 | switch (mapping_type) { | |
257 | case TM_FUNCTION: | |
258 | delete u.func.function_ref; | |
259 | break; | |
260 | case TM_ENCODE: | |
261 | case TM_DECODE: | |
262 | delete u.encdec.coding_options; | |
263 | delete u.encdec.eb_list; | |
264 | default: | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | TypeMappingTarget *TypeMappingTarget::clone() const | |
270 | { | |
271 | FATAL_ERROR("TypeMappingTarget::clone"); | |
272 | } | |
273 | ||
274 | void TypeMappingTarget::set_fullname(const string& p_fullname) | |
275 | { | |
276 | Node::set_fullname(p_fullname); | |
277 | if (target_type) target_type->set_fullname(p_fullname + ".<target_type>"); | |
278 | switch (mapping_type) { | |
279 | case TM_SIMPLE: | |
280 | case TM_DISCARD: | |
281 | break; | |
282 | case TM_FUNCTION: | |
283 | u.func.function_ref->set_fullname(p_fullname + ".<function_ref>"); | |
284 | break; | |
285 | case TM_ENCODE: | |
286 | case TM_DECODE: | |
287 | if (u.encdec.eb_list) | |
288 | u.encdec.eb_list->set_fullname(p_fullname + ".<errorbehavior>"); | |
289 | break; | |
290 | default: | |
291 | FATAL_ERROR("TypeMappingTarget::set_fullname()"); | |
292 | } | |
293 | } | |
294 | ||
295 | void TypeMappingTarget::set_my_scope(Common::Scope *p_scope) | |
296 | { | |
297 | if (target_type) target_type->set_my_scope(p_scope); | |
298 | switch (mapping_type) { | |
299 | case TM_SIMPLE: | |
300 | case TM_DISCARD: | |
301 | case TM_ENCODE: | |
302 | case TM_DECODE: | |
303 | break; | |
304 | case TM_FUNCTION: | |
305 | u.func.function_ref->set_my_scope(p_scope); | |
306 | break; | |
307 | default: | |
308 | FATAL_ERROR("TypeMappingTarget::set_my_scope()"); | |
309 | } | |
310 | } | |
311 | ||
312 | const char *TypeMappingTarget::get_mapping_name() const | |
313 | { | |
314 | switch (mapping_type) { | |
315 | case TM_SIMPLE: | |
316 | return "simple"; | |
317 | case TM_DISCARD: | |
318 | return "discard"; | |
319 | case TM_FUNCTION: | |
320 | return "function"; | |
321 | case TM_ENCODE: | |
322 | return "encode"; | |
323 | case TM_DECODE: | |
324 | return "decode"; | |
325 | default: | |
326 | return "<unknown mapping>"; | |
327 | } | |
328 | } | |
329 | ||
330 | Ttcn::Def_Function_Base *TypeMappingTarget::get_function() const | |
331 | { | |
332 | if (mapping_type != TM_FUNCTION || !checked) | |
333 | FATAL_ERROR("TypeMappingTarget::get_function()"); | |
334 | return u.func.function_ptr; | |
335 | } | |
336 | ||
337 | Type::MessageEncodingType_t TypeMappingTarget::get_coding_type() const | |
338 | { | |
339 | if (mapping_type != TM_ENCODE && mapping_type != TM_DECODE) | |
340 | FATAL_ERROR("TypeMappingTarget::get_coding_type()"); | |
341 | return u.encdec.coding_type; | |
342 | } | |
343 | ||
344 | bool TypeMappingTarget::has_coding_options() const | |
345 | { | |
346 | if (mapping_type != TM_ENCODE && mapping_type != TM_DECODE) | |
347 | FATAL_ERROR("TypeMappingTarget::has_coding_options()"); | |
348 | return u.encdec.coding_options != 0; | |
349 | } | |
350 | ||
351 | const string& TypeMappingTarget::get_coding_options() const | |
352 | { | |
353 | if ((mapping_type != TM_ENCODE && mapping_type != TM_DECODE) || | |
354 | !u.encdec.coding_options) | |
355 | FATAL_ERROR("TypeMappingTarget::get_coding_options()"); | |
356 | return *u.encdec.coding_options; | |
357 | } | |
358 | ||
359 | ErrorBehaviorList *TypeMappingTarget::get_eb_list() const | |
360 | { | |
361 | if (mapping_type != TM_ENCODE && mapping_type != TM_DECODE) | |
362 | FATAL_ERROR("TypeMappingTarget::get_eb_list()"); | |
363 | return u.encdec.eb_list; | |
364 | } | |
365 | ||
366 | void TypeMappingTarget::chk_simple(Type *source_type) | |
367 | { | |
368 | Error_Context cntxt(this, "In `simple' mapping"); | |
369 | if (!source_type->is_identical(target_type)) { | |
370 | target_type->error("The source and target types must be the same: " | |
371 | "`%s' was expected instead of `%s'", | |
372 | source_type->get_typename().c_str(), | |
373 | target_type->get_typename().c_str()); | |
374 | } | |
375 | } | |
376 | ||
377 | void TypeMappingTarget::chk_function(Type *source_type) | |
378 | { | |
379 | Error_Context cntxt(this, "In `function' mapping"); | |
380 | Assignment *t_ass = u.func.function_ref->get_refd_assignment(false); | |
381 | if (!t_ass) return; | |
382 | t_ass->chk(); | |
383 | switch (t_ass->get_asstype()) { | |
384 | case Assignment::A_FUNCTION: | |
385 | case Assignment::A_FUNCTION_RVAL: | |
386 | case Assignment::A_FUNCTION_RTEMP: | |
387 | case Assignment::A_EXT_FUNCTION: | |
388 | case Assignment::A_EXT_FUNCTION_RVAL: | |
389 | case Assignment::A_EXT_FUNCTION_RTEMP: | |
390 | break; | |
391 | default: | |
392 | u.func.function_ref->error("Reference to a function or external " | |
393 | "function was expected instead of %s", | |
394 | t_ass->get_description().c_str()); | |
395 | return; | |
396 | } | |
397 | u.func.function_ptr = dynamic_cast<Ttcn::Def_Function_Base*>(t_ass); | |
398 | if (!u.func.function_ptr) FATAL_ERROR("TypeMappingTarget::chk_function()"); | |
399 | if (u.func.function_ptr->get_prototype() == | |
400 | Ttcn::Def_Function_Base::PROTOTYPE_NONE) { | |
401 | u.func.function_ref->error("The referenced %s does not have `prototype' " | |
402 | "attribute", u.func.function_ptr->get_description().c_str()); | |
403 | return; | |
404 | } | |
405 | Type *input_type = u.func.function_ptr->get_input_type(); | |
406 | if (input_type && !source_type->is_identical(input_type)) { | |
407 | source_type->error("The input type of %s must be the same as the source " | |
408 | "type of the mapping: `%s' was expected instead of `%s'", | |
409 | u.func.function_ptr->get_description().c_str(), | |
410 | source_type->get_typename().c_str(), | |
411 | input_type->get_typename().c_str()); | |
412 | } | |
413 | Type *output_type = u.func.function_ptr->get_output_type(); | |
414 | if (output_type && !target_type->is_identical(output_type)) { | |
415 | target_type->error("The output type of %s must be the same as the " | |
416 | "target type of the mapping: `%s' was expected instead of `%s'", | |
417 | u.func.function_ptr->get_description().c_str(), | |
418 | target_type->get_typename().c_str(), | |
419 | output_type->get_typename().c_str()); | |
420 | } | |
421 | } | |
422 | ||
423 | void TypeMappingTarget::chk_encode(Type *source_type) | |
424 | { | |
425 | Error_Context cntxt(this, "In `encode' mapping"); | |
426 | if (!source_type->has_encoding(u.encdec.coding_type)) { | |
427 | source_type->error("Source type `%s' does not support %s encoding", | |
428 | source_type->get_typename().c_str(), | |
429 | Type::get_encoding_name(u.encdec.coding_type)); | |
430 | } | |
431 | Type *stream_type = Type::get_stream_type(u.encdec.coding_type); | |
432 | if (!stream_type->is_identical(target_type)) { | |
433 | target_type->error("Target type of %s encoding should be `%s' instead " | |
434 | "of `%s'", Type::get_encoding_name(u.encdec.coding_type), | |
435 | stream_type->get_typename().c_str(), | |
436 | target_type->get_typename().c_str()); | |
437 | } | |
438 | if (u.encdec.eb_list) u.encdec.eb_list->chk(); | |
439 | } | |
440 | ||
441 | void TypeMappingTarget::chk_decode(Type *source_type) | |
442 | { | |
443 | Error_Context cntxt(this, "In `decode' mapping"); | |
444 | Type *stream_type = Type::get_stream_type(u.encdec.coding_type); | |
445 | if (!stream_type->is_identical(source_type)) { | |
446 | source_type->error("Source type of %s encoding should be `%s' instead " | |
447 | "of `%s'", Type::get_encoding_name(u.encdec.coding_type), | |
448 | stream_type->get_typename().c_str(), | |
449 | source_type->get_typename().c_str()); | |
450 | } | |
451 | if (!target_type->has_encoding(u.encdec.coding_type)) { | |
452 | target_type->error("Target type `%s' does not support %s encoding", | |
453 | target_type->get_typename().c_str(), | |
454 | Type::get_encoding_name(u.encdec.coding_type)); | |
455 | } | |
456 | if (u.encdec.eb_list) u.encdec.eb_list->chk(); | |
457 | } | |
458 | ||
459 | void TypeMappingTarget::chk(Type *source_type) | |
460 | { | |
461 | if (checked) return; | |
462 | checked = true; | |
463 | if (target_type) { | |
464 | Error_Context cntxt(target_type, "In target type"); | |
465 | target_type->chk(); | |
466 | } | |
467 | switch (mapping_type) { | |
468 | case TM_SIMPLE: | |
469 | chk_simple(source_type); | |
470 | break; | |
471 | case TM_DISCARD: | |
472 | break; | |
473 | case TM_FUNCTION: | |
474 | chk_function(source_type); | |
475 | break; | |
476 | case TM_ENCODE: | |
477 | chk_encode(source_type); | |
478 | break; | |
479 | case TM_DECODE: | |
480 | chk_decode(source_type); | |
481 | break; | |
482 | default: | |
483 | FATAL_ERROR("TypeMappingTarget::chk()"); | |
484 | } | |
485 | } | |
486 | ||
487 | bool TypeMappingTarget::fill_type_mapping_target( | |
488 | port_msg_type_mapping_target *target, Type *source_type, | |
489 | Scope *p_scope, stringpool& pool) | |
490 | { | |
491 | bool has_sliding = false; | |
492 | if (target_type) { | |
493 | target->target_name = pool.add(target_type->get_genname_value(p_scope)); | |
494 | target->target_dispname = pool.add(target_type->get_typename()); | |
495 | } else { | |
496 | target->target_name = NULL; | |
497 | target->target_dispname = NULL; | |
498 | } | |
499 | switch (mapping_type) { | |
500 | case TM_SIMPLE: | |
501 | target->mapping_type = M_SIMPLE; | |
502 | break; | |
503 | case TM_DISCARD: | |
504 | target->mapping_type = M_DISCARD; | |
505 | break; | |
506 | case TM_FUNCTION: | |
507 | target->mapping_type = M_FUNCTION; | |
508 | if (!u.func.function_ptr) | |
509 | FATAL_ERROR("TypeMappingTarget::fill_type_mapping_target()"); | |
510 | target->mapping.function.name = | |
511 | pool.add(u.func.function_ptr->get_genname_from_scope(p_scope)); | |
512 | switch (u.func.function_ptr->get_prototype()) { | |
513 | case Ttcn::Def_Function_Base::PROTOTYPE_CONVERT: | |
514 | target->mapping.function.prototype = PT_CONVERT; | |
515 | break; | |
516 | case Ttcn::Def_Function_Base::PROTOTYPE_FAST: | |
517 | target->mapping.function.prototype = PT_FAST; | |
518 | break; | |
519 | case Ttcn::Def_Function_Base::PROTOTYPE_BACKTRACK: | |
520 | target->mapping.function.prototype = PT_BACKTRACK; | |
521 | break; | |
522 | case Ttcn::Def_Function_Base::PROTOTYPE_SLIDING: | |
523 | target->mapping.function.prototype = PT_SLIDING; | |
524 | has_sliding = true; | |
525 | break; | |
526 | default: | |
527 | FATAL_ERROR("TypeMappingTarget::fill_type_mapping_target()"); | |
528 | } | |
529 | break; | |
530 | case TM_ENCODE: | |
531 | case TM_DECODE: | |
532 | if (mapping_type == TM_ENCODE) { | |
533 | target->mapping_type = M_ENCODE; | |
534 | target->mapping.encdec.typedescr_name = | |
535 | pool.add(source_type->get_genname_typedescriptor(p_scope)); | |
536 | } else { | |
537 | target->mapping_type = M_DECODE; | |
538 | target->mapping.encdec.typedescr_name = | |
539 | pool.add(target_type->get_genname_typedescriptor(p_scope)); | |
540 | } | |
541 | target->mapping.encdec.encoding_type = | |
542 | Type::get_encoding_name(u.encdec.coding_type); | |
543 | if (u.encdec.coding_options) target->mapping.encdec.encoding_options = | |
544 | u.encdec.coding_options->c_str(); | |
545 | else target->mapping.encdec.encoding_options = NULL; | |
546 | if (u.encdec.eb_list) { | |
547 | char *str = u.encdec.eb_list->generate_code(memptystr()); | |
548 | target->mapping.encdec.errorbehavior = pool.add(string(str)); | |
549 | Free(str); | |
550 | } else { | |
551 | target->mapping.encdec.errorbehavior = | |
552 | "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " | |
553 | "TTCN_EncDec::EB_DEFAULT);\n"; | |
554 | } | |
555 | break; | |
556 | default: | |
557 | FATAL_ERROR("TypeMappingTarget::fill_type_mapping_target()"); | |
558 | } | |
559 | return has_sliding; | |
560 | } | |
561 | ||
562 | void TypeMappingTarget::dump(unsigned level) const | |
563 | { | |
564 | DEBUG(level, "target:"); | |
565 | if (target_type) target_type->dump(level + 1); | |
566 | else DEBUG(level + 1, "<none>"); | |
567 | DEBUG(level, "mapping type: %s", get_mapping_name()); | |
568 | switch (mapping_type) { | |
569 | case TM_FUNCTION: | |
570 | u.func.function_ref->dump(level + 1); | |
571 | break; | |
572 | case TM_ENCODE: | |
573 | case TM_DECODE: | |
574 | DEBUG(level + 1, "encoding: %s", | |
575 | Type::get_encoding_name(u.encdec.coding_type)); | |
576 | if (u.encdec.coding_options) | |
577 | DEBUG(level + 1, "options: %s", u.encdec.coding_options->c_str()); | |
578 | if (u.encdec.eb_list) u.encdec.eb_list->dump(level + 1); | |
579 | default: | |
580 | break; | |
581 | } | |
582 | } | |
583 | ||
584 | // ================================= | |
585 | // ===== TypeMappingTargets | |
586 | // ================================= | |
587 | ||
588 | TypeMappingTargets::~TypeMappingTargets() | |
589 | { | |
590 | size_t nof_targets = targets_v.size(); | |
591 | for (size_t i = 0; i < nof_targets; i++) delete targets_v[i]; | |
592 | targets_v.clear(); | |
593 | } | |
594 | ||
595 | TypeMappingTargets *TypeMappingTargets::clone() const | |
596 | { | |
597 | FATAL_ERROR("TypeMappingTargets::clone"); | |
598 | } | |
599 | ||
600 | void TypeMappingTargets::set_fullname(const string& p_fullname) | |
601 | { | |
602 | Node::set_fullname(p_fullname); | |
603 | size_t nof_targets = targets_v.size(); | |
604 | for (size_t i = 0; i < nof_targets; i++) { | |
605 | targets_v[i]->set_fullname(p_fullname + ".<target" + Int2string(i + 1) | |
606 | + ">"); | |
607 | } | |
608 | } | |
609 | ||
610 | void TypeMappingTargets::set_my_scope(Scope *p_scope) | |
611 | { | |
612 | size_t nof_targets = targets_v.size(); | |
613 | for (size_t i = 0; i < nof_targets; i++) | |
614 | targets_v[i]->set_my_scope(p_scope); | |
615 | } | |
616 | ||
617 | void TypeMappingTargets::add_target(TypeMappingTarget *p_target) | |
618 | { | |
619 | if (!p_target) FATAL_ERROR("TypeMappingTargets::add_target()"); | |
620 | targets_v.add(p_target); | |
621 | } | |
622 | ||
623 | void TypeMappingTargets::dump(unsigned level) const | |
624 | { | |
625 | size_t nof_targets = targets_v.size(); | |
626 | DEBUG(level, "Targets: (%lu pcs.)", (unsigned long) nof_targets); | |
627 | for (size_t i = 0; i < nof_targets; i++) targets_v[i]->dump(level + 1); | |
628 | } | |
629 | ||
630 | // ================================= | |
631 | // ===== TypeMapping | |
632 | // ================================= | |
633 | ||
634 | TypeMapping::TypeMapping(Type *p_source_type, TypeMappingTargets *p_targets) | |
635 | : Node(), Location(), source_type(p_source_type), targets(p_targets) | |
636 | { | |
637 | if (!p_source_type || !p_targets) | |
638 | FATAL_ERROR("TypeMapping::TypeMapping()"); | |
639 | source_type->set_ownertype(Type::OT_TYPE_MAP, this); | |
640 | } | |
641 | ||
642 | TypeMapping::~TypeMapping() | |
643 | { | |
644 | delete source_type; | |
645 | delete targets; | |
646 | } | |
647 | ||
648 | TypeMapping *TypeMapping::clone() const | |
649 | { | |
650 | FATAL_ERROR("TypeMapping::clone"); | |
651 | } | |
652 | ||
653 | void TypeMapping::set_fullname(const string& p_fullname) | |
654 | { | |
655 | Node::set_fullname(p_fullname); | |
656 | source_type->set_fullname(p_fullname + ".<source_type>"); | |
657 | targets->set_fullname(p_fullname); | |
658 | } | |
659 | ||
660 | void TypeMapping::set_my_scope(Scope *p_scope) | |
661 | { | |
662 | source_type->set_my_scope(p_scope); | |
663 | targets->set_my_scope(p_scope); | |
664 | } | |
665 | ||
666 | void TypeMapping::chk() | |
667 | { | |
668 | Error_Context cntxt(this, "In type mapping"); | |
669 | { | |
670 | Error_Context cntxt2(source_type, "In source type"); | |
671 | source_type->chk(); | |
672 | } | |
673 | size_t nof_targets = targets->get_nof_targets(); | |
674 | bool has_sliding = false, has_non_sliding = false; | |
675 | for (size_t i = 0; i < nof_targets; i++) { | |
676 | TypeMappingTarget *target = targets->get_target_byIndex(i); | |
677 | target->chk(source_type); | |
678 | if (nof_targets > 1) { | |
679 | switch (target->get_mapping_type()) { | |
680 | case TypeMappingTarget::TM_DISCARD: | |
681 | if (has_sliding) target->error("Mapping `discard' cannot be used " | |
682 | "if functions with `prototype(sliding)' are referred from the same " | |
683 | "source type"); | |
684 | else if (i < nof_targets - 1) target->error("Mapping `discard' must " | |
685 | "be the last target of the source type"); | |
686 | break; | |
687 | case TypeMappingTarget::TM_FUNCTION: { | |
688 | Ttcn::Def_Function_Base *t_function = target->get_function(); | |
689 | if (t_function) { | |
690 | switch (t_function->get_prototype()) { | |
691 | case Ttcn::Def_Function_Base::PROTOTYPE_NONE: | |
692 | break; | |
693 | case Ttcn::Def_Function_Base::PROTOTYPE_BACKTRACK: | |
694 | has_non_sliding = true; | |
695 | break; | |
696 | case Ttcn::Def_Function_Base::PROTOTYPE_SLIDING: | |
697 | has_sliding = true; | |
698 | break; | |
699 | default: | |
700 | target->error("The referenced %s must have the attribute " | |
701 | "`prototype(backtrack)' or `prototype(sliding)' when more " | |
702 | "than one targets are present", | |
703 | t_function->get_description().c_str()); | |
704 | } | |
705 | } | |
706 | break; } | |
707 | case TypeMappingTarget::TM_DECODE: | |
708 | break; | |
709 | default: | |
710 | target->error("The type of the mapping must be `function', `decode' " | |
711 | "or `discard' instead of `%s' when more than one targets are " | |
712 | "present", target->get_mapping_name()); | |
713 | } | |
714 | } | |
715 | } | |
716 | if (has_sliding && has_non_sliding) { | |
717 | error("If one of the mappings refers to a function with attribute " | |
718 | "`prototype(sliding)' then mappings of this source type cannot refer " | |
719 | "to functions with attribute `prototype(backtrack)'"); | |
720 | } | |
721 | } | |
722 | ||
723 | void TypeMapping::dump(unsigned level) const | |
724 | { | |
725 | DEBUG(level, "Source type:"); | |
726 | source_type->dump(level + 1); | |
727 | targets->dump(level); | |
728 | } | |
729 | ||
730 | // ================================= | |
731 | // ===== TypeMappings | |
732 | // ================================= | |
733 | ||
734 | TypeMappings::~TypeMappings() | |
735 | { | |
736 | size_t nof_mappings = mappings_v.size(); | |
737 | for (size_t i = 0; i < nof_mappings; i++) delete mappings_v[i]; | |
738 | mappings_v.clear(); | |
739 | mappings_m.clear(); | |
740 | } | |
741 | ||
742 | TypeMappings *TypeMappings::clone() const | |
743 | { | |
744 | FATAL_ERROR("TypeMappings::clone"); | |
745 | } | |
746 | ||
747 | void TypeMappings::set_fullname(const string& p_fullname) | |
748 | { | |
749 | Node::set_fullname(p_fullname); | |
750 | size_t nof_mappings = mappings_v.size(); | |
751 | for (size_t i = 0; i < nof_mappings; i++) { | |
752 | mappings_v[i]->set_fullname(p_fullname + ".<mapping" + Int2string(i + 1) | |
753 | + ">"); | |
754 | } | |
755 | } | |
756 | ||
757 | void TypeMappings::set_my_scope(Scope *p_scope) | |
758 | { | |
759 | size_t nof_mappings = mappings_v.size(); | |
760 | for (size_t i = 0; i < nof_mappings; i++) | |
761 | mappings_v[i]->set_my_scope(p_scope); | |
762 | } | |
763 | ||
764 | void TypeMappings::add_mapping(TypeMapping *p_mapping) | |
765 | { | |
766 | if (checked || !p_mapping) FATAL_ERROR("TypeMappings::add_mapping()"); | |
767 | mappings_v.add(p_mapping); | |
768 | } | |
769 | ||
770 | void TypeMappings::steal_mappings(TypeMappings *p_mappings) | |
771 | { | |
772 | if (checked || !p_mappings || p_mappings->checked) | |
773 | FATAL_ERROR("TypeMappings::steal_mappings()"); | |
774 | size_t nof_mappings = p_mappings->mappings_v.size(); | |
775 | for (size_t i = 0; i < nof_mappings; i++) | |
776 | mappings_v.add(p_mappings->mappings_v[i]); | |
777 | p_mappings->mappings_v.clear(); | |
778 | join_location(*p_mappings); | |
779 | } | |
780 | ||
781 | bool TypeMappings::has_mapping_for_type(Type *p_type) const | |
782 | { | |
783 | if (!checked || !p_type) | |
784 | FATAL_ERROR("TypeMappings::has_mapping_for_type()"); | |
785 | if (p_type->get_type_refd_last()->get_typetype() == Type::T_ERROR) | |
786 | return true; | |
787 | else return mappings_m.has_key(p_type->get_typename()); | |
788 | } | |
789 | ||
790 | TypeMapping *TypeMappings::get_mapping_byType(Type *p_type) const | |
791 | { | |
792 | if (!checked || !p_type) | |
793 | FATAL_ERROR("TypeMappings::get_mapping_byType()"); | |
794 | return mappings_m[p_type->get_typename()]; | |
795 | } | |
796 | ||
797 | void TypeMappings::chk() | |
798 | { | |
799 | if (checked) return; | |
800 | checked = true; | |
801 | size_t nof_mappings = mappings_v.size(); | |
802 | for (size_t i = 0; i < nof_mappings; i++) { | |
803 | TypeMapping *mapping = mappings_v[i]; | |
804 | mapping->chk(); | |
805 | Type *source_type = mapping->get_source_type(); | |
806 | if (source_type->get_type_refd_last()->get_typetype() != Type::T_ERROR) { | |
807 | const string& source_type_name = source_type->get_typename(); | |
808 | if (mappings_m.has_key(source_type_name)) { | |
809 | const char *source_type_name_str = source_type_name.c_str(); | |
810 | source_type->error("Duplicate mapping for type `%s'", | |
811 | source_type_name_str); | |
812 | mappings_m[source_type_name]->note("The mapping of type `%s' is " | |
813 | "already given here", source_type_name_str); | |
814 | } else mappings_m.add(source_type_name, mapping); | |
815 | } | |
816 | } | |
817 | } | |
818 | ||
819 | void TypeMappings::dump(unsigned level) const | |
820 | { | |
821 | size_t nof_mappings = mappings_v.size(); | |
822 | DEBUG(level, "type mappings: (%lu pcs.)", (unsigned long) nof_mappings); | |
823 | for (size_t i = 0; i < nof_mappings; i++) | |
824 | mappings_v[i]->dump(level + 1); | |
825 | } | |
826 | ||
827 | // ================================= | |
828 | // ===== Types | |
829 | // ================================= | |
830 | ||
831 | Types::~Types() | |
832 | { | |
833 | size_t nof_types = types.size(); | |
834 | for (size_t i = 0; i < nof_types; i++) delete types[i]; | |
835 | types.clear(); | |
836 | } | |
837 | ||
838 | Types *Types::clone() const | |
839 | { | |
840 | FATAL_ERROR("Types::clone"); | |
841 | } | |
842 | ||
843 | void Types::add_type(Type *p_type) | |
844 | { | |
845 | if (!p_type) FATAL_ERROR("Types::add_type()"); | |
846 | p_type->set_ownertype(Type::OT_TYPE_LIST, this); | |
847 | types.add(p_type); | |
848 | } | |
849 | ||
850 | Type *Types::extract_type_byIndex(size_t n) | |
851 | { | |
852 | Type *retval = types[n]; | |
853 | types[n] = 0; | |
854 | return retval; | |
855 | } | |
856 | ||
857 | void Types::steal_types(Types *p_tl) | |
858 | { | |
859 | if (!p_tl) FATAL_ERROR("Types::steal_types()"); | |
860 | size_t nof_types = p_tl->types.size(); | |
861 | for (size_t i = 0; i < nof_types; i++) types.add(p_tl->types[i]); | |
862 | p_tl->types.clear(); | |
863 | join_location(*p_tl); | |
864 | } | |
865 | ||
866 | void Types::set_fullname(const string& p_fullname) | |
867 | { | |
868 | Node::set_fullname(p_fullname); | |
869 | size_t nof_types = types.size(); | |
870 | for (size_t i = 0; i < nof_types; i++) | |
871 | types[i]->set_fullname(p_fullname + ".<type" + Int2string(i + 1) + ">"); | |
872 | } | |
873 | ||
874 | void Types::set_my_scope(Scope *p_scope) | |
875 | { | |
876 | size_t nof_types = types.size(); | |
877 | for (size_t i = 0; i < nof_types; i++) types[i]->set_my_scope(p_scope); | |
878 | } | |
879 | ||
880 | void Types::dump(unsigned level) const | |
881 | { | |
882 | size_t nof_types = types.size(); | |
883 | DEBUG(level, "Types: (%lu pcs.)", (unsigned long) nof_types); | |
884 | for (size_t i = 0; i < nof_types; i++) types[i]->dump(level + 1); | |
885 | } | |
886 | ||
887 | // ================================= | |
888 | // ===== TypeSet | |
889 | // ================================= | |
890 | ||
891 | TypeSet::~TypeSet() | |
892 | { | |
893 | types_v.clear(); | |
894 | types_m.clear(); | |
895 | } | |
896 | ||
897 | TypeSet *TypeSet::clone() const | |
898 | { | |
899 | FATAL_ERROR("TypeSet::clone()"); | |
900 | } | |
901 | ||
902 | void TypeSet::add_type(Type *p_type) | |
903 | { | |
904 | if (!p_type) FATAL_ERROR("TypeSet::add_type()"); | |
905 | types_v.add(p_type); | |
906 | types_m.add(p_type->get_typename(), p_type); | |
907 | } | |
908 | ||
909 | bool TypeSet::has_type(Type *p_type) const | |
910 | { | |
911 | if (!p_type) FATAL_ERROR("TypeSet::has_type()"); | |
912 | if (p_type->get_type_refd_last()->get_typetype() == Type::T_ERROR) | |
913 | return true; | |
914 | else return types_m.has_key(p_type->get_typename()); | |
915 | } | |
916 | ||
917 | size_t TypeSet::get_nof_compatible_types(Type *p_type) const | |
918 | { | |
919 | if (!p_type) FATAL_ERROR("TypeSet::get_nof_compatible_types()"); | |
920 | if (p_type->get_type_refd_last()->get_typetype() == Type::T_ERROR) { | |
921 | // Return a positive answer for erroneous types. | |
922 | return 1; | |
923 | } else { | |
924 | size_t ret_val = 0; | |
925 | size_t nof_types = types_v.size(); | |
926 | for (size_t i = 0; i < nof_types; i++) { | |
927 | // Don't allow type compatibility. | |
928 | if (types_v[i]->is_compatible(p_type, NULL)) ret_val++; | |
929 | } | |
930 | return ret_val; | |
931 | } | |
932 | } | |
933 | ||
934 | size_t TypeSet::get_index_byType(Type *p_type) const | |
935 | { | |
936 | if (!p_type) FATAL_ERROR("TypeSet::get_index_byType()"); | |
937 | const string& name = p_type->get_typename(); | |
938 | size_t nof_types = types_v.size(); | |
939 | for (size_t i = 0; i < nof_types; i++) | |
940 | if (types_v[i]->get_typename() == name) return i; | |
941 | FATAL_ERROR("TypeSet::get_index_byType()"); | |
942 | return static_cast<size_t>(-1); | |
943 | } | |
944 | ||
945 | void TypeSet::dump(unsigned level) const | |
946 | { | |
947 | size_t nof_types = types_v.size(); | |
948 | DEBUG(level, "Types: (%lu pcs.)", (unsigned long) nof_types); | |
949 | for (size_t i = 0; i < nof_types; i++) types_v[i]->dump(level + 1); | |
950 | } | |
951 | ||
952 | // ================================= | |
953 | // ===== PortTypeBody | |
954 | // ================================= | |
955 | ||
956 | PortTypeBody::PortTypeBody(PortOperationMode_t p_operation_mode, | |
957 | Types *p_in_list, Types *p_out_list, Types *p_inout_list, | |
958 | bool p_in_all, bool p_out_all, bool p_inout_all) | |
959 | : Node(), Location(), my_type(0), operation_mode(p_operation_mode), | |
960 | in_list(p_in_list), out_list(p_out_list), inout_list(p_inout_list), | |
961 | in_all(p_in_all), out_all(p_out_all), inout_all(p_inout_all), | |
962 | checked(false), | |
963 | in_msgs(0), out_msgs(0), in_sigs(0), out_sigs(0), | |
964 | testport_type(TP_REGULAR), port_type(PT_REGULAR), | |
965 | provider_ref(0), provider_type(0), in_mappings(0), out_mappings(0) | |
966 | { | |
967 | } | |
968 | ||
969 | PortTypeBody::~PortTypeBody() | |
970 | { | |
971 | delete in_list; | |
972 | delete out_list; | |
973 | delete inout_list; | |
974 | delete in_msgs; | |
975 | delete out_msgs; | |
976 | delete in_sigs; | |
977 | delete out_sigs; | |
978 | delete provider_ref; | |
979 | delete in_mappings; | |
980 | delete out_mappings; | |
981 | } | |
982 | ||
983 | PortTypeBody *PortTypeBody::clone() const | |
984 | { | |
985 | FATAL_ERROR("PortTypeBody::clone"); | |
986 | } | |
987 | ||
988 | void PortTypeBody::set_fullname(const string& p_fullname) | |
989 | { | |
990 | Node::set_fullname(p_fullname); | |
991 | if (in_list) in_list->set_fullname(p_fullname + ".<in_list>"); | |
992 | if (out_list) out_list->set_fullname(p_fullname + ".<out_list>"); | |
993 | if (inout_list) inout_list->set_fullname(p_fullname + ".<inout_list>"); | |
994 | if (in_msgs) in_msgs->set_fullname(p_fullname + ".<incoming_messages>"); | |
995 | if (out_msgs) out_msgs->set_fullname(p_fullname + ".<outgoing_messages>"); | |
996 | if (in_sigs) in_sigs->set_fullname(p_fullname + ".<incoming_signatures>"); | |
997 | if (out_sigs) out_sigs->set_fullname(p_fullname + ".<outgoing_signatures>"); | |
998 | if (provider_ref) | |
999 | provider_ref->set_fullname(p_fullname + ".<provider_ref>"); | |
1000 | if (in_mappings) in_mappings->set_fullname(p_fullname + ".<in_mappings>"); | |
1001 | if (out_mappings) | |
1002 | out_mappings->set_fullname(p_fullname + ".<out_mappings>"); | |
1003 | } | |
1004 | ||
1005 | void PortTypeBody::set_my_scope(Scope *p_scope) | |
1006 | { | |
1007 | if (in_list) in_list->set_my_scope(p_scope); | |
1008 | if (out_list) out_list->set_my_scope(p_scope); | |
1009 | if (inout_list) inout_list->set_my_scope(p_scope); | |
1010 | if (provider_ref) provider_ref->set_my_scope(p_scope); | |
1011 | if (in_mappings) in_mappings->set_my_scope(p_scope); | |
1012 | if (out_mappings) out_mappings->set_my_scope(p_scope); | |
1013 | } | |
1014 | ||
1015 | void PortTypeBody::set_my_type(Type *p_type) | |
1016 | { | |
1017 | if (!p_type || p_type->get_typetype() != Type::T_PORT) | |
1018 | FATAL_ERROR("PortTypeBody::set_my_type()"); | |
1019 | my_type = p_type; | |
1020 | } | |
1021 | ||
1022 | TypeSet *PortTypeBody::get_in_msgs() const | |
1023 | { | |
1024 | if (!checked) FATAL_ERROR("PortTypeBody::get_in_msgs()"); | |
1025 | return in_msgs; | |
1026 | } | |
1027 | ||
1028 | TypeSet *PortTypeBody::get_out_msgs() const | |
1029 | { | |
1030 | if (!checked) FATAL_ERROR("PortTypeBody::get_out_msgs()"); | |
1031 | return out_msgs; | |
1032 | } | |
1033 | ||
1034 | TypeSet *PortTypeBody::get_in_sigs() const | |
1035 | { | |
1036 | if (!checked) FATAL_ERROR("PortTypeBody::get_in_sigs()"); | |
1037 | return in_sigs; | |
1038 | } | |
1039 | ||
1040 | TypeSet *PortTypeBody::get_out_sigs() const | |
1041 | { | |
1042 | if (!checked) FATAL_ERROR("PortTypeBody::get_out_sigs()"); | |
1043 | return out_sigs; | |
1044 | } | |
1045 | ||
1046 | bool PortTypeBody::has_queue() const | |
1047 | { | |
1048 | if (!checked) FATAL_ERROR("PortTypeBody::has_queue()"); | |
1049 | if (in_msgs || in_sigs) return true; | |
1050 | if (out_sigs) { | |
1051 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1052 | for (size_t i = 0; i < nof_sigs; i++) { | |
1053 | Type *t_sig = out_sigs->get_type_byIndex(i)->get_type_refd_last(); | |
1054 | if (!t_sig->is_nonblocking_signature() || | |
1055 | t_sig->get_signature_exceptions()) return true; | |
1056 | } | |
1057 | } | |
1058 | return false; | |
1059 | } | |
1060 | ||
1061 | bool PortTypeBody::getreply_allowed() const | |
1062 | { | |
1063 | if (!checked) FATAL_ERROR("PortTypeBody::getreply_allowed()"); | |
1064 | if (out_sigs) { | |
1065 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1066 | for (size_t i = 0; i < nof_sigs; i++) { | |
1067 | if (!out_sigs->get_type_byIndex(i)->get_type_refd_last() | |
1068 | ->is_nonblocking_signature()) return true; | |
1069 | } | |
1070 | } | |
1071 | return false; | |
1072 | } | |
1073 | ||
1074 | bool PortTypeBody::catch_allowed() const | |
1075 | { | |
1076 | if (!checked) FATAL_ERROR("PortTypeBody::catch_allowed()"); | |
1077 | if (out_sigs) { | |
1078 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1079 | for (size_t i = 0; i < nof_sigs; i++) { | |
1080 | if (out_sigs->get_type_byIndex(i)->get_type_refd_last() | |
1081 | ->get_signature_exceptions()) return true; | |
1082 | } | |
1083 | } | |
1084 | return false; | |
1085 | } | |
1086 | ||
1087 | bool PortTypeBody::is_internal() const | |
1088 | { | |
1089 | if (!checked) FATAL_ERROR("PortTypeBody::is_internal_port()"); | |
1090 | return testport_type == TP_INTERNAL; | |
1091 | } | |
1092 | ||
1093 | Type *PortTypeBody::get_address_type() | |
1094 | { | |
1095 | if (!checked) FATAL_ERROR("PortTypeBody::get_address_type()"); | |
1096 | if (testport_type == TP_ADDRESS) { | |
1097 | Type *t; | |
1098 | // in case of 'user' port types the address visible and supported by the | |
1099 | // 'provider' port type is relevant | |
1100 | if (port_type == PT_USER && provider_type) t = provider_type; | |
1101 | else t = my_type; | |
1102 | return t->get_my_scope()->get_scope_mod()->get_address_type(); | |
1103 | } else { | |
1104 | // the port type does not support SUT addresses | |
1105 | return 0; | |
1106 | } | |
1107 | } | |
1108 | ||
1109 | void PortTypeBody::add_provider_attribute() | |
1110 | { | |
1111 | port_type = PT_PROVIDER; | |
1112 | delete provider_ref; | |
1113 | provider_ref = 0; | |
1114 | provider_type = 0; | |
1115 | delete in_mappings; | |
1116 | in_mappings = 0; | |
1117 | delete out_mappings; | |
1118 | out_mappings = 0; | |
1119 | } | |
1120 | ||
1121 | void PortTypeBody::add_user_attribute(Ttcn::Reference *p_provider_ref, | |
1122 | TypeMappings *p_in_mappings, TypeMappings *p_out_mappings) | |
1123 | { | |
1124 | if (!p_provider_ref || !my_type) | |
1125 | FATAL_ERROR("PortTypeBody::add_user_attribute()"); | |
1126 | Scope *t_scope = my_type->get_my_scope(); | |
1127 | const string& t_fullname = get_fullname(); | |
1128 | port_type = PT_USER; | |
1129 | delete provider_ref; | |
1130 | provider_ref = p_provider_ref; | |
1131 | provider_ref->set_fullname(t_fullname + ".<provider_ref>"); | |
1132 | provider_ref->set_my_scope(t_scope); | |
1133 | provider_type = 0; | |
1134 | delete in_mappings; | |
1135 | in_mappings = p_in_mappings; | |
1136 | if (in_mappings) { | |
1137 | in_mappings->set_fullname(t_fullname + ".<in_mappings>"); | |
1138 | in_mappings->set_my_scope(t_scope); | |
1139 | } | |
1140 | delete out_mappings; | |
1141 | out_mappings = p_out_mappings; | |
1142 | if (out_mappings) { | |
1143 | out_mappings->set_fullname(t_fullname + ".<out_mappings>"); | |
1144 | out_mappings->set_my_scope(t_scope); | |
1145 | } | |
1146 | } | |
1147 | ||
1148 | Type *PortTypeBody::get_provider_type() const | |
1149 | { | |
1150 | if (!checked || port_type != PT_USER) | |
1151 | FATAL_ERROR("PortTypeBody::get_provider_type()"); | |
1152 | return provider_type; | |
1153 | } | |
1154 | ||
1155 | void PortTypeBody::chk_list(const Types *list, bool is_in, bool is_out) | |
1156 | { | |
1157 | const char *err_msg; | |
1158 | if (is_in) { | |
1159 | if (is_out) err_msg = "sent or received"; | |
1160 | else err_msg = "received"; | |
1161 | } else if (is_out) err_msg = "sent"; | |
1162 | else { | |
1163 | FATAL_ERROR("PortTypeBody::chk_list()"); | |
1164 | err_msg = 0; | |
1165 | } | |
1166 | size_t nof_types = list->get_nof_types(); | |
1167 | for (size_t i = 0; i < nof_types; i++) { | |
1168 | Type *t = list->get_type_byIndex(i); | |
1169 | t->chk(); | |
1170 | // check if a value/template of this type can leave the component | |
1171 | if (t->is_component_internal()) { | |
1172 | map<Type*,void> type_chain; | |
1173 | t->chk_component_internal(type_chain, "sent or received on a port"); | |
1174 | } | |
1175 | Type *t_last = t->get_type_refd_last(); | |
1176 | switch (t_last->get_typetype()) { | |
1177 | case Type::T_ERROR: | |
1178 | // silently ignore | |
1179 | break; | |
1180 | case Type::T_SIGNATURE: | |
1181 | if (operation_mode == PO_MESSAGE) { | |
1182 | t->error("Signature `%s' cannot be used on a message based port", | |
1183 | t_last->get_typename().c_str()); | |
1184 | } | |
1185 | if (is_in) { | |
1186 | if (in_sigs && in_sigs->has_type(t_last)) { | |
1187 | const string& type_name = t_last->get_typename(); | |
1188 | t->error("Duplicate incoming signature `%s'", type_name.c_str()); | |
1189 | in_sigs->get_type_byName(type_name)->note("Signature `%s' is " | |
1190 | "already listed here", type_name.c_str()); | |
1191 | } else { | |
1192 | if (!in_sigs) { | |
1193 | in_sigs = new TypeSet; | |
1194 | in_sigs->set_fullname(get_fullname() + ".<incoming_signatures>"); | |
1195 | } | |
1196 | in_sigs->add_type(t); | |
1197 | } | |
1198 | } | |
1199 | if (is_out) { | |
1200 | if (out_sigs && out_sigs->has_type(t_last)) { | |
1201 | const string& type_name = t_last->get_typename(); | |
1202 | t->error("Duplicate outgoing signature `%s'", type_name.c_str()); | |
1203 | out_sigs->get_type_byName(type_name)->note("Signature `%s' is " | |
1204 | "already listed here", type_name.c_str()); | |
1205 | } else { | |
1206 | if (!out_sigs) { | |
1207 | out_sigs = new TypeSet; | |
1208 | out_sigs->set_fullname(get_fullname() + ".<outgoing_signatures>"); | |
1209 | } | |
1210 | out_sigs->add_type(t); | |
1211 | } | |
1212 | } | |
1213 | break; | |
1214 | default: | |
1215 | // t is a normal data type | |
1216 | if (operation_mode == PO_PROCEDURE) { | |
1217 | t->error("Data type `%s' cannot be %s on a procedure based port", | |
1218 | t_last->get_typename().c_str(), err_msg); | |
1219 | } | |
1220 | if (is_in) { | |
1221 | if (in_msgs && in_msgs->has_type(t_last)) { | |
1222 | const string& type_name = t_last->get_typename(); | |
1223 | t->error("Duplicate incoming message type `%s'", type_name.c_str()); | |
1224 | in_msgs->get_type_byName(type_name)->note("Type `%s' is already " | |
1225 | "listed here", type_name.c_str()); | |
1226 | } else { | |
1227 | if (!in_msgs) { | |
1228 | in_msgs = new TypeSet; | |
1229 | in_msgs->set_fullname(get_fullname() + ".<incoming_messages>"); | |
1230 | } | |
1231 | in_msgs->add_type(t); | |
1232 | } | |
1233 | } | |
1234 | if (is_out) { | |
1235 | if (out_msgs && out_msgs->has_type(t_last)) { | |
1236 | const string& type_name = t_last->get_typename(); | |
1237 | t->error("Duplicate outgoing message type `%s'", type_name.c_str()); | |
1238 | out_msgs->get_type_byName(type_name)->note("Type `%s' is already " | |
1239 | "listed here", type_name.c_str()); | |
1240 | } else { | |
1241 | if (!out_msgs) { | |
1242 | out_msgs = new TypeSet; | |
1243 | out_msgs->set_fullname(get_fullname() + ".<outgoing_messages>"); | |
1244 | } | |
1245 | out_msgs->add_type(t); | |
1246 | } | |
1247 | } | |
1248 | } | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | void PortTypeBody::chk_user_attribute() | |
1253 | { | |
1254 | Error_Context cntxt(this, "In extension attribute `user'"); | |
1255 | // check the reference that points to the provider type | |
1256 | provider_type = 0; | |
1257 | PortTypeBody *provider_body = 0; | |
1258 | Assignment *t_ass = provider_ref->get_refd_assignment(); // provider port | |
1259 | if (t_ass) { | |
1260 | if (t_ass->get_asstype() == Assignment::A_TYPE) { | |
1261 | Type *t = t_ass->get_Type()->get_type_refd_last(); | |
1262 | if (t->get_typetype() == Type::T_PORT) { | |
1263 | provider_type = t; | |
1264 | provider_body = t->get_PortBody(); | |
1265 | } else { | |
1266 | provider_ref->error("Type reference `%s' does not refer to a port " | |
1267 | "type", provider_ref->get_dispname().c_str()); | |
1268 | } | |
1269 | } else { | |
1270 | provider_ref->error("Reference `%s' does not refer to a type", | |
1271 | provider_ref->get_dispname().c_str()); | |
1272 | } | |
1273 | } | |
1274 | ||
1275 | // checking the consistency of attributes in this and provider_body | |
1276 | if (provider_body && testport_type != TP_INTERNAL) { | |
1277 | if (provider_body->port_type != PT_PROVIDER) { | |
1278 | provider_ref->error("The referenced port type `%s' must have the " | |
1279 | "`provider' attribute", provider_type->get_typename().c_str()); | |
1280 | } | |
1281 | switch (provider_body->testport_type) { | |
1282 | case TP_REGULAR: | |
1283 | if (testport_type == TP_ADDRESS) { | |
1284 | provider_ref->error("Attribute `address' cannot be used because the " | |
1285 | "provider port type `%s' does not have attribute `address'", | |
1286 | provider_type->get_typename().c_str()); | |
1287 | } | |
1288 | break; | |
1289 | case TP_INTERNAL: | |
1290 | provider_ref->error("Missing attribute `internal'. Provider port " | |
1291 | "type `%s' has attribute `internal', which must be also present here", | |
1292 | provider_type->get_typename().c_str()); | |
1293 | case TP_ADDRESS: | |
1294 | break; | |
1295 | default: | |
1296 | FATAL_ERROR("PortTypeBody::chk_attributes()"); | |
1297 | } | |
1298 | // inherit the test port API type from the provider | |
1299 | testport_type = provider_body->testport_type; | |
1300 | } | |
1301 | ||
1302 | // checking the incoming mappings | |
1303 | if (in_mappings) { | |
1304 | Error_Context cntxt2(in_mappings, "In `in' mappings"); | |
1305 | in_mappings->chk(); | |
1306 | // checking source types | |
1307 | if (provider_body) { | |
1308 | if (provider_body->in_msgs) { | |
1309 | // check if all source types are present on the `in' list of the | |
1310 | // provider | |
1311 | size_t nof_mappings = in_mappings->get_nof_mappings(); | |
1312 | for (size_t i = 0; i < nof_mappings; i++) { | |
1313 | Type *source_type = | |
1314 | in_mappings->get_mapping_byIndex(i)->get_source_type(); | |
1315 | if (!provider_body->in_msgs->has_type(source_type)) { | |
1316 | source_type->error("Source type `%s' of the `in' mapping is not " | |
1317 | "present on the list of incoming messages in provider port " | |
1318 | "type `%s'", source_type->get_typename().c_str(), | |
1319 | provider_type->get_typename().c_str()); | |
1320 | } | |
1321 | } | |
1322 | // check if all types of the `in' list of the provider are handled by | |
1323 | // the mappings | |
1324 | size_t nof_msgs = provider_body->in_msgs->get_nof_types(); | |
1325 | for (size_t i = 0; i < nof_msgs; i++) { | |
1326 | Type *msg_type = provider_body->in_msgs->get_type_byIndex(i); | |
1327 | if (!in_mappings->has_mapping_for_type(msg_type)) { | |
1328 | in_mappings->error("Incoming message type `%s' of provider " | |
1329 | "port type `%s' is not handled by the incoming mappings", | |
1330 | msg_type->get_typename().c_str(), | |
1331 | provider_type->get_typename().c_str()); | |
1332 | } | |
1333 | } | |
1334 | } else { | |
1335 | in_mappings->error("Invalid incoming mappings. Provider port type " | |
1336 | "`%s' does not have incoming message types", | |
1337 | provider_type->get_typename().c_str()); | |
1338 | } | |
1339 | } | |
1340 | // checking target types | |
1341 | size_t nof_mappings = in_mappings->get_nof_mappings(); | |
1342 | for (size_t i = 0; i < nof_mappings; i++) { | |
1343 | TypeMapping *mapping = in_mappings->get_mapping_byIndex(i); | |
1344 | size_t nof_targets = mapping->get_nof_targets(); | |
1345 | for (size_t j = 0; j < nof_targets; j++) { | |
1346 | Type *target_type = | |
1347 | mapping->get_target_byIndex(j)->get_target_type(); | |
1348 | if (target_type && (!in_msgs || !in_msgs->has_type(target_type))) { | |
1349 | target_type->error("Target type `%s' of the `in' mapping is not " | |
1350 | "present on the list of incoming messages in user port type " | |
1351 | "`%s'", target_type->get_typename().c_str(), | |
1352 | my_type->get_typename().c_str()); | |
1353 | } | |
1354 | } | |
1355 | } | |
1356 | } else if (provider_body && provider_body->in_msgs) { | |
1357 | error("Missing `in' mappings to handle the incoming message types of " | |
1358 | "provider port type `%s'", provider_type->get_typename().c_str()); | |
1359 | } | |
1360 | ||
1361 | // checking the outgoing mappings | |
1362 | if (out_mappings) { | |
1363 | Error_Context cntxt2(out_mappings, "In `out' mappings"); | |
1364 | out_mappings->chk(); | |
1365 | // checking source types | |
1366 | if (out_msgs) { | |
1367 | // check if all source types are present on the `out' list | |
1368 | size_t nof_mappings = out_mappings->get_nof_mappings(); | |
1369 | for (size_t i = 0; i < nof_mappings; i++) { | |
1370 | Type *source_type = | |
1371 | out_mappings->get_mapping_byIndex(i)->get_source_type(); | |
1372 | if (!out_msgs->has_type(source_type)) { | |
1373 | source_type->error("Source type `%s' of the `out' mapping is not " | |
1374 | "present on the list of outgoing messages in user port type `%s'", | |
1375 | source_type->get_typename().c_str(), | |
1376 | my_type->get_typename().c_str()); | |
1377 | } | |
1378 | } | |
1379 | // check if all types of the `out' list are handled by the mappings | |
1380 | size_t nof_msgs = out_msgs->get_nof_types(); | |
1381 | for (size_t i = 0; i < nof_msgs; i++) { | |
1382 | Type *msg_type = out_msgs->get_type_byIndex(i); | |
1383 | if (!out_mappings->has_mapping_for_type(msg_type)) { | |
1384 | out_mappings->error("Outgoing message type `%s' of user port type " | |
1385 | "`%s' is not handled by the outgoing mappings", | |
1386 | msg_type->get_typename().c_str(), | |
1387 | my_type->get_typename().c_str()); | |
1388 | } | |
1389 | } | |
1390 | } else { | |
1391 | out_mappings->error("Invalid outgoing mappings. User port type " | |
1392 | "`%s' does not have outgoing message types", | |
1393 | my_type->get_typename().c_str()); | |
1394 | } | |
1395 | // checking target types | |
1396 | if (provider_body) { | |
1397 | size_t nof_mappings = out_mappings->get_nof_mappings(); | |
1398 | for (size_t i = 0; i < nof_mappings; i++) { | |
1399 | TypeMapping *mapping = out_mappings->get_mapping_byIndex(i); | |
1400 | size_t nof_targets = mapping->get_nof_targets(); | |
1401 | for (size_t j = 0; j < nof_targets; j++) { | |
1402 | Type *target_type = | |
1403 | mapping->get_target_byIndex(j)->get_target_type(); | |
1404 | if (target_type && (!provider_body->out_msgs || | |
1405 | !provider_body->out_msgs->has_type(target_type))) { | |
1406 | target_type->error("Target type `%s' of the `out' mapping is " | |
1407 | "not present on the list of outgoing messages in provider " | |
1408 | "port type `%s'", target_type->get_typename().c_str(), | |
1409 | provider_type->get_typename().c_str()); | |
1410 | } | |
1411 | } | |
1412 | } | |
1413 | } | |
1414 | } else if (out_msgs) { | |
1415 | error("Missing `out' mappings to handle the outgoing message types of " | |
1416 | "user port type `%s'", my_type->get_typename().c_str()); | |
1417 | } | |
1418 | ||
1419 | // checking the compatibility of signature lists | |
1420 | if (provider_body) { | |
1421 | if (in_sigs) { | |
1422 | size_t nof_sigs = in_sigs->get_nof_types(); | |
1423 | for (size_t i = 0; i < nof_sigs; i++) { | |
1424 | Type *t_sig = in_sigs->get_type_byIndex(i); | |
1425 | if (!provider_body->in_sigs || | |
1426 | !provider_body->in_sigs->has_type(t_sig)) { | |
1427 | Type *t_sig_last = t_sig->get_type_refd_last(); | |
1428 | if (!t_sig_last->is_nonblocking_signature() || | |
1429 | t_sig_last->get_signature_exceptions()) | |
1430 | t_sig->error("Incoming signature `%s' of user port type `%s' is " | |
1431 | "not present on the list of incoming signatures in provider " | |
1432 | "port type `%s'", t_sig->get_typename().c_str(), | |
1433 | my_type->get_typename().c_str(), | |
1434 | provider_type->get_typename().c_str()); | |
1435 | } | |
1436 | } | |
1437 | } | |
1438 | ||
1439 | if (provider_body->in_sigs) { | |
1440 | size_t nof_sigs = provider_body->in_sigs->get_nof_types(); | |
1441 | for (size_t i = 0; i < nof_sigs; i++) { | |
1442 | Type *t_sig = provider_body->in_sigs->get_type_byIndex(i); | |
1443 | if (!in_sigs || !in_sigs->has_type(t_sig)) { | |
1444 | error("Incoming signature `%s' of provider port type `%s' is not " | |
1445 | "present on the list of incoming signatures in user port type " | |
1446 | "`%s'", t_sig->get_typename().c_str(), | |
1447 | provider_type->get_typename().c_str(), | |
1448 | my_type->get_typename().c_str()); | |
1449 | } | |
1450 | } | |
1451 | } | |
1452 | ||
1453 | if (out_sigs) { | |
1454 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1455 | for (size_t i = 0; i < nof_sigs; i++) { | |
1456 | Type *t_sig = out_sigs->get_type_byIndex(i); | |
1457 | if (!provider_body->out_sigs || | |
1458 | !provider_body->out_sigs->has_type(t_sig)) { | |
1459 | t_sig->error("Outgoing signature `%s' of user port type `%s' is " | |
1460 | "not present on the list of outgoing signatures in provider port " | |
1461 | "type `%s'", t_sig->get_typename().c_str(), | |
1462 | my_type->get_typename().c_str(), | |
1463 | provider_type->get_typename().c_str()); | |
1464 | } | |
1465 | } | |
1466 | } | |
1467 | ||
1468 | if (provider_body->out_sigs) { | |
1469 | size_t nof_sigs = provider_body->out_sigs->get_nof_types(); | |
1470 | for (size_t i = 0; i < nof_sigs; i++) { | |
1471 | Type *t_sig = provider_body->out_sigs->get_type_byIndex(i); | |
1472 | if (!out_sigs || !out_sigs->has_type(t_sig)) { | |
1473 | Type *t_sig_last = t_sig->get_type_refd_last(); | |
1474 | if (!t_sig_last->is_nonblocking_signature() || | |
1475 | t_sig_last->get_signature_exceptions()) | |
1476 | error("Outgoing signature `%s' of provider port type `%s' is not " | |
1477 | "present on the list of outgoing signatures in user port type " | |
1478 | "`%s'", t_sig->get_typename().c_str(), | |
1479 | provider_type->get_typename().c_str(), | |
1480 | my_type->get_typename().c_str()); | |
1481 | } | |
1482 | } | |
1483 | } | |
1484 | } | |
1485 | } | |
1486 | ||
1487 | void PortTypeBody::chk() | |
1488 | { | |
1489 | if (checked) return; | |
1490 | checked = true; | |
1491 | ||
1492 | // checking 'all' directives | |
1493 | if (inout_all) { | |
1494 | if (in_all) { | |
1495 | warning("Redundant `in all' and `inout all' directives"); | |
1496 | in_all = false; | |
1497 | } | |
1498 | if (out_all) { | |
1499 | warning("Redundant `out all' and `inout all' directives"); | |
1500 | out_all = false; | |
1501 | } | |
1502 | warning("Unsupported `inout all' directive was ignored"); | |
1503 | } else { | |
1504 | if (in_all) warning("Unsupported `in all' directive was ignored"); | |
1505 | if (out_all) warning("Unsupported `out all' directive was ignored"); | |
1506 | } | |
1507 | ||
1508 | // checking message/signature lists | |
1509 | if (in_list) { | |
1510 | Error_Context cntxt(in_list, "In `in' list"); | |
1511 | chk_list(in_list, true, false); | |
1512 | } | |
1513 | if (out_list) { | |
1514 | Error_Context cntxt(out_list, "In `out' list"); | |
1515 | chk_list(out_list, false, true); | |
1516 | } | |
1517 | if (inout_list) { | |
1518 | Error_Context cntxt(inout_list, "In `inout' list"); | |
1519 | chk_list(inout_list, true, true); | |
1520 | } | |
1521 | } | |
1522 | ||
1523 | void PortTypeBody::chk_attributes(Ttcn::WithAttribPath *w_attrib_path) | |
1524 | { | |
1525 | if (!w_attrib_path || !checked || !my_type) | |
1526 | FATAL_ERROR("PortTypeBody::chk_attributes()"); | |
1527 | ||
1528 | Ttcn::ExtensionAttributes * extarts = parse_extattributes(w_attrib_path); | |
1529 | if (extarts != 0) { // NULL means parsing error | |
1530 | size_t num_atrs = extarts->size(); | |
1531 | for (size_t k = 0; k < num_atrs; ++k) { | |
1532 | ExtensionAttribute &ea = extarts->get(k); | |
1533 | switch (ea.get_type()) { | |
1534 | case ExtensionAttribute::PORT_API: { // internal or address | |
1535 | const PortTypeBody::TestPortAPI_t api = ea.get_api(); | |
1536 | if (api == PortTypeBody::TP_INTERNAL) { | |
1537 | switch (testport_type) { | |
1538 | case PortTypeBody::TP_REGULAR: | |
1539 | break; | |
1540 | case PortTypeBody::TP_INTERNAL: { | |
1541 | ea.warning("Duplicate attribute `internal'"); | |
1542 | break; } | |
1543 | case PortTypeBody::TP_ADDRESS: { | |
1544 | ea.error("Attributes `address' and `internal' " | |
1545 | "cannot be used at the same time"); | |
1546 | break; } | |
1547 | default: | |
1548 | FATAL_ERROR("coding_attrib_parse(): invalid testport type"); | |
1549 | } | |
1550 | set_testport_type(PortTypeBody::TP_INTERNAL); | |
1551 | } | |
1552 | else if (api == PortTypeBody::TP_ADDRESS) { | |
1553 | switch (testport_type) { | |
1554 | case PortTypeBody::TP_REGULAR: | |
1555 | break; | |
1556 | case PortTypeBody::TP_INTERNAL: { | |
1557 | ea.error("Attributes `internal' and `address' " | |
1558 | "cannot be used at the same time"); | |
1559 | break; } | |
1560 | case PortTypeBody::TP_ADDRESS: { | |
1561 | ea.warning("Duplicate attribute `address'"); | |
1562 | break; } | |
1563 | default: | |
1564 | FATAL_ERROR("coding_attrib_parse(): invalid testport type"); | |
1565 | } | |
1566 | set_testport_type(PortTypeBody::TP_ADDRESS); | |
1567 | } | |
1568 | break; } | |
1569 | ||
1570 | case ExtensionAttribute::PORT_TYPE_PROVIDER: | |
1571 | switch (port_type) { | |
1572 | case PortTypeBody::PT_REGULAR: | |
1573 | break; | |
1574 | case PortTypeBody::PT_PROVIDER: { | |
1575 | ea.warning("Duplicate attribute `provider'"); | |
1576 | break; } | |
1577 | case PortTypeBody::PT_USER: { | |
1578 | ea.error("Attributes `user' and `provider' " | |
1579 | "cannot be used at the same time"); | |
1580 | break; } | |
1581 | default: | |
1582 | FATAL_ERROR("coding_attrib_parse(): invalid testport type"); | |
1583 | } | |
1584 | add_provider_attribute(); | |
1585 | break; | |
1586 | ||
1587 | case ExtensionAttribute::PORT_TYPE_USER: | |
1588 | switch (port_type) { | |
1589 | case PortTypeBody::PT_REGULAR: | |
1590 | break; | |
1591 | case PortTypeBody::PT_PROVIDER: { | |
1592 | ea.error("Attributes `provider' and `user' " | |
1593 | "cannot be used at the same time"); | |
1594 | break; } | |
1595 | case PortTypeBody::PT_USER: { | |
1596 | ea.error("Duplicate attribute `user'"); | |
1597 | break; } | |
1598 | default: | |
1599 | FATAL_ERROR("coding_attrib_parse(): invalid testport type"); | |
1600 | } | |
1601 | Reference *ref; | |
1602 | TypeMappings *in; | |
1603 | TypeMappings *out; | |
1604 | ea.get_user(ref, in, out); | |
1605 | add_user_attribute(ref, in, out); | |
1606 | break; | |
1607 | ||
1608 | case ExtensionAttribute::ANYTYPELIST: | |
1609 | break; // ignore it | |
1610 | ||
1611 | case ExtensionAttribute::NONE: | |
1612 | break; // ignore, do not issue "wrong type" error | |
1613 | ||
1614 | default: | |
1615 | ea.error("Port can only have the following extension attributes: " | |
1616 | "'provider', 'user', 'internal' or 'address'"); | |
1617 | break; | |
1618 | } // switch | |
1619 | } // next attribute | |
1620 | delete extarts; | |
1621 | } // if not null | |
1622 | ||
1623 | if (port_type == PT_USER) chk_user_attribute(); | |
1624 | else if (testport_type == TP_ADDRESS) { | |
1625 | Error_Context cntxt(this, "In extension attribute `address'"); | |
1626 | Common::Module *my_mod = my_type->get_my_scope()->get_scope_mod(); | |
1627 | if (!my_mod->get_address_type()) | |
1628 | error("Type `address' is not defined in module `%s'", | |
1629 | my_mod->get_modid().get_dispname().c_str()); | |
1630 | } | |
1631 | } | |
1632 | ||
1633 | bool PortTypeBody::is_connectable(PortTypeBody *p_other) const | |
1634 | { | |
1635 | if (!checked || !p_other || !p_other->checked) | |
1636 | FATAL_ERROR("Type::is_connectable()"); | |
1637 | if (out_msgs) { | |
1638 | if (!p_other->in_msgs) return false; | |
1639 | size_t nof_msgs = out_msgs->get_nof_types(); | |
1640 | for (size_t i = 0; i < nof_msgs; i++) { | |
1641 | if (!p_other->in_msgs->has_type(out_msgs->get_type_byIndex(i))) | |
1642 | return false; | |
1643 | } | |
1644 | } | |
1645 | if (out_sigs) { | |
1646 | if (!p_other->in_sigs) return false; | |
1647 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1648 | for (size_t i = 0; i < nof_sigs; i++) { | |
1649 | if (!p_other->in_sigs->has_type(out_sigs->get_type_byIndex(i))) | |
1650 | return false; | |
1651 | } | |
1652 | } | |
1653 | return true; | |
1654 | } | |
1655 | ||
1656 | void PortTypeBody::report_connection_errors(PortTypeBody *p_other) const | |
1657 | { | |
1658 | if (!checked || !my_type || !p_other || !p_other->checked || | |
1659 | !p_other->my_type) | |
1660 | FATAL_ERROR("PortTypeBody::report_connection_errors()"); | |
1661 | const string& my_typename = my_type->get_typename(); | |
1662 | const char *my_typename_str = my_typename.c_str(); | |
1663 | const string& other_typename = p_other->my_type->get_typename(); | |
1664 | const char *other_typename_str = other_typename.c_str(); | |
1665 | if (out_msgs) { | |
1666 | size_t nof_msgs = out_msgs->get_nof_types(); | |
1667 | for (size_t i = 0; i < nof_msgs; i++) { | |
1668 | Type *t_msg = out_msgs->get_type_byIndex(i); | |
1669 | if (!p_other->in_msgs || !p_other->in_msgs->has_type(t_msg)) { | |
1670 | t_msg->note("Outgoing message type `%s' of port type `%s' is not " | |
1671 | "present on the incoming list of port type `%s'", | |
1672 | t_msg->get_typename().c_str(), my_typename_str, other_typename_str); | |
1673 | } | |
1674 | } | |
1675 | } | |
1676 | if (out_sigs) { | |
1677 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1678 | for (size_t i = 0; i < nof_sigs; i++) { | |
1679 | Type *t_sig = out_sigs->get_type_byIndex(i); | |
1680 | if (!p_other->in_sigs || !p_other->in_sigs->has_type(t_sig)) { | |
1681 | t_sig->note("Outgoing signature `%s' of port type `%s' is not " | |
1682 | "present on the incoming list of port type `%s'", | |
1683 | t_sig->get_typename().c_str(), my_typename_str, other_typename_str); | |
1684 | } | |
1685 | } | |
1686 | } | |
1687 | } | |
1688 | ||
1689 | bool PortTypeBody::is_mappable(PortTypeBody *p_other) const | |
1690 | { | |
1691 | if (!checked || !p_other || !p_other->checked) | |
1692 | FATAL_ERROR("PortTypeBody::is_mappable()"); | |
1693 | // shortcut: every port type can be mapped to itself | |
1694 | if (this == p_other) return true; | |
1695 | // outgoing lists of this should be covered by outgoing lists of p_other | |
1696 | if (out_msgs) { | |
1697 | if (!p_other->out_msgs) return false; | |
1698 | size_t nof_msgs = out_msgs->get_nof_types(); | |
1699 | for (size_t i = 0; i < nof_msgs; i++) { | |
1700 | if (!p_other->out_msgs->has_type(out_msgs->get_type_byIndex(i))) | |
1701 | return false; | |
1702 | } | |
1703 | } | |
1704 | if (out_sigs) { | |
1705 | if (!p_other->out_sigs) return false; | |
1706 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1707 | for (size_t i = 0; i < nof_sigs; i++) { | |
1708 | if (!p_other->out_sigs->has_type(out_sigs->get_type_byIndex(i))) | |
1709 | return false; | |
1710 | } | |
1711 | } | |
1712 | // incoming lists of p_other should be covered by incoming lists of this | |
1713 | if (p_other->in_msgs) { | |
1714 | if (!in_msgs) return false; | |
1715 | size_t nof_msgs = p_other->in_msgs->get_nof_types(); | |
1716 | for (size_t i = 0; i < nof_msgs; i++) { | |
1717 | if (!in_msgs->has_type(p_other->in_msgs->get_type_byIndex(i))) | |
1718 | return false; | |
1719 | } | |
1720 | } | |
1721 | if (p_other->in_sigs) { | |
1722 | if (!in_sigs) return false; | |
1723 | size_t nof_sigs = p_other->in_sigs->get_nof_types(); | |
1724 | for (size_t i = 0; i < nof_sigs; i++) { | |
1725 | if (!in_sigs->has_type(p_other->in_sigs->get_type_byIndex(i))) | |
1726 | return false; | |
1727 | } | |
1728 | } | |
1729 | return true; | |
1730 | } | |
1731 | ||
1732 | void PortTypeBody::report_mapping_errors(PortTypeBody *p_other) const | |
1733 | { | |
1734 | if (!checked || !my_type || !p_other || !p_other->checked || | |
1735 | !p_other->my_type) FATAL_ERROR("PortTypeBody::report_mapping_errors()"); | |
1736 | const string& my_typename = my_type->get_typename(); | |
1737 | const char *my_typename_str = my_typename.c_str(); | |
1738 | const string& other_typename = p_other->my_type->get_typename(); | |
1739 | const char *other_typename_str = other_typename.c_str(); | |
1740 | if (out_msgs) { | |
1741 | size_t nof_msgs = out_msgs->get_nof_types(); | |
1742 | for (size_t i = 0; i < nof_msgs; i++) { | |
1743 | Type *t_msg = out_msgs->get_type_byIndex(i); | |
1744 | if (!p_other->out_msgs || !p_other->out_msgs->has_type(t_msg)) { | |
1745 | t_msg->note("Outgoing message type `%s' of test component " | |
1746 | "port type `%s' is not present on the outgoing list of " | |
1747 | "system port type `%s'", t_msg->get_typename().c_str(), | |
1748 | my_typename_str, other_typename_str); | |
1749 | } | |
1750 | } | |
1751 | } | |
1752 | if (out_sigs) { | |
1753 | size_t nof_sigs = out_sigs->get_nof_types(); | |
1754 | for (size_t i = 0; i < nof_sigs; i++) { | |
1755 | Type *t_sig = out_sigs->get_type_byIndex(i); | |
1756 | if (!p_other->out_sigs || !p_other->out_sigs->has_type(t_sig)) { | |
1757 | t_sig->note("Outgoing signature `%s' of test component port type " | |
1758 | "`%s' is not present on the outgoing list of system port type " | |
1759 | "`%s'", t_sig->get_typename().c_str(), my_typename_str, | |
1760 | other_typename_str); | |
1761 | } | |
1762 | } | |
1763 | } | |
1764 | if (p_other->in_msgs) { | |
1765 | size_t nof_msgs = p_other->in_msgs->get_nof_types(); | |
1766 | for (size_t i = 0; i < nof_msgs; i++) { | |
1767 | Type *t_msg = p_other->in_msgs->get_type_byIndex(i); | |
1768 | if (!in_msgs || !in_msgs->has_type(t_msg)) { | |
1769 | t_msg->note("Incoming message type `%s' of system port type `%s' " | |
1770 | "is not present on the incoming list of test component port type " | |
1771 | "`%s'", t_msg->get_typename().c_str(), other_typename_str, | |
1772 | my_typename_str); | |
1773 | } | |
1774 | } | |
1775 | } | |
1776 | if (p_other->in_sigs) { | |
1777 | size_t nof_sigs = p_other->in_sigs->get_nof_types(); | |
1778 | for (size_t i = 0; i < nof_sigs; i++) { | |
1779 | Type *t_sig = p_other->in_sigs->get_type_byIndex(i); | |
1780 | if (!in_sigs || !in_sigs->has_type(t_sig)) { | |
1781 | t_sig->note("Incoming signature `%s' of system port type `%s' is " | |
1782 | "not present on the incoming list of test component port type " | |
1783 | "`%s'", t_sig->get_typename().c_str(), other_typename_str, | |
1784 | my_typename_str); | |
1785 | } | |
1786 | } | |
1787 | } | |
1788 | } | |
1789 | ||
1790 | void PortTypeBody::generate_code(output_struct *target) | |
1791 | { | |
1792 | if (!checked || !my_type) FATAL_ERROR("PortTypeBody::generate_code()"); | |
1793 | stringpool pool; | |
1794 | port_def pdef; | |
1795 | memset(&pdef, 0, sizeof(pdef)); | |
1796 | const string& t_genname = my_type->get_genname_own(); | |
1797 | pdef.name = t_genname.c_str(); | |
1798 | pdef.dispname = my_type->get_fullname().c_str(); | |
1799 | pdef.filename = pool.add(Identifier::name_2_ttcn(t_genname)); | |
1800 | Scope *my_scope = my_type->get_my_scope(); | |
1801 | const Identifier& modid = my_scope->get_scope_mod_gen()->get_modid(); | |
1802 | pdef.module_name = modid.get_name().c_str(); | |
1803 | pdef.module_dispname = modid.get_ttcnname().c_str(); | |
1804 | if (testport_type == TP_ADDRESS) { | |
1805 | Type *t_address = get_address_type(); | |
1806 | if (!t_address) FATAL_ERROR("PortTypeBody::generate_code()"); | |
1807 | pdef.address_name = pool.add(t_address->get_genname_value(my_scope)); | |
1808 | } else pdef.address_name = NULL; | |
1809 | ||
1810 | if (in_msgs) { | |
1811 | pdef.msg_in.nElements = in_msgs->get_nof_types(); | |
1812 | pdef.msg_in.elements = (port_msg_type*) | |
1813 | Malloc(pdef.msg_in.nElements * sizeof(*pdef.msg_in.elements)); | |
1814 | for (size_t i = 0; i < pdef.msg_in.nElements; i++) { | |
1815 | Type *type = in_msgs->get_type_byIndex(i); | |
1816 | pdef.msg_in.elements[i].name = | |
1817 | pool.add(type->get_genname_value(my_scope)); | |
1818 | pdef.msg_in.elements[i].dispname = pool.add(type->get_typename()); | |
1819 | } | |
1820 | } else { | |
1821 | pdef.msg_in.nElements = 0; | |
1822 | pdef.msg_in.elements = NULL; | |
1823 | } | |
1824 | if (out_msgs) { | |
1825 | pdef.msg_out.nElements = out_msgs->get_nof_types(); | |
1826 | pdef.msg_out.elements = (port_msg_mapped_type*) | |
1827 | Malloc(pdef.msg_out.nElements * sizeof(*pdef.msg_out.elements)); | |
1828 | for (size_t i = 0; i < pdef.msg_out.nElements; i++) { | |
1829 | Type *type = out_msgs->get_type_byIndex(i); | |
1830 | port_msg_mapped_type *mapped_type = pdef.msg_out.elements + i; | |
1831 | mapped_type->name = pool.add(type->get_genname_value(my_scope)); | |
1832 | mapped_type->dispname = pool.add(type->get_typename()); | |
1833 | if (port_type == PT_USER) { | |
1834 | if (!out_mappings) FATAL_ERROR("PortTypeBody::generate_code()"); | |
1835 | TypeMapping *mapping = out_mappings->get_mapping_byType(type); | |
1836 | mapped_type->nTargets = mapping->get_nof_targets(); | |
1837 | mapped_type->targets = (port_msg_type_mapping_target*) | |
1838 | Malloc(mapped_type->nTargets * sizeof(*mapped_type->targets)); | |
1839 | for (size_t j = 0; j < mapped_type->nTargets; j++) { | |
1840 | mapping->get_target_byIndex(j)->fill_type_mapping_target( | |
1841 | mapped_type->targets + j, type, my_scope, pool); | |
1842 | mapped_type->targets[j].target_index = static_cast<size_t>(-1); | |
1843 | } | |
1844 | } else { | |
1845 | mapped_type->nTargets = 0; | |
1846 | mapped_type->targets = NULL; | |
1847 | } | |
1848 | } | |
1849 | } else { | |
1850 | pdef.msg_out.nElements = 0; | |
1851 | pdef.msg_out.elements = NULL; | |
1852 | } | |
1853 | ||
1854 | if (in_sigs) { | |
1855 | pdef.proc_in.nElements = in_sigs->get_nof_types(); | |
1856 | pdef.proc_in.elements = (port_proc_signature*) | |
1857 | Malloc(pdef.proc_in.nElements * sizeof(*pdef.proc_in.elements)); | |
1858 | for (size_t i = 0; i < pdef.proc_in.nElements; i++) { | |
1859 | Type *signature = in_sigs->get_type_byIndex(i)->get_type_refd_last(); | |
1860 | pdef.proc_in.elements[i].name = | |
1861 | pool.add(signature->get_genname_value(my_scope)); | |
1862 | pdef.proc_in.elements[i].dispname = | |
1863 | pool.add(signature->get_typename()); | |
1864 | pdef.proc_in.elements[i].is_noblock = | |
1865 | signature->is_nonblocking_signature(); | |
1866 | pdef.proc_in.elements[i].has_exceptions = | |
1867 | signature->get_signature_exceptions() ? TRUE : FALSE; | |
1868 | } | |
1869 | } else { | |
1870 | pdef.proc_in.nElements = 0; | |
1871 | pdef.proc_in.elements = NULL; | |
1872 | } | |
1873 | if (out_sigs) { | |
1874 | pdef.proc_out.nElements = out_sigs->get_nof_types(); | |
1875 | pdef.proc_out.elements = (port_proc_signature*) | |
1876 | Malloc(pdef.proc_out.nElements * sizeof(*pdef.proc_out.elements)); | |
1877 | for (size_t i = 0; i < pdef.proc_out.nElements; i++) { | |
1878 | Type *signature = out_sigs->get_type_byIndex(i)->get_type_refd_last(); | |
1879 | pdef.proc_out.elements[i].name = | |
1880 | pool.add(signature->get_genname_value(my_scope)); | |
1881 | pdef.proc_out.elements[i].dispname = | |
1882 | pool.add(signature->get_typename()); | |
1883 | pdef.proc_out.elements[i].is_noblock = | |
1884 | signature->is_nonblocking_signature(); | |
1885 | pdef.proc_out.elements[i].has_exceptions = | |
1886 | signature->get_signature_exceptions() ? TRUE : FALSE; | |
1887 | } | |
1888 | } else { | |
1889 | pdef.proc_out.nElements = 0; | |
1890 | pdef.proc_out.elements = NULL; | |
1891 | } | |
1892 | ||
1893 | switch (testport_type) { | |
1894 | case TP_REGULAR: | |
1895 | pdef.testport_type = NORMAL; | |
1896 | break; | |
1897 | case TP_INTERNAL: | |
1898 | pdef.testport_type = INTERNAL; | |
1899 | break; | |
1900 | case TP_ADDRESS: | |
1901 | pdef.testport_type = ADDRESS; | |
1902 | break; | |
1903 | default: | |
1904 | FATAL_ERROR("PortTypeBody::generate_code()"); | |
1905 | } | |
1906 | ||
1907 | if (port_type == PT_USER) { | |
1908 | pdef.port_type = USER; | |
1909 | if (!provider_type) FATAL_ERROR("PortTypeBody::generate_code()"); | |
1910 | pdef.provider_name = | |
1911 | pool.add(provider_type->get_genname_value(my_scope)); | |
1912 | PortTypeBody *provider_body = provider_type->get_PortBody(); | |
1913 | if (provider_body->in_msgs) { | |
1914 | if (!in_mappings) // !this->in_msgs OK for an all-discard mapping | |
1915 | FATAL_ERROR("PortTypeBody::generate_code()"); | |
1916 | pdef.provider_msg_in.nElements = | |
1917 | provider_body->in_msgs->get_nof_types(); | |
1918 | pdef.provider_msg_in.elements = (port_msg_mapped_type*) | |
1919 | Malloc(pdef.provider_msg_in.nElements * | |
1920 | sizeof(*pdef.provider_msg_in.elements)); | |
1921 | for (size_t i = 0; i < pdef.provider_msg_in.nElements; i++) { | |
1922 | Type *type = provider_body->in_msgs->get_type_byIndex(i); | |
1923 | port_msg_mapped_type *mapped_type = pdef.provider_msg_in.elements + i; | |
1924 | mapped_type->name = pool.add(type->get_genname_value(my_scope)); | |
1925 | mapped_type->dispname = pool.add(type->get_typename()); | |
1926 | TypeMapping *mapping = in_mappings->get_mapping_byType(type); | |
1927 | mapped_type->nTargets = mapping->get_nof_targets(); | |
1928 | mapped_type->targets = (port_msg_type_mapping_target*) | |
1929 | Malloc(mapped_type->nTargets * sizeof(*mapped_type->targets)); | |
1930 | for (size_t j = 0; j < mapped_type->nTargets; j++) { | |
1931 | TypeMappingTarget *t_target = mapping->get_target_byIndex(j); | |
1932 | pdef.has_sliding |= t_target->fill_type_mapping_target( | |
1933 | mapped_type->targets + j, type, my_scope, pool); | |
1934 | Type *target_type = t_target->get_target_type(); | |
1935 | if (target_type) { | |
1936 | if (!in_msgs) FATAL_ERROR("PortTypeBody::generate_code()"); | |
1937 | mapped_type->targets[j].target_index = | |
1938 | in_msgs->get_index_byType(target_type); | |
1939 | } else { | |
1940 | // the message will be discarded: fill in a dummy index | |
1941 | mapped_type->targets[j].target_index = static_cast<size_t>(-1); | |
1942 | } | |
1943 | } | |
1944 | } | |
1945 | } else { | |
1946 | pdef.provider_msg_in.nElements = 0; | |
1947 | pdef.provider_msg_in.elements = NULL; | |
1948 | } | |
1949 | } else { | |
1950 | // "internal provider" is the same as "internal" | |
1951 | if (port_type == PT_PROVIDER && testport_type != TP_INTERNAL) | |
1952 | pdef.port_type = PROVIDER; | |
1953 | else pdef.port_type = REGULAR; | |
1954 | pdef.provider_name = NULL; | |
1955 | pdef.provider_msg_in.nElements = 0; | |
1956 | pdef.provider_msg_in.elements = NULL; | |
1957 | } | |
1958 | ||
1959 | defPortClass(&pdef, target); | |
1960 | if (generate_skeleton && testport_type != TP_INTERNAL && | |
1961 | port_type != PT_USER) generateTestPortSkeleton(&pdef); | |
1962 | ||
1963 | Free(pdef.msg_in.elements); | |
1964 | for (size_t i = 0; i < pdef.msg_out.nElements; i++) | |
1965 | Free(pdef.msg_out.elements[i].targets); | |
1966 | Free(pdef.msg_out.elements); | |
1967 | Free(pdef.proc_in.elements); | |
1968 | Free(pdef.proc_out.elements); | |
1969 | for (size_t i = 0; i < pdef.provider_msg_in.nElements; i++) | |
1970 | Free(pdef.provider_msg_in.elements[i].targets); | |
1971 | Free(pdef.provider_msg_in.elements); | |
1972 | } | |
1973 | ||
1974 | void PortTypeBody::dump(unsigned level) const | |
1975 | { | |
1976 | switch (operation_mode) { | |
1977 | case PO_MESSAGE: | |
1978 | DEBUG(level, "mode: message"); | |
1979 | break; | |
1980 | case PO_PROCEDURE: | |
1981 | DEBUG(level, "mode: procedure"); | |
1982 | break; | |
1983 | case PO_MIXED: | |
1984 | DEBUG(level, "mode: mixed"); | |
1985 | break; | |
1986 | default: | |
1987 | DEBUG(level, "mode: <invalid>"); | |
1988 | } | |
1989 | if (in_list) { | |
1990 | DEBUG(level, "in list:"); | |
1991 | in_list->dump(level + 1); | |
1992 | } | |
1993 | if (in_all) DEBUG(level, "in all"); | |
1994 | if (out_list) { | |
1995 | DEBUG(level, "out list:"); | |
1996 | out_list->dump(level + 1); | |
1997 | } | |
1998 | if (out_all) DEBUG(level, "out all"); | |
1999 | if (inout_list) { | |
2000 | DEBUG(level, "inout list:"); | |
2001 | inout_list->dump(level + 1); | |
2002 | } | |
2003 | if (inout_all) DEBUG(level, "inout all"); | |
2004 | if (in_msgs) { | |
2005 | DEBUG(level, "incoming messages:"); | |
2006 | in_msgs->dump(level + 1); | |
2007 | } | |
2008 | if (out_msgs) { | |
2009 | DEBUG(level, "outgoing messages:"); | |
2010 | out_msgs->dump(level + 1); | |
2011 | } | |
2012 | if (in_sigs) { | |
2013 | DEBUG(level, "incoming signatures:"); | |
2014 | in_sigs->dump(level + 1); | |
2015 | } | |
2016 | if (out_sigs) { | |
2017 | DEBUG(level, "outgoing signatures:"); | |
2018 | out_sigs->dump(level + 1); | |
2019 | } | |
2020 | switch (testport_type) { | |
2021 | case TP_REGULAR: | |
2022 | break; | |
2023 | case TP_INTERNAL: | |
2024 | DEBUG(level, "attribute: internal"); | |
2025 | break; | |
2026 | case TP_ADDRESS: | |
2027 | DEBUG(level, "attribute: address"); | |
2028 | break; | |
2029 | default: | |
2030 | DEBUG(level, "attribute: <unknown>"); | |
2031 | } | |
2032 | switch (port_type) { | |
2033 | case PT_REGULAR: | |
2034 | break; | |
2035 | case PT_PROVIDER: | |
2036 | DEBUG(level, "attribute: provider"); | |
2037 | break; | |
2038 | case PT_USER: | |
2039 | DEBUG(level, "attribute: user"); | |
2040 | break; | |
2041 | default: | |
2042 | DEBUG(level, "attribute: <unknown>"); | |
2043 | } | |
2044 | if (provider_ref) | |
2045 | DEBUG(level, "provider type: %s", provider_ref->get_dispname().c_str()); | |
2046 | if (in_mappings) { | |
2047 | DEBUG(level, "in mappings:"); | |
2048 | in_mappings->dump(level + 1); | |
2049 | } | |
2050 | if (out_mappings) { | |
2051 | DEBUG(level, "out mappings:"); | |
2052 | out_mappings->dump(level + 1); | |
2053 | } | |
2054 | } | |
2055 | ||
2056 | // ================================= | |
2057 | // ===== ExtensionAttribute | |
2058 | // ================================= | |
2059 | static const string version_template("RnXnn"); | |
2060 | ||
2061 | void ExtensionAttribute::check_product_number(const char* ABCClass, int type_number, int sequence) { | |
2062 | if (NULL == ABCClass && 0 == type_number && 0 == sequence) { | |
2063 | return; | |
2064 | } | |
2065 | ||
2066 | int ABCLength = strlen(ABCClass); | |
2067 | if (ABCLength < 3 || ABCLength > 5) { | |
2068 | // incorrect ABC number | |
2069 | type_ = NONE; | |
2070 | return; | |
2071 | } | |
2072 | ||
2073 | if (type_number >= 1000) { | |
2074 | type_ = NONE; | |
2075 | return; | |
2076 | } | |
2077 | ||
2078 | if (sequence >= 10000 ) { | |
2079 | type_ = NONE; | |
2080 | } | |
2081 | } | |
2082 | ||
2083 | void ExtensionAttribute::parse_version(Identifier *ver) { | |
2084 | unsigned int rel, bld = 99; | |
2085 | char patch[4] = {0,0,0,0}; | |
2086 | // The limit of max three characters is an optimization: any more than two | |
2087 | // is already an error and we can quit scanning. We can't limit the field | |
2088 | // to two by using "%2[...] because then we can't distinguish between R1AA | |
2089 | // and R1AAA. The switch below makes the distinction between one character | |
2090 | // like R1A (valid), two characters like R1AA (also valid), and | |
2091 | // R1AAA (invalid). | |
2092 | // in addition after the RmXnn part some characters may come (needed by TitanSim) | |
2093 | char extra_junk[64]; | |
2094 | int scanned = sscanf(ver->get_dispname().c_str(), "R%u%3[A-HJ-NS-VX-Z]%u%63s", | |
2095 | &rel, patch, &bld, extra_junk); | |
2096 | value_.version_.extra_ = NULL; | |
2097 | switch (scanned * (patch[2]==0)) { | |
2098 | case 4: // all fields + titansim's extra stuff scanned | |
2099 | if (strlen(extra_junk)>0) { | |
2100 | value_.version_.extra_ = mprintf("%s", extra_junk); | |
2101 | } | |
2102 | case 3: // all fields scanned | |
2103 | case 2: // 2 scanned, bld remained unmodified | |
2104 | value_.version_.release_ = rel; | |
2105 | value_.version_.build_ = bld; | |
2106 | switch (patch[0]) { | |
2107 | case 'A': case 'B': case 'C': case 'D': | |
2108 | case 'E': case 'F': case 'G': case 'H': | |
2109 | value_.version_.patch_ = patch[0] - 'A'; | |
2110 | break; | |
2111 | case 'J': case 'K': case 'L': case 'M': case 'N': | |
2112 | value_.version_.patch_ = patch[0] - 'A' - 1; | |
2113 | break; | |
2114 | case 'S': case 'T': case 'U': case 'V': | |
2115 | value_.version_.patch_ = patch[0] - 'A' - 5; | |
2116 | break; | |
2117 | case 'X': case 'Y': case 'Z': | |
2118 | value_.version_.patch_ = patch[0] - 'A' - 6; | |
2119 | break; | |
2120 | ||
2121 | case 'I': case 'W': // forbidden | |
2122 | case 'O': case 'P': case 'Q': case 'R': // forbidden | |
2123 | default: // incorrect | |
2124 | type_ = NONE; | |
2125 | break; | |
2126 | } | |
2127 | break; | |
2128 | default: // there was an error | |
2129 | type_ = NONE; | |
2130 | break; | |
2131 | } | |
2132 | } | |
2133 | ||
2134 | ExtensionAttribute::ExtensionAttribute(const char* ABCClass, int type_number, | |
2135 | int sequence, int suffix, Identifier *ver) | |
2136 | : Location(), type_(VERSION), value_() | |
2137 | { | |
2138 | if (ver == NULL) FATAL_ERROR("ExtensionAttribute::ExtensionAttribute()"); | |
2139 | value_.version_.module_ = NULL; | |
2140 | ||
2141 | check_product_number(ABCClass, type_number, sequence); | |
2142 | parse_version(ver); | |
2143 | if (type_ != NONE) { | |
2144 | value_.version_.productNumber_ = | |
2145 | NULL == ABCClass ? NULL : mprintf("%s %d %d", ABCClass, type_number, sequence); | |
2146 | value_.version_.suffix_ = suffix; | |
2147 | delete ver; // "took care of it" | |
2148 | } | |
2149 | } | |
2150 | ||
2151 | ExtensionAttribute::ExtensionAttribute(Identifier *mod, const char* ABCClass, | |
2152 | int type_number, int sequence, int suffix, Identifier *ver) | |
2153 | : Location(), type_(REQUIRES), value_() | |
2154 | { | |
2155 | if (mod == NULL || ver == NULL) | |
2156 | FATAL_ERROR("ExtensionAttribute::ExtensionAttribute()"); | |
2157 | // store the module identifier | |
2158 | value_.version_.module_ = mod; | |
2159 | ||
2160 | check_product_number(ABCClass, type_number, sequence); | |
2161 | parse_version(ver); | |
2162 | if (type_ == NONE) { // parse_version reported an error | |
2163 | value_.version_.module_ = NULL; // disown it; caller will free | |
2164 | value_.version_.suffix_ = suffix; | |
2165 | } else { | |
2166 | value_.version_.productNumber_ = | |
2167 | NULL == ABCClass ? NULL : mprintf("%s %d %d", ABCClass, type_number, sequence); | |
2168 | value_.version_.suffix_ = suffix; | |
2169 | delete ver; | |
2170 | } | |
2171 | } | |
2172 | ||
2173 | ExtensionAttribute::ExtensionAttribute(const char* ABCClass, int type_number, | |
2174 | int sequence, int suffix, Identifier* ver, extension_t et) | |
2175 | : Location(), type_(et), value_() | |
2176 | { | |
2177 | if (ver == NULL) FATAL_ERROR("ExtensionAttribute::ExtensionAttribute()"); | |
2178 | ||
2179 | switch (et) { | |
2180 | case REQ_TITAN: | |
2181 | check_product_number(ABCClass, type_number, sequence); | |
2182 | parse_version(ver); | |
2183 | if (type_ != NONE) { | |
2184 | value_.version_.productNumber_ = | |
2185 | NULL == ABCClass ? NULL : mprintf("%s %d %d", ABCClass, type_number, sequence); | |
2186 | value_.version_.suffix_ = suffix; | |
2187 | delete ver; // "took care of it" | |
2188 | } else { | |
2189 | value_.version_.suffix_ = suffix; | |
2190 | } | |
2191 | break; | |
2192 | ||
2193 | case VERSION_TEMPLATE: // RnXnn without the <>, must match exactly | |
2194 | if (ver->get_name() == version_template) { | |
2195 | value_.version_.productNumber_ = NULL; | |
2196 | value_.version_.suffix_ = UINT_MAX; | |
2197 | value_.version_.release_ = UINT_MAX; | |
2198 | value_.version_.patch_ = UINT_MAX; | |
2199 | value_.version_.build_ = UINT_MAX; | |
2200 | delete ver; | |
2201 | return; | |
2202 | } | |
2203 | else type_ = NONE; | |
2204 | break; | |
2205 | ||
2206 | default: | |
2207 | FATAL_ERROR("ExtensionAttribute::ExtensionAttribute()"); | |
2208 | break; | |
2209 | } | |
2210 | ||
2211 | } | |
2212 | ||
2213 | ||
2214 | ExtensionAttribute::~ExtensionAttribute() | |
2215 | { | |
2216 | switch (type_) { | |
2217 | case NONE: | |
2218 | break; // nothing to do, data has been extracted | |
2219 | // TODO perhaps NONE should be the only acceptable option? | |
2220 | // (no unprocessed attribute allowed) | |
2221 | case PROTOTYPE: | |
2222 | break; | |
2223 | case ENCODE: case DECODE: | |
2224 | delete value_.encdec_.s_; | |
2225 | break; | |
2226 | case PORT_API: | |
2227 | break; | |
2228 | case PORT_TYPE_USER: | |
2229 | delete value_.user_.ref_; | |
2230 | delete value_.user_.inmaps_; | |
2231 | delete value_.user_.outmaps_; | |
2232 | break; | |
2233 | case PORT_TYPE_PROVIDER: | |
2234 | break; | |
2235 | case ERRORBEHAVIOR: | |
2236 | delete value_.ebl_; | |
2237 | break; | |
2238 | case ANYTYPELIST: | |
2239 | delete value_.anytypes_; | |
2240 | break; | |
2241 | case ENCDECVALUE: | |
2242 | delete value_.encdecvalue_.inmaps_; | |
2243 | delete value_.encdecvalue_.outmaps_; | |
2244 | break; | |
2245 | case VERSION: | |
2246 | case VERSION_TEMPLATE: | |
2247 | Free(value_.version_.productNumber_); | |
2248 | Free(value_.version_.extra_); | |
2249 | break; | |
2250 | case REQUIRES: | |
2251 | Free(value_.version_.productNumber_); | |
2252 | Free(value_.version_.extra_); | |
2253 | delete value_.version_.module_; | |
2254 | break; | |
2255 | case REQ_TITAN: | |
2256 | Free(value_.version_.productNumber_); | |
2257 | Free(value_.version_.extra_); | |
2258 | break; | |
2259 | case TRANSPARENT: | |
2260 | break; | |
2261 | case PRINTING: | |
2262 | delete value_.pt_; | |
2263 | break; | |
2264 | default: // can't happen | |
2265 | FATAL_ERROR("ExtensionAttribute::~ExtensionAttribute(%X)", type_); | |
2266 | } | |
2267 | } | |
2268 | ||
2269 | Types *ExtensionAttribute::get_types() | |
2270 | { | |
2271 | if (type_ != ANYTYPELIST) FATAL_ERROR("ExtensionAttribute::get_types()"); | |
2272 | type_ = NONE; | |
2273 | return value_.anytypes_; | |
2274 | } | |
2275 | ||
2276 | Ttcn::Def_Function_Base::prototype_t ExtensionAttribute::get_proto() | |
2277 | { | |
2278 | if (type_ != PROTOTYPE) FATAL_ERROR("ExtensionAttribute::get_proto()"); | |
2279 | type_ = NONE; | |
2280 | return value_.proto_; | |
2281 | } | |
2282 | ||
2283 | void ExtensionAttribute::get_encdec_parameters( | |
2284 | Type::MessageEncodingType_t &p_encoding_type, string *&p_encoding_options) | |
2285 | { | |
2286 | if (type_ != ENCODE && type_ != DECODE) | |
2287 | FATAL_ERROR("ExtensionAttribute::get_encdec_parameters()"); | |
2288 | type_ = NONE; | |
2289 | p_encoding_type = value_.encdec_.mess_; | |
2290 | p_encoding_options = value_.encdec_.s_; | |
2291 | const_cast<ExtensionAttribute*>(this)->value_.encdec_.s_ = 0; | |
2292 | } | |
2293 | ||
2294 | ErrorBehaviorList *ExtensionAttribute::get_eb_list() | |
2295 | { | |
2296 | if (type_ != ERRORBEHAVIOR) | |
2297 | FATAL_ERROR("ExtensionAttribute::get_eb_list()"); | |
2298 | type_ = NONE; | |
2299 | ErrorBehaviorList *retval = value_.ebl_; | |
2300 | const_cast<ExtensionAttribute*>(this)->value_.ebl_ = 0; | |
2301 | return retval; | |
2302 | } | |
2303 | ||
2304 | PrintingType *ExtensionAttribute::get_printing() | |
2305 | { | |
2306 | if (type_ != PRINTING) | |
2307 | FATAL_ERROR("ExtensionAttribute::get_printing()"); | |
2308 | type_ = NONE; | |
2309 | PrintingType *retval = value_.pt_; | |
2310 | const_cast<ExtensionAttribute*>(this)->value_.pt_ = 0; | |
2311 | return retval; | |
2312 | } | |
2313 | ||
2314 | PortTypeBody::TestPortAPI_t ExtensionAttribute::get_api() | |
2315 | { | |
2316 | if (type_ != PORT_API) | |
2317 | FATAL_ERROR("ExtensionAttribute::get_api()"); | |
2318 | type_ = NONE; | |
2319 | return value_.api_; | |
2320 | } | |
2321 | ||
2322 | void ExtensionAttribute::get_user(Reference *&ref, | |
2323 | TypeMappings *&in, TypeMappings *&out) | |
2324 | { | |
2325 | if (type_ != PORT_TYPE_USER) | |
2326 | FATAL_ERROR("ExtensionAttribute::get_user()"); | |
2327 | type_ = NONE; | |
2328 | ||
2329 | ref = value_.user_.ref_; | |
2330 | in = value_.user_.inmaps_; | |
2331 | out = value_.user_.outmaps_; | |
2332 | ||
2333 | value_.user_.ref_ = 0; | |
2334 | value_.user_.inmaps_ = 0; | |
2335 | value_.user_.outmaps_ = 0; | |
2336 | } | |
2337 | ||
2338 | void ExtensionAttribute::get_encdecvalue_mappings( | |
2339 | TypeMappings *&in, TypeMappings *&out) | |
2340 | { | |
2341 | if (type_ != ENCDECVALUE) | |
2342 | FATAL_ERROR("ExtensionAttribute::get_encdecvalue_mappings()"); | |
2343 | ||
2344 | in = value_.encdecvalue_.inmaps_; | |
2345 | out = value_.encdecvalue_.outmaps_; | |
2346 | } | |
2347 | ||
2348 | //FIXME ot is update -elni kell. | |
2349 | Common::Identifier *ExtensionAttribute::get_id( | |
2350 | char*& product_number, unsigned int& suffix, | |
2351 | unsigned int& rel, unsigned int& patch, unsigned int& bld, char*& extra) | |
2352 | { | |
2353 | if ( type_ != REQUIRES && type_ != REQ_TITAN | |
2354 | && type_ != VERSION && type_ != VERSION_TEMPLATE) { | |
2355 | FATAL_ERROR("ExtensionAttribute::get_id()"); | |
2356 | } | |
2357 | product_number = value_.version_.productNumber_; | |
2358 | suffix = value_.version_.suffix_; | |
2359 | rel = value_.version_.release_; | |
2360 | patch = value_.version_.patch_; | |
2361 | bld = value_.version_.build_; | |
2362 | extra = value_.version_.extra_; | |
2363 | return value_.version_.module_; | |
2364 | } | |
2365 | ||
2366 | // ================================= | |
2367 | // ===== ExtensionAttributes | |
2368 | // ================================= | |
2369 | void ExtensionAttributes::add(ExtensionAttribute *a) | |
2370 | { | |
2371 | vector<ExtensionAttribute>::add(a); | |
2372 | } | |
2373 | ||
2374 | ExtensionAttributes::~ExtensionAttributes() | |
2375 | { | |
2376 | for (int i = size()-1; i >= 0; --i) | |
2377 | delete operator [](i); | |
2378 | clear(); | |
2379 | } | |
2380 | ||
2381 | void ExtensionAttributes::import(ExtensionAttributes *other) | |
2382 | { | |
2383 | size_t n = other->size(); | |
2384 | for (size_t i = 0; i < n; ++i) { | |
2385 | vector<ExtensionAttribute>::add((*other)[i]); | |
2386 | } | |
2387 | other->clear(); | |
2388 | } | |
2389 | ||
2390 | } // namespace Ttcn |