Replaced unbound record elements with null pointers in record-ofs (bug 494614)
[deliverable/titan.core.git] / compiler2 / Type_codegen.cc
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 * Baji, Laszlo
10 * Balasko, Jeno
11 * Baranyi, Botond
12 * Delic, Adam
13 * Raduly, Csaba
14 * Szabados, Kristof
15 * Pandi, Krisztian
16 *
17 ******************************************************************************/
18 #include "../common/dbgnew.hh"
19 #include "Type.hh"
20 #include "CompField.hh"
21 #include "EnumItem.hh"
22 #include "SigParam.hh"
23 #include "main.hh"
24
25 #include "enum.h"
26 #include "record.h"
27 #include "union.h"
28 #include "record_of.h"
29 #include "functionref.h"
30
31
32 #include "ttcn3/Ttcnstuff.hh"
33 #include "ttcn3/ArrayDimensions.hh"
34 #include "ttcn3/Attributes.hh"
35 #include "ttcn3/signature.h"
36 #include "XerAttributes.hh"
37
38 #include "asn1/TableConstraint.hh"
39 #include "asn1/Object.hh"
40 #include "asn1/Tag.hh"
41 #include "asn1/Ref.hh"
42
43 #include "CodeGenHelper.hh"
44
45 #include "../common/JSON_Tokenizer.hh"
46
47 namespace Common {
48
49 using Asn::Tags;
50 using Ttcn::SingleWithAttrib;
51
52 void Type::generate_code(output_struct *target)
53 {
54 if (code_generated) return;
55 generate_code_embedded_before(target);
56 // escape from recursion loops
57 if (code_generated) return;
58 code_generated = true;
59 generate_code_typedescriptor(target);
60 string sourcefile = get_sourcefile_attribute();
61 if (!sourcefile.empty()) {
62 generate_code_include(sourcefile, target);
63 } else {
64 switch(typetype) {
65 case T_ENUM_A:
66 case T_ENUM_T:
67 generate_code_Enum(target);
68 break;
69 case T_CHOICE_A:
70 case T_CHOICE_T:
71 case T_OPENTYPE:
72 case T_ANYTYPE:
73 generate_code_Choice(target);
74 break;
75 case T_SEQ_A:
76 case T_SEQ_T:
77 case T_SET_A:
78 case T_SET_T:
79 generate_code_Se(target);
80 break;
81 case T_SEQOF:
82 case T_SETOF:
83 generate_code_SeOf(target);
84 break;
85 case T_PORT:
86 u.port->generate_code(target);
87 break;
88 case T_ARRAY:
89 generate_code_Array(target);
90 break;
91 case T_SIGNATURE:
92 generate_code_Signature(target);
93 break;
94 case T_FUNCTION:
95 case T_ALTSTEP:
96 case T_TESTCASE:
97 generate_code_Fat(target);
98 break;
99 default:
100 generate_code_alias(target);
101 break;
102 } // switch
103 }
104 generate_code_embedded_after(target);
105 if (!is_asn1()) {
106 if (has_done_attribute()) generate_code_done(target);
107 if (sub_type) sub_type->generate_code(*target);
108 }
109 }
110
111 void Type::generate_code_include(const string& sourcefile, output_struct *target)
112 {
113 const char* name = get_genname_own().c_str();
114 const char* dispname = get_fullname().c_str();
115 target->header.class_decls = mputprintf(target->header.class_decls,
116 "class %s;\n"
117 "class %s_template;\n",
118 name, name);
119
120 target->header.class_defs = mputprintf(target->header.class_defs,
121 "// Implementation of type %s\n"
122 "#include \"%s.hh\"\n",
123 dispname, sourcefile.c_str());
124 }
125
126 void Type::generate_code_embedded_before(output_struct *target)
127 {
128 switch (typetype) {
129 case T_SEQ_A:
130 case T_SEQ_T:
131 case T_SET_A:
132 case T_SET_T: {
133 size_t nof_comps = get_nof_comps();
134 for (size_t i = 0; i < nof_comps; i++) {
135 CompField *cf = get_comp_byIndex(i);
136 if (!cf->get_is_optional()) {
137 // generate code for mandatory record/set fields only
138 cf->get_type()->generate_code(
139 CodeGenHelper::GetInstance().get_outputstruct(
140 cf->get_type()->get_type_refd_last()
141 )
142 );
143 CodeGenHelper::GetInstance().finalize_generation(
144 cf->get_type()->get_type_refd_last()
145 );
146 // escape from recursion loops
147 if (code_generated) break;
148 }
149 }
150 break; }
151 case T_REFD:
152 case T_SELTYPE:
153 case T_REFDSPEC:
154 case T_OCFT: {
155 Type *type_refd = get_type_refd();
156 // generate code for the referenced type only if it is defined
157 // in the same module
158 if (my_scope->get_scope_mod_gen() ==
159 type_refd->my_scope->get_scope_mod_gen())
160 type_refd->generate_code(target);
161 break; }
162 case T_SIGNATURE:
163 // the parameter types and the return type shall be generated
164 if (u.signature.parameters) {
165 size_t nof_params = u.signature.parameters->get_nof_params();
166 for (size_t i = 0; i < nof_params; i++) {
167 u.signature.parameters->get_param_byIndex(i)->get_type()
168 ->generate_code(target);
169 }
170 }
171 if (u.signature.return_type)
172 u.signature.return_type->generate_code(target);
173 break;
174 case T_ARRAY:
175 u.array.element_type->generate_code(target);
176 break;
177 default:
178 break;
179 }
180 }
181
182 void Type::generate_code_embedded_after(output_struct *target)
183 {
184 switch (typetype) {
185 case T_SEQ_A:
186 case T_SEQ_T:
187 case T_SET_A:
188 case T_SET_T: {
189 size_t nof_comps = get_nof_comps();
190 for (size_t i = 0; i < nof_comps; i++) {
191 CompField *cf = get_comp_byIndex(i);
192 if (cf->get_is_optional()) {
193 // generate code for optional record/set fields only
194 // mandatory fields are already completed
195 Type *t = cf->get_type();
196 if (!t->is_pure_refd()) t->generate_code(target);
197 }
198 }
199 break; }
200 case T_ANYTYPE:
201 case T_CHOICE_A:
202 case T_CHOICE_T: {
203 size_t nof_comps = get_nof_comps();
204 for (size_t i = 0; i < nof_comps; i++) {
205 // generate code for all union fields
206 Type *t = get_comp_byIndex(i)->get_type();
207 if (!t->is_pure_refd()) t->generate_code(target);
208 }
209 break; }
210 case T_OPENTYPE:
211 if (u.secho.my_tableconstraint) {
212 // generate code for all embedded settings of the object set
213 // that is used in the table constraint
214 Asn::ObjectSet *os = u.secho.my_tableconstraint->get_os();
215 if (os->get_my_scope()->get_scope_mod_gen() ==
216 my_scope->get_scope_mod_gen()) os->generate_code(target);
217 }
218 break;
219 case T_SEQOF:
220 case T_SETOF:
221 // generate code for the embedded type
222 if (!u.seof.ofType->is_pure_refd()) u.seof.ofType->generate_code(target);
223 break;
224 case T_FUNCTION:
225 case T_ALTSTEP:
226 case T_TESTCASE: {
227 size_t nof_params = u.fatref.fp_list->get_nof_fps();
228 for(size_t i = 0; i < nof_params; i++) {
229 u.fatref.fp_list->get_fp_byIndex(i)->get_Type()
230 ->generate_code(target);
231 }
232 break; }
233 default:
234 break;
235 }
236 }
237
238 void Type::generate_code_typedescriptor(output_struct *target)
239 {
240 bool force_xer = false;
241 switch (get_type_refd_last()->typetype) {
242 case T_PORT:
243 case T_SIGNATURE:
244 // do not generate any type descriptor for these non-data types
245 return;
246 case T_ARRAY:
247 // no force xer
248 break;
249
250 default:
251 switch (ownertype) {
252 case OT_TYPE_ASS:
253 case OT_TYPE_DEF:
254 case OT_COMP_FIELD:
255 case OT_RECORD_OF:
256 case OT_REF_SPEC:
257 force_xer = has_encoding(CT_XER); // && (is_ref() || (xerattrib && !xerattrib->empty()));
258 break;
259 default:
260 break;
261 } // switch(ownertype)
262 break;
263 } // switch
264
265 const string& gennameown = get_genname_own();
266 const char *gennameown_str = gennameown.c_str();
267 const string& gennametypedescriptor = get_genname_typedescriptor(my_scope);
268 //printf("generate_code_typedescriptor(%s)\n", gennameown_str);
269
270 // FIXME: force_xer should be elminated. if a type needs a descriptor,
271 // it should say so via get_genname_typedescriptor()
272
273 /* genname{type,ber,raw,text,xer}descriptor == gennameown is true if
274 * the type needs its own {type,ber,raw,text,xer}descriptor
275 * and can't use the descriptor of one of the built-in types.
276 */
277 if (gennametypedescriptor == gennameown
278 || force_xer) {
279 // the type has its own type descriptor
280 bool generate_ber = has_encoding(CT_BER) && enable_ber();
281 const string& gennameberdescriptor = get_genname_berdescriptor();
282 if (generate_ber && gennameberdescriptor == gennameown)
283 generate_code_berdescriptor(target);
284
285 bool generate_raw = has_encoding(CT_RAW) && enable_raw();
286 const string& gennamerawdescriptor = get_genname_rawdescriptor();
287 if (generate_raw && gennamerawdescriptor == gennameown)
288 generate_code_rawdescriptor(target);
289
290 bool generate_text = has_encoding(CT_TEXT) && enable_text();
291 const string& gennametextdescriptor = get_genname_textdescriptor();
292 if (generate_text && gennametextdescriptor == gennameown)
293 generate_code_textdescriptor(target);
294
295 bool generate_xer = has_encoding(CT_XER) && enable_xer();
296 const string& gennamexerdescriptor = get_genname_xerdescriptor();
297 if (generate_xer && gennamexerdescriptor == gennameown)
298 generate_code_xerdescriptor(target);
299 else target->source.global_vars=mputprintf(target->source.global_vars,
300 "// No XER for %s\n", gennamexerdescriptor.c_str());
301
302 const string& gennamejsondescriptor = get_genname_jsondescriptor();
303 bool generate_json = has_encoding(CT_JSON) && enable_json() &&
304 gennamejsondescriptor == gennameown;
305 if (generate_json) {
306 generate_code_jsondescriptor(target);
307 }
308
309 // the type descriptor must be always exported.
310 // embedded (possibly unnamed) types can be referenced from other modules
311 // using field/array sub-references
312 target->header.global_vars = mputprintf(target->header.global_vars,
313 "extern const TTCN_Typedescriptor_t %s_descr_;\n", gennameown_str);
314 target->source.global_vars = mputprintf(target->source.global_vars,
315 "const TTCN_Typedescriptor_t %s_descr_ = { \"%s\", ", gennameown_str,
316 get_fullname().c_str());
317
318 if(generate_ber)
319 target->source.global_vars=mputprintf
320 (target->source.global_vars,
321 "&%s_ber_, ", gennameberdescriptor.c_str());
322 else
323 target->source.global_vars=mputstr
324 (target->source.global_vars, "NULL, ");
325
326 if (generate_raw)
327 target->source.global_vars=mputprintf
328 (target->source.global_vars,
329 "&%s_raw_, ", gennamerawdescriptor.c_str());
330 else
331 target->source.global_vars=mputstr
332 (target->source.global_vars, "NULL, ");
333
334 if (generate_text)
335 target->source.global_vars=mputprintf
336 (target->source.global_vars,
337 "&%s_text_, ", gennametextdescriptor.c_str());
338 else
339 target->source.global_vars=mputstr
340 (target->source.global_vars, "NULL, ");
341
342 if (generate_xer)
343 target->source.global_vars = mputprintf(target->source.global_vars,
344 "&%s_xer_, ", gennamexerdescriptor.c_str());
345 else
346 target->source.global_vars = mputprintf(target->source.global_vars,
347 "NULL, ");
348
349 if (generate_json) {
350 target->source.global_vars = mputprintf(target->source.global_vars,
351 "&%s_json_, ", gennamejsondescriptor.c_str());
352 } else {
353 switch(get_type_refd_last()->typetype) {
354 case T_BOOL:
355 case T_INT:
356 case T_INT_A:
357 case T_REAL:
358 case T_BSTR:
359 case T_BSTR_A:
360 case T_HSTR:
361 case T_OSTR:
362 case T_CSTR:
363 case T_USTR:
364 case T_UTF8STRING:
365 case T_NUMERICSTRING:
366 case T_PRINTABLESTRING:
367 case T_TELETEXSTRING:
368 case T_VIDEOTEXSTRING:
369 case T_IA5STRING:
370 case T_GRAPHICSTRING:
371 case T_VISIBLESTRING:
372 case T_GENERALSTRING:
373 case T_UNIVERSALSTRING:
374 case T_BMPSTRING:
375 case T_VERDICT:
376 case T_NULL:
377 case T_OID:
378 case T_ROID:
379 case T_ANY:
380 // use predefined JSON descriptors instead of null pointers for basic types
381 target->source.global_vars = mputprintf(target->source.global_vars,
382 "&%s_json_, ", gennamejsondescriptor.c_str());
383 break;
384 case T_ENUM_T:
385 case T_ENUM_A:
386 // use a predefined JSON descriptor for enumerated types
387 target->source.global_vars = mputstr(target->source.global_vars,
388 "&ENUMERATED_json_, ");
389 break;
390 default:
391 target->source.global_vars = mputstr(target->source.global_vars,
392 "NULL, ");
393 }
394 }
395
396 if (T_SEQOF == get_type_refd_last()->typetype ||
397 T_SETOF == get_type_refd_last()->typetype) {
398 target->source.global_vars=mputprintf(target->source.global_vars,
399 "&%s_descr_, ", get_type_refd_last()->u.seof.ofType->get_genname_typedescriptor(my_scope).c_str());
400 }
401 else {
402 target->source.global_vars = mputstr(target->source.global_vars,
403 "NULL, ");
404 }
405
406 target->source.global_vars=mputprintf(target->source.global_vars,
407 "TTCN_Typedescriptor_t::%s };\n"
408 #ifndef NDEBUG
409 "\n"
410 #endif
411 , get_genname_typedescr_asnbasetype());
412 } else {
413 // the type uses the type descriptor of another type
414 if (needs_alias()) {
415 // we need to generate an aliased type descriptor only if the type is
416 // directly accessible by the user
417 target->header.global_vars = mputprintf(target->header.global_vars,
418 "extern const TTCN_Typedescriptor_t& %s_descr_;\n", gennameown_str);
419 target->source.global_vars = mputprintf(target->source.global_vars,
420 "const TTCN_Typedescriptor_t& %s_descr_ = %s_descr_;\n",
421 gennameown_str, gennametypedescriptor.c_str());
422 }
423 #ifndef NDEBUG
424 else {
425 target->source.global_vars = mputprintf( target->source.global_vars,
426 "// %s_descr_ not needed, use %s_descr_\n",
427 gennameown_str, gennametypedescriptor.c_str());
428 } // if(needs_alias())
429 #endif
430
431 } // if (gennameown == gennametypedescriptor)
432 }
433
434 void Type::generate_code_berdescriptor(output_struct *target)
435 {
436 const char *gennameown_str = get_genname_own().c_str();
437 char *str = mprintf("static const ASN_Tag_t %s_tag_[] = { ",
438 gennameown_str);
439 Tags *joinedtags = build_tags_joined();
440 size_t tagarraysize = joinedtags->get_nof_tags();
441 for (size_t i = 0; i < tagarraysize; i++) {
442 if (i > 0) str = mputstr(str, ", ");
443 Tag *t_tag = joinedtags->get_tag_byIndex(i);
444 str = mputprintf(str, "{ %s, %su }", t_tag->get_tagclass_str(),
445 Int2string(t_tag->get_tagvalue()).c_str());
446 }
447 delete joinedtags;
448 str = mputstr(str, "};\n");
449 target->source.global_vars = mputstr(target->source.global_vars, str);
450 Free(str);
451 target->header.global_vars = mputprintf(target->header.global_vars,
452 "extern const ASN_BERdescriptor_t %s_ber_;\n", gennameown_str);
453 target->source.global_vars = mputprintf(target->source.global_vars,
454 "const ASN_BERdescriptor_t %s_ber_ = { %luu, %s_tag_ };\n",
455 gennameown_str, (unsigned long)tagarraysize, gennameown_str);
456 }
457
458 static const char* whitespace_action[3] = {"PRESERVE", "REPLACE", "COLLAPSE"};
459
460 extern void change_name(string &name, XerAttributes::NameChange change);
461 // implemented in Type_chk.cc
462
463 void Type::generate_code_xerdescriptor(output_struct* target)
464 {
465 const char *gennameown_str = get_genname_own().c_str();
466 target->header.global_vars = mputprintf(target->header.global_vars,
467 "extern const XERdescriptor_t %s_xer_;\n", gennameown_str);
468 string last_s;
469
470 Type *ot = this;
471 for(;;) {
472 string full_s = ot->get_fullname();
473 size_t dot_pos = full_s.rfind('.');
474 if (full_s.size() == dot_pos) dot_pos = 0;
475 last_s = full_s.substr(dot_pos+1); // FIXME: may be better to use replace(pos, n, s)
476
477 if ('&'==last_s[0] // object class field ?
478 ||'<'==last_s[0]) { // <oftype> and the like
479 if (ot->is_ref()) {
480 ot = ot->get_type_refd();
481 /* Fetch the referenced type and use that. Do not use
482 * get_type_refd_last() here. In case of a record-of user-defined type:
483 * <ttcn>type integer MyInt; type record of MyInt MyRecof;</ttcn>
484 * we want "MyInt" and not "integer" */
485 continue;
486 }
487 else { // probably a built-in type, punt with the C++ class name
488 last_s = ot->get_genname_value(0);
489 break;
490 }
491 }
492 break;
493 }
494
495 // Name for basic XER which ignores all the EXER fanciness
496 string bxer_name(last_s);
497
498 long ns_index = -1;
499 //fprintf(stderr, "%2d gno='%s'\tfn='%s'\n", typetype, gennameown_str, last_s.c_str());
500 int atrib=0, any_atr=0, any_elem=0, base64=0, decimal=0, embed=0, list=0,
501 text=0, untagged=0, use_nil=0, use_number=0, use_order=0, use_qname=0,
502 use_type_attr=0, ws=0, has_1untag=0, form_qualified=0, any_from=0,
503 any_except=0, nof_ns_uris=0, blocked=0;
504 const char* dfe_str = 0;
505 char** ns_uris = 0;
506 char* oftype_descr_name = 0;
507 if (xerattrib) {
508 change_name(last_s, xerattrib->name_);
509
510 if (xerattrib->namespace_.uri && xerattrib->namespace_.prefix) {
511 ns_index = my_scope->get_scope_mod()->get_ns_index(
512 xerattrib->namespace_.prefix);
513 // This is known to have succeeded
514 }
515
516 any_atr = has_aa(xerattrib);
517 any_elem= has_ae(xerattrib);
518 atrib = xerattrib->attribute_;
519 base64 = xerattrib->base64_;
520 blocked = xerattrib->abstract_ || xerattrib->block_;
521 decimal = xerattrib->decimal_;
522 embed = xerattrib->embedValues_;
523 form_qualified = (xerattrib->form_ & XerAttributes::QUALIFIED)
524 || (xerattrib->element_); // a global element is always qualified
525 list = xerattrib->list_;
526 untagged= xerattrib->untagged_;
527 ws = xerattrib->whitespace_;
528 // only set TEXT if it has no TextToBeUsed (plain "text" for a bool)
529 text = xerattrib->num_text_ && xerattrib->text_->prefix == 0;
530 use_nil = xerattrib->useNil_;
531 use_number= xerattrib->useNumber_;
532 use_order = xerattrib->useOrder_;
533 use_qname = xerattrib->useQName_;
534 // In ASN.1, the use of a type identification attribute is optional
535 // (encoder's choice) for USE-UNION. However, TTCN-3 removes this choice:
536 // it is mandatory to use it when possible (valid choice for ASN.1 too).
537 use_type_attr = xerattrib->useType_ || xerattrib->useUnion_;
538
539 if (xerattrib->defaultValue_) {
540 Type *t = xerattrib->defaultValue_->get_my_governor();
541 dfe_str = xerattrib->defaultValue_->get_genname_own().c_str();
542 const_def cdef;
543 Code::init_cdef(&cdef);
544 t->generate_code_object(&cdef, xerattrib->defaultValue_);
545 cdef.init = xerattrib->defaultValue_->generate_code_init
546 (cdef.init, xerattrib->defaultValue_->get_lhs_name().c_str());
547 Code::merge_cdef(target, &cdef);
548 Code::free_cdef(&cdef);
549 }
550
551 if (any_elem) {
552 // data needed for "anyElement from ..." and "anyElement except ..." encoding instructions
553 any_from = xerattrib->anyElement_.type_ == NamespaceRestriction::FROM;
554 any_except = xerattrib->anyElement_.type_ == NamespaceRestriction::EXCEPT;
555 nof_ns_uris = xerattrib->anyElement_.nElements_;
556 ns_uris = xerattrib->anyElement_.uris_;
557 }
558 else if (any_atr) {
559 // data needed for "anyAttributes from ..." and "anyAttributes except ..." encoding instructions
560 any_from = xerattrib->anyAttributes_.type_ == NamespaceRestriction::FROM;
561 any_except = xerattrib->anyAttributes_.type_ == NamespaceRestriction::EXCEPT;
562 nof_ns_uris = xerattrib->anyAttributes_.nElements_;
563 ns_uris = xerattrib->anyAttributes_.uris_;
564 }
565 }
566 else if (ownertype == OT_COMP_FIELD
567 && parent_type && parent_type->xerattrib) {
568 //no xerattrib, this must be an element; apply element default
569 form_qualified = (parent_type->xerattrib->form_
570 & XerAttributes::ELEMENT_DEFAULT_QUALIFIED);
571 }
572
573 Type *last = get_type_refd_last();
574 has_1untag= last->is_secho() && last->u.secho.has_single_charenc; // does not come from xerattrib
575
576 /* If this is a string type whose grandparent is a record
577 * (containing a record-of (this)string) which has EMBED-VALUES,
578 * then reuse this string's any_element field in the XER descriptor
579 * to signal this (ANY-ELEMENT causes the tag to be omitted,
580 * which is what we want in EMBED-VALUES) */
581 if (parent_type && parent_type->parent_type) switch (last->typetype) {
582 case T_UTF8STRING:
583 case T_USTR: // the TTCN equivalent of UTF8String
584 if ( T_SEQOF == parent_type->typetype
585 && (T_SEQ_T == parent_type->parent_type->typetype
586 ||T_SEQ_A == parent_type->parent_type->typetype)
587 && parent_type->parent_type->xerattrib) {
588 embed |= (parent_type->parent_type->xerattrib->embedValues_);
589 }
590 break;
591 default:
592 break;
593 }
594 size_t last_len = 2 + last_s.size(); // 2 for > \n
595 size_t bxer_len = 2 + bxer_name.size(); // 2 for > \n
596
597 if ((T_SEQOF == last->typetype || T_SETOF == last->typetype) &&
598 T_ANYTYPE != last->u.seof.ofType->get_type_refd_last()->typetype) {
599 // anytypes don't have XER descriptors
600 oftype_descr_name = mprintf("&%s_xer_", last->u.seof.ofType->get_genname_typedescriptor(my_scope).c_str());
601 }
602
603 // Generate a separate variable for the namespace URIs, if there are any
604 char* ns_uris_var = 0;
605 if (ns_uris && nof_ns_uris) {
606 ns_uris_var = mputprintf(ns_uris_var, "%s_ns_uris_", gennameown_str);
607 target->source.global_vars = mputprintf(target->source.global_vars,
608 "const char* %s[] = {", ns_uris_var);
609 for (int idx = 0; idx < nof_ns_uris; ++idx) {
610 // The unqualified namespace is sometimes stored as an empty string and
611 // sometimes as a null pointer -> unify it, always store it as an empty string
612 target->source.global_vars = mputprintf(target->source.global_vars,
613 "%s\"%s\"", (idx != 0) ? ", " : "", ns_uris[idx] ? ns_uris[idx] : "");
614 }
615 target->source.global_vars = mputstrn(target->source.global_vars, "};\n", 3);
616 }
617
618 // Generate the XER descriptor itself
619 target->source.global_vars = mputprintf(target->source.global_vars,
620 "const XERdescriptor_t %s_xer_ = { {\"%s>\\n\", \"%s>\\n\"},"
621 " {%lu, %lu}, %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s, WHITESPACE_%s, %c%s, "
622 "&%s, %ld, %u, %s, %s };\n",
623 gennameown_str,
624 bxer_name.c_str(), last_s.c_str(), // names
625 (unsigned long)bxer_len, (unsigned long)last_len, // lengths
626 (any_atr ? "ANY_ATTRIBUTES" : "0"),
627 (any_elem ? " |ANY_ELEMENT" : ""),
628 (atrib ? " |XER_ATTRIBUTE" : ""),
629 (base64 ? " |BASE_64" : ""),
630 (blocked ? " |BLOCKED" : ""),
631 (decimal ? " |XER_DECIMAL" : ""),
632 (embed ? " |EMBED_VALUES" : ""),
633 (list ? " |XER_LIST" : ""),
634 (text ? " |XER_TEXT" : ""),
635 (untagged ? " |UNTAGGED" : ""),
636 (use_nil ? " |USE_NIL" : ""),
637 (use_number ? " |USE_NUMBER" : ""),
638 (use_order ? " |USE_ORDER" : ""),
639 (use_qname ? " |USE_QNAME" : ""),
640 (use_type_attr ? " |USE_TYPE_ATTR" : ""),
641 (has_1untag ? " |HAS_1UNTAGGED" : ""),
642 (form_qualified ? "" : " |FORM_UNQUALIFIED"),
643 (any_from ? " |ANY_FROM" : ""),
644 (any_except ? " |ANY_EXCEPT" : ""),
645 (is_optional_field() ? " |XER_OPTIONAL" : ""),
646 whitespace_action[ws],
647 (dfe_str ? '&' : ' '), (dfe_str ? dfe_str : "NULL"),
648 "module_object",
649 ns_index,
650 nof_ns_uris,
651 (ns_uris_var ? ns_uris_var : "NULL"),
652 (oftype_descr_name ? oftype_descr_name : "NULL")
653 );
654
655 Free(ns_uris_var);
656 Free(oftype_descr_name);
657 }
658
659 void Type::generate_code_rawdescriptor(output_struct *target)
660 {
661 const char *gennameown_str = get_genname_own().c_str();
662 target->header.global_vars = mputprintf(target->header.global_vars,
663 "extern const TTCN_RAWdescriptor_t %s_raw_;\n", gennameown_str);
664 char *str = mprintf("const TTCN_RAWdescriptor_t %s_raw_ = {",
665 gennameown_str);
666 if (rawattrib->intx) {
667 str = mputstr(str, "RAW_INTX,");
668 }
669 else {
670 str = mputprintf(str, "%d,", rawattrib->fieldlength);
671 }
672 if (rawattrib->comp == XDEFCOMPL) str = mputstr(str, "SG_2COMPL,");
673 else if (rawattrib->comp == XDEFSIGNBIT) str = mputstr(str, "SG_SG_BIT,");
674 else str = mputstr(str, "SG_NO,");
675 if (rawattrib->byteorder == XDEFLAST) str = mputstr(str, "ORDER_MSB,");
676 else str = mputstr(str, "ORDER_LSB,");
677 if (rawattrib->align == XDEFLEFT) str = mputstr(str, "ORDER_MSB,");
678 else str = mputstr(str, "ORDER_LSB,");
679 if (rawattrib->bitorderinfield == XDEFMSB)
680 str = mputstr(str, "ORDER_MSB,");
681 else str = mputstr(str, "ORDER_LSB,");
682 if (rawattrib->bitorderinoctet == XDEFMSB)
683 str = mputstr(str, "ORDER_MSB,");
684 else str = mputstr(str, "ORDER_LSB,");
685 if (rawattrib->extension_bit == XDEFYES)
686 str = mputstr(str, "EXT_BIT_YES,");
687 else if (rawattrib->extension_bit == XDEFREVERSE)
688 str = mputstr(str, "EXT_BIT_REVERSE,");
689 else str = mputstr(str, "EXT_BIT_NO,");
690 if (rawattrib->hexorder == XDEFHIGH) str = mputstr(str, "ORDER_MSB,");
691 else str = mputstr(str, "ORDER_LSB,");
692 if (rawattrib->fieldorder == XDEFMSB) str = mputstr(str, "ORDER_MSB,");
693 else str = mputstr(str, "ORDER_LSB,");
694 if (rawattrib->topleveleind) {
695 if (rawattrib->toplevel.bitorder==XDEFLSB)
696 str = mputstr(str, "TOP_BIT_LEFT,");
697 else str = mputstr(str, "TOP_BIT_RIGHT,");
698 } else str = mputstr(str, "TOP_BIT_INHERITED,");
699 str = mputprintf(str, "%d,", rawattrib->padding);
700 str = mputprintf(str, "%d,", rawattrib->prepadding);
701 str = mputprintf(str, "%d,", rawattrib->ptroffset);
702 str = mputprintf(str, "%d,", rawattrib->unit);
703 str = mputprintf(str, "%d,", rawattrib->padding_pattern_length);
704 if (rawattrib->padding_pattern_length > 0)
705 str = mputprintf(str, "%s,", my_scope->get_scope_mod_gen()
706 ->add_padding_pattern(string(rawattrib->padding_pattern)).c_str());
707 else str = mputstr(str, "NULL,");
708 str = mputprintf(str, "%d};\n", rawattrib->length_restrition);
709 target->source.global_vars = mputstr(target->source.global_vars, str);
710 Free(str);
711 }
712
713 void Type::generate_code_textdescriptor(output_struct *target)
714 {
715 const char *gennameown_str = get_genname_own().c_str();
716 char *union_member_name=NULL;
717 Common::Module *mymod=my_scope->get_scope_mod();
718 Type *t = get_type_refd_last();
719 switch (t->typetype) {
720 case T_BOOL:
721 if (textattrib->true_params || textattrib->false_params) {
722 target->source.global_vars = mputprintf(target->source.global_vars,
723 "static const TTCN_TEXTdescriptor_bool %s_bool_ = {", gennameown_str);
724 if (textattrib->true_params &&
725 textattrib->true_params->encode_token) {
726 target->source.global_vars = mputprintf(target->source.global_vars,
727 "&%s,", mymod->add_charstring_literal(
728 string(textattrib->true_params->encode_token)).c_str());
729 } else {
730 target->source.global_vars=mputstr(target->source.global_vars,
731 "NULL,");
732 }
733 if (textattrib->true_params &&
734 textattrib->true_params->decode_token) {
735 char *pstr = make_posix_str_code(
736 textattrib->true_params->decode_token,
737 textattrib->true_params->case_sensitive);
738 target->source.global_vars = mputprintf(target->source.global_vars,
739 "&%s,", mymod->add_matching_literal(string(pstr)).c_str());
740 Free(pstr);
741 } else if (textattrib->true_params &&
742 !textattrib->true_params->case_sensitive) {
743 target->source.global_vars = mputprintf(target->source.global_vars,
744 "&%s,", mymod->add_matching_literal(
745 string("N^(true).*$")).c_str());
746 } else {
747 target->source.global_vars = mputstr(target->source.global_vars,
748 "NULL,");
749 }
750 if (textattrib->false_params &&
751 textattrib->false_params->encode_token) {
752 target->source.global_vars = mputprintf(target->source.global_vars,
753 "&%s,",mymod->add_charstring_literal(
754 string(textattrib->false_params->encode_token)).c_str());
755 } else {
756 target->source.global_vars = mputstr(target->source.global_vars,
757 "NULL,");
758 }
759 if (textattrib->false_params &&
760 textattrib->false_params->decode_token) {
761 char *pstr = make_posix_str_code(
762 textattrib->false_params->decode_token,
763 textattrib->false_params->case_sensitive);
764 target->source.global_vars=mputprintf(target->source.global_vars,
765 "&%s};\n", mymod->add_matching_literal(string(pstr)).c_str());
766 Free(pstr);
767 } else if (textattrib->false_params &&
768 !textattrib->false_params->case_sensitive) {
769 target->source.global_vars = mputprintf(target->source.global_vars,
770 "&%s};\n", mymod->add_matching_literal(
771 string("N^(false).*$")).c_str());
772 } else {
773 target->source.global_vars = mputstr(target->source.global_vars,
774 "NULL};\n");
775 }
776 union_member_name = mprintf("(TTCN_TEXTdescriptor_param_values*)"
777 "&%s_bool_", gennameown_str);
778 }
779 break;
780 case T_ENUM_T:
781 target->source.global_vars = mputprintf(target->source.global_vars,
782 "static const TTCN_TEXTdescriptor_enum %s_enum_[] = { ",
783 gennameown_str);
784 for (size_t i = 0; i < t->u.enums.eis->get_nof_eis(); i++) {
785 if (i > 0) target->source.global_vars =
786 mputstr(target->source.global_vars, ", ");
787 target->source.global_vars =
788 mputstr(target->source.global_vars, "{ ");
789 if (textattrib->field_params && textattrib->field_params[i] &&
790 textattrib->field_params[i]->value.encode_token) {
791 // the encode token is present
792 target->source.global_vars = mputprintf(target->source.global_vars,
793 "&%s, ", mymod->add_charstring_literal(
794 string(textattrib->field_params[i]->value.encode_token)).c_str());
795 } else {
796 // the encode token is not present: generate a NULL pointer and the
797 // RTE will substitute the enumerated value
798 target->source.global_vars = mputstr(target->source.global_vars,
799 "NULL, ");
800 }
801 // a pattern must be always present for decoding
802 const char *decode_token;
803 bool case_sensitive;
804 if (textattrib->field_params && textattrib->field_params[i]) {
805 if (textattrib->field_params[i]->value.decode_token) {
806 // the decode token is present
807 decode_token = textattrib->field_params[i]->value.decode_token;
808 } else {
809 // there is an attribute for the enumerated value,
810 // but the decode token is omitted
811 // use the value as decode token
812 decode_token = t->u.enums.eis->get_ei_byIndex(i)->get_name()
813 .get_dispname().c_str();
814 }
815 // take the case sensitivity from the attribute
816 case_sensitive = textattrib->field_params[i]->value.case_sensitive;
817 } else {
818 // there is no attribute for the enumerated value
819 // use the value as decode token
820 decode_token = t->u.enums.eis->get_ei_byIndex(i)->get_name()
821 .get_dispname().c_str();
822 // it is always case sensitive
823 case_sensitive = true;
824 }
825 char *pstr = make_posix_str_code(decode_token, case_sensitive);
826 target->source.global_vars = mputprintf(target->source.global_vars,
827 " &%s }", mymod->add_matching_literal(string(pstr)).c_str());
828 Free(pstr);
829 }
830 target->source.global_vars = mputstr(target->source.global_vars,
831 " };\n");
832 union_member_name = mprintf(
833 "(TTCN_TEXTdescriptor_param_values*)%s_enum_", gennameown_str);
834 break;
835 case T_INT:
836 case T_CSTR:
837 if(textattrib->coding_params.leading_zero ||
838 textattrib->coding_params.min_length!=-1 ||
839 textattrib->coding_params.max_length!=-1 ||
840 textattrib->coding_params.convert!=0 ||
841 textattrib->coding_params.just!=1 ||
842 textattrib->decoding_params.leading_zero ||
843 textattrib->decoding_params.min_length!=-1 ||
844 textattrib->decoding_params.max_length!=-1 ||
845 textattrib->decoding_params.convert!=0 ||
846 textattrib->decoding_params.just!=1 ){
847 target->source.global_vars=mputprintf(target->source.global_vars,
848 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
849 gennameown_str);
850 target->source.global_vars=mputprintf(target->source.global_vars,
851 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
852 ,textattrib->coding_params.leading_zero?"true":"false"
853 ,textattrib->coding_params.repeatable?"true":"false"
854 ,textattrib->coding_params.min_length
855 ,textattrib->coding_params.max_length
856 ,textattrib->coding_params.convert
857 ,textattrib->coding_params.just
858 ,textattrib->decoding_params.leading_zero?"true":"false"
859 ,textattrib->decoding_params.repeatable?"true":"false"
860 ,textattrib->decoding_params.min_length
861 ,textattrib->decoding_params.max_length
862 ,textattrib->decoding_params.convert
863 ,textattrib->decoding_params.just);
864
865 union_member_name=mprintf("&%s_par_", gennameown_str);
866 }
867 break;
868 case T_SEQOF:
869 case T_SETOF:
870 target->source.global_vars=mputprintf(target->source.global_vars,
871 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
872 gennameown_str);
873 target->source.global_vars=mputprintf(target->source.global_vars,
874 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
875 ,textattrib->coding_params.leading_zero?"true":"false"
876 ,textattrib->coding_params.repeatable?"true":"false"
877 ,textattrib->coding_params.min_length
878 ,textattrib->coding_params.max_length
879 ,textattrib->coding_params.convert
880 ,textattrib->coding_params.just
881 ,textattrib->decoding_params.leading_zero?"true":"false"
882 ,textattrib->decoding_params.repeatable?"true":"false"
883 ,textattrib->decoding_params.min_length
884 ,textattrib->decoding_params.max_length
885 ,textattrib->decoding_params.convert
886 ,textattrib->decoding_params.just);
887
888 union_member_name=mprintf("&%s_par_", gennameown_str);
889 break;
890 default:
891 break;
892 }
893
894 target->header.global_vars = mputprintf(target->header.global_vars,
895 "extern const TTCN_TEXTdescriptor_t %s_text_;\n", gennameown_str);
896 target->source.global_vars = mputprintf(target->source.global_vars,
897 "const TTCN_TEXTdescriptor_t %s_text_ = {", gennameown_str);
898
899 if (textattrib->begin_val && textattrib->begin_val->encode_token) {
900 target->source.global_vars = mputprintf(target->source.global_vars,
901 "&%s,", mymod->add_charstring_literal(
902 string(textattrib->begin_val->encode_token)).c_str());
903 } else {
904 target->source.global_vars = mputstr(target->source.global_vars,
905 "NULL,");
906 }
907 if(textattrib->begin_val && textattrib->begin_val->decode_token){
908 char *pstr = make_posix_str_code(
909 textattrib->begin_val->decode_token,
910 textattrib->begin_val->case_sensitive);
911 target->source.global_vars = mputprintf(target->source.global_vars,
912 "&%s,", mymod->add_matching_literal(string(pstr)).c_str());
913 Free(pstr);
914 } else {
915 target->source.global_vars = mputstr(target->source.global_vars,
916 "NULL,");
917 }
918 if (textattrib->end_val && textattrib->end_val->encode_token) {
919 target->source.global_vars = mputprintf(target->source.global_vars,
920 "&%s,",mymod->add_charstring_literal(
921 string(textattrib->end_val->encode_token)).c_str());
922 } else {
923 target->source.global_vars = mputstr(target->source.global_vars,
924 "NULL,");
925 }
926 if (textattrib->end_val && textattrib->end_val->decode_token) {
927 char *pstr = make_posix_str_code(
928 textattrib->end_val->decode_token,
929 textattrib->end_val->case_sensitive);
930 target->source.global_vars = mputprintf(target->source.global_vars,
931 "&%s,", mymod->add_matching_literal(string(pstr)).c_str());
932 Free(pstr);
933 } else {
934 target->source.global_vars = mputstr(target->source.global_vars,
935 "NULL,");
936 }
937
938 if (textattrib->separator_val &&
939 textattrib->separator_val->encode_token) {
940 target->source.global_vars = mputprintf(target->source.global_vars,
941 "&%s,", mymod->add_charstring_literal(
942 string(textattrib->separator_val->encode_token)).c_str());
943 } else {
944 target->source.global_vars = mputstr(target->source.global_vars,
945 "NULL,");
946 }
947 if(textattrib->separator_val &&
948 textattrib->separator_val->decode_token) {
949 char *pstr = make_posix_str_code(
950 textattrib->separator_val->decode_token,
951 textattrib->separator_val->case_sensitive);
952 target->source.global_vars = mputprintf(target->source.global_vars,
953 "&%s,", mymod->add_matching_literal(string(pstr)).c_str());
954 Free(pstr);
955 } else {
956 target->source.global_vars=mputstr(target->source.global_vars,
957 "NULL,");
958 }
959
960 if (textattrib->decode_token) {
961 char *pstr = make_posix_str_code(textattrib->decode_token,
962 textattrib->case_sensitive);
963 target->source.global_vars = mputprintf(target->source.global_vars,
964 "&%s,", mymod->add_matching_literal(string(pstr)).c_str());
965 Free(pstr);
966 } else {
967 target->source.global_vars = mputstr(target->source.global_vars,
968 "NULL,");
969 }
970
971 if (union_member_name) {
972 target->source.global_vars = mputprintf(target->source.global_vars,
973 "{%s}};\n", union_member_name);
974 Free(union_member_name);
975 } else {
976 target->source.global_vars = mputstr(target->source.global_vars,
977 "{NULL}};\n");
978 }
979 }
980
981 void Type::generate_code_jsondescriptor(output_struct *target)
982 {
983 target->header.global_vars = mputprintf(target->header.global_vars,
984 "extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str());
985
986 if (NULL == jsonattrib) {
987 target->source.global_vars = mputprintf(target->source.global_vars,
988 "const TTCN_JSONdescriptor_t %s_json_ = { false, NULL, false, NULL, false };\n"
989 , get_genname_own().c_str());
990 } else {
991 char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
992 char* def_val = jsonattrib->default_value ?
993 mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL;
994 target->source.global_vars = mputprintf(target->source.global_vars,
995 "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s };\n"
996 , get_genname_own().c_str()
997 , jsonattrib->omit_as_null ? "true" : "false"
998 , alias ? alias : "NULL"
999 , jsonattrib->as_value ? "true" : "false"
1000 , def_val ? def_val : "NULL"
1001 , jsonattrib->metainfo_unbound ? "true" : "false");
1002 Free(alias);
1003 Free(def_val);
1004 }
1005
1006 }
1007
1008 void Type::generate_code_alias(output_struct *target)
1009 {
1010 if (!needs_alias()) return;
1011
1012 const string& t_genname = get_genname_value(my_scope);
1013 const char *refd_name = t_genname.c_str();
1014 const char *own_name = get_genname_own().c_str();
1015
1016 Type *t_last = get_type_refd_last();
1017 switch (t_last->typetype) {
1018 case T_PORT: // only value class exists
1019 target->header.typedefs = mputprintf(target->header.typedefs,
1020 "typedef %s %s;\n", refd_name, own_name);
1021 break;
1022 case T_SIGNATURE: // special classes (7 pcs.) exist
1023 target->header.typedefs = mputprintf(target->header.typedefs,
1024 "typedef %s_call %s_call;\n"
1025 "typedef %s_call_redirect %s_call_redirect;\n",
1026 refd_name, own_name, refd_name, own_name);
1027 if (!t_last->is_nonblocking_signature()) {
1028 target->header.typedefs = mputprintf(target->header.typedefs,
1029 "typedef %s_reply %s_reply;\n"
1030 "typedef %s_reply_redirect %s_reply_redirect;\n",
1031 refd_name, own_name, refd_name, own_name);
1032 }
1033 if (t_last->get_signature_exceptions()) {
1034 target->header.typedefs = mputprintf(target->header.typedefs,
1035 "typedef %s_exception %s_exception;\n"
1036 "typedef %s_exception_template %s_exception_template;\n",
1037 refd_name, own_name, refd_name, own_name);
1038 }
1039 target->header.typedefs = mputprintf(target->header.typedefs,
1040 "typedef %s_template %s_template;\n",
1041 refd_name, own_name);
1042 break;
1043 default: // value and template classes exist
1044 target->header.typedefs = mputprintf(target->header.typedefs,
1045 #ifndef NDEBUG
1046 "// written by %s in " __FILE__ " at %d\n"
1047 #endif
1048 "typedef %s %s;\n"
1049 "typedef %s_template %s_template;\n",
1050 #ifndef NDEBUG
1051 __FUNCTION__, __LINE__,
1052 #endif
1053 refd_name, own_name, refd_name, own_name);
1054 break;
1055 }
1056 }
1057
1058 void Type::generate_code_Enum(output_struct *target)
1059 {
1060 stringpool pool;
1061 enum_def e_def;
1062 memset(&e_def, 0, sizeof(e_def));
1063 e_def.name = get_genname_own().c_str();
1064 e_def.dispname = get_fullname().c_str();
1065 e_def.isASN1 = is_asn1();
1066 e_def.nElements = u.enums.eis->get_nof_eis();
1067 e_def.elements = (enum_field*)
1068 Malloc(e_def.nElements*sizeof(*e_def.elements));
1069 e_def.firstUnused = u.enums.first_unused;
1070 e_def.secondUnused = u.enums.second_unused;
1071 e_def.hasText = textattrib!=NULL;
1072 e_def.hasRaw = rawattrib!=NULL;
1073 e_def.hasXer = has_encoding(CT_XER);
1074 e_def.hasJson = has_encoding(CT_JSON);
1075 if (xerattrib) {
1076 e_def.xerUseNumber = xerattrib->useNumber_;
1077 }
1078 for (size_t i = 0; i < e_def.nElements; i++) {
1079 EnumItem *ei = u.enums.eis->get_ei_byIndex(i);
1080 e_def.elements[i].name = ei->get_name().get_name().c_str();
1081 e_def.elements[i].dispname = ei->get_name().get_ttcnname().c_str();
1082 if (ei->get_text().empty()) e_def.elements[i].text = 0;
1083 else {
1084 e_def.xerText = TRUE;
1085 e_def.elements[i].text = ei->get_text().c_str();
1086 }
1087 e_def.elements[i].value = ei->get_value()->get_val_Int()->get_val();
1088 }
1089
1090 defEnumClass(&e_def, target);
1091 defEnumTemplate(&e_def, target);
1092
1093 Free(e_def.elements);
1094 }
1095
1096 void Type::generate_code_Choice(output_struct *target)
1097 {
1098 stringpool pool;
1099 struct_def sdef;
1100 memset(&sdef, 0, sizeof(sdef));
1101 sdef.name = get_genname_own().c_str();
1102 sdef.dispname=get_fullname().c_str();
1103 if (T_ANYTYPE==typetype) {
1104 if (0 == get_nof_comps()) {
1105 //return; // don't generate code for empty anytype
1106 // XXX what to do with empty anytype ?
1107 // Easy: make sure it doesn't happen by filling it from the AST!
1108 }
1109 sdef.kind = ANYTYPE;
1110 }
1111 else sdef.kind = UNION;
1112 sdef.isASN1 = is_asn1();
1113 sdef.hasText = textattrib!=NULL;
1114 sdef.hasXer = has_encoding(CT_XER);
1115 sdef.hasJson = has_encoding(CT_JSON);
1116 sdef.has_opentypes = get_has_opentypes();
1117 sdef.opentype_outermost = get_is_opentype_outermost();
1118 sdef.ot = generate_code_ot(pool);
1119 sdef.nElements = get_nof_comps();
1120 sdef.isOptional = false;
1121 if (parent_type != NULL) {
1122 switch (parent_type->typetype) {
1123 case T_SEQ_T:
1124 case T_SEQ_A:
1125 case T_SET_T:
1126 case T_SET_A:
1127 for (size_t x = 0; x < parent_type->get_nof_comps(); ++x) {
1128 CompField * cf = parent_type->get_comp_byIndex(x);
1129 if (cf->get_type() == this && cf->get_is_optional()) {
1130 sdef.isOptional = true;
1131 break; // from the for loop
1132 }
1133 }
1134 break;
1135 default:
1136 break;
1137 }
1138 }
1139 sdef.elements = (struct_field*)
1140 Malloc(sdef.nElements*sizeof(*sdef.elements));
1141 memset(sdef.elements, 0, sdef.nElements*sizeof(*sdef.elements));
1142 sdef.exerMaybeEmptyIndex = -1;
1143 if (jsonattrib) {
1144 sdef.jsonAsValue = jsonattrib->as_value;
1145 }
1146 for(size_t i = 0; i < sdef.nElements; i++) {
1147 CompField *cf = get_comp_byIndex(i);
1148 const Identifier& id = cf->get_name();
1149 Type *cftype = cf->get_type();
1150 sdef.elements[i].type = pool.add(cftype->get_genname_value(my_scope));
1151 sdef.elements[i].typedescrname =
1152 pool.add(cftype->get_genname_typedescriptor(my_scope));
1153 sdef.elements[i].typegen = pool.add(cftype->get_genname_xerdescriptor());
1154 sdef.elements[i].name = id.get_name().c_str();
1155 sdef.elements[i].dispname = id.get_ttcnname().c_str();
1156 if (xerattrib) {
1157 if (cftype->has_empty_xml()) sdef.exerMaybeEmptyIndex = i;
1158 // This will overwrite lower values, which is what we want.
1159 }
1160 if (sdef.jsonAsValue) {
1161 // Determine the JSON value type of each field to make decoding faster
1162 typetype_t tt = cftype->get_type_refd_last()->typetype;
1163 switch(tt) {
1164 case T_INT:
1165 case T_INT_A:
1166 sdef.elements[i].jsonValueType = JSON_NUMBER;
1167 break;
1168 case T_REAL:
1169 sdef.elements[i].jsonValueType = JSON_NUMBER | JSON_STRING;
1170 break;
1171 case T_BOOL:
1172 sdef.elements[i].jsonValueType = JSON_BOOLEAN;
1173 break;
1174 case T_NULL:
1175 sdef.elements[i].jsonValueType = JSON_NULL;
1176 break;
1177 case T_BSTR:
1178 case T_BSTR_A:
1179 case T_HSTR:
1180 case T_OSTR:
1181 case T_CSTR:
1182 case T_USTR:
1183 case T_UTF8STRING:
1184 case T_NUMERICSTRING:
1185 case T_PRINTABLESTRING:
1186 case T_TELETEXSTRING:
1187 case T_VIDEOTEXSTRING:
1188 case T_IA5STRING:
1189 case T_GRAPHICSTRING:
1190 case T_VISIBLESTRING:
1191 case T_GENERALSTRING:
1192 case T_UNIVERSALSTRING:
1193 case T_BMPSTRING:
1194 case T_VERDICT:
1195 case T_ENUM_T:
1196 case T_ENUM_A:
1197 case T_OID:
1198 case T_ROID:
1199 case T_ANY:
1200 sdef.elements[i].jsonValueType = JSON_STRING;
1201 break;
1202 case T_SEQ_T:
1203 case T_SEQ_A:
1204 case T_SET_T:
1205 case T_SET_A:
1206 case T_CHOICE_T:
1207 case T_CHOICE_A:
1208 case T_ANYTYPE:
1209 case T_OPENTYPE:
1210 sdef.elements[i].jsonValueType = JSON_OBJECT;
1211 break;
1212 case T_SEQOF:
1213 case T_SETOF:
1214 case T_ARRAY:
1215 sdef.elements[i].jsonValueType = JSON_ARRAY;
1216 break;
1217 default:
1218 FATAL_ERROR("Type::generate_code_Choice - invalid field type %d", tt);
1219 }
1220 }
1221 if (cftype->jsonattrib) {
1222 sdef.elements[i].jsonAlias = cftype->jsonattrib->alias;
1223 if (sdef.jsonAsValue && cftype->jsonattrib->as_value) {
1224 // Override the JSON_OBJECT value given in the switch
1225 sdef.elements[i].jsonValueType = JSON_ANY_VALUE;
1226 }
1227 }
1228 }
1229 if(rawattrib) {
1230 copy_rawAST_to_struct(rawattrib,&(sdef.raw));
1231 sdef.hasRaw=true;
1232 // building taglist
1233 for(int c=0;c<rawattrib->taglist.nElements;c++){
1234 if(rawattrib->taglist.tag[c].nElements)
1235 sdef.raw.taglist.list[c].fields=
1236 (rawAST_coding_field_list*)
1237 Malloc(rawattrib->taglist.tag[c].nElements
1238 *sizeof(rawAST_coding_field_list));
1239 else sdef.raw.taglist.list[c].fields=NULL;
1240 sdef.raw.taglist.list[c].nElements=
1241 rawattrib->taglist.tag[c].nElements;
1242 sdef.raw.taglist.list[c].fieldName=
1243 rawattrib->taglist.tag[c].fieldName->get_name().c_str();
1244 Identifier *idf=rawattrib->taglist.tag[c].fieldName;
1245 sdef.raw.taglist.list[c].fieldnum=get_comp_index_byName(*idf);
1246 for(int a=0;a<rawattrib->taglist.tag[c].nElements;a++){
1247 rawAST_coding_field_list* key=
1248 sdef.raw.taglist.list[c].fields+a;
1249 key->nElements=
1250 rawattrib->taglist.tag[c].keyList[a].keyField->nElements+1;
1251 key->value=rawattrib->taglist.tag[c].keyList[a].value;
1252 key->start_pos=0;
1253 key->fields=(rawAST_coding_fields*)
1254 Malloc(key->nElements*sizeof(rawAST_coding_fields));
1255 CompField *cf=get_comp_byIndex(sdef.raw.taglist.list[c].fieldnum);
1256 Type *t=cf->get_type()->get_type_refd_last();
1257
1258 key->fields[0].nthfield = sdef.raw.taglist.list[c].fieldnum;
1259 key->fields[0].nthfieldname =
1260 rawattrib->taglist.tag[c].fieldName->get_name().c_str();
1261 key->fields[0].fieldtype = UNION_FIELD;
1262 key->fields[0].type = pool.add(t->get_genname_value(my_scope));
1263 key->fields[0].typedescr =
1264 pool.add(t->get_genname_typedescriptor(my_scope));
1265
1266 for (int b = 1; b < key->nElements; b++) {
1267 Identifier *idf2 =
1268 rawattrib->taglist.tag[c].keyList[a].keyField->names[b-1];
1269 size_t comp_index = t->get_comp_index_byName(*idf2);
1270 CompField *cf2 = t->get_comp_byIndex(comp_index);
1271 key->fields[b].nthfield = comp_index;
1272 key->fields[b].nthfieldname = idf2->get_name().c_str();
1273 if (t->typetype == T_CHOICE_T)
1274 key->fields[b].fieldtype = UNION_FIELD;
1275 else if (cf2->get_is_optional()){
1276 key->fields[b].fieldtype = OPTIONAL_FIELD;
1277 }else key->fields[b].fieldtype = MANDATORY_FIELD;
1278 Type *field_type = cf2->get_type();
1279 key->fields[b].type =
1280 pool.add(field_type->get_genname_value(my_scope));
1281 key->fields[b].typedescr =
1282 pool.add(field_type->get_genname_typedescriptor(my_scope));
1283 if (field_type->typetype == T_SEQ_T && field_type->rawattrib
1284 && (field_type->rawattrib->pointerto
1285 || field_type->rawattrib->lengthto_num))
1286 key->start_pos = -1;
1287
1288 if(t->typetype != T_CHOICE_T && t->typetype != T_SET_T){
1289 Type *t2;
1290 for(size_t i = 0; i < comp_index && key->start_pos >=0; i++)
1291 {
1292 t2 = t->get_comp_byIndex(i)->get_type();
1293 if(t2->get_raw_length() >= 0){
1294 if(t2->rawattrib)
1295 key->start_pos += t2->rawattrib->padding;
1296 key->start_pos += t2->get_raw_length();
1297 }else key->start_pos = -1;
1298 }
1299 }
1300 t = field_type->get_type_refd_last();
1301 }
1302 }
1303 }
1304 } else sdef.hasRaw=false;
1305 if (xerattrib) {
1306 Module *my_module = get_my_scope()->get_scope_mod();
1307 sdef.xerHasNamespaces = my_module->get_nof_ns() != 0;
1308 const char *ns, *prefix;
1309 my_module->get_controlns(ns, prefix);
1310 sdef.control_ns_prefix = prefix;
1311 sdef.xerUseUnion = xerattrib->useUnion_;
1312 sdef.xerUseTypeAttr = xerattrib->useType_ || xerattrib->useUnion_;
1313 }
1314 defUnionClass(&sdef, target);
1315 defUnionTemplate(&sdef, target);
1316
1317 free_code_ot(sdef.ot);
1318 sdef.ot=0;
1319 if (rawattrib) {
1320 free_raw_attrib_struct(&sdef.raw);
1321 }
1322 Free(sdef.elements);
1323 }
1324
1325 Opentype_t *Type::generate_code_ot(stringpool& pool)
1326 {
1327 using namespace Asn;
1328 if(typetype!=T_OPENTYPE)
1329 return 0;
1330 if(!u.secho.my_tableconstraint
1331 || !u.secho.my_tableconstraint->get_ans()) {
1332 DEBUG(1, "Opentype ObjectClassFieldType without"
1333 " ComponentRelationConstraint: `%s'",
1334 get_fullname().c_str());
1335 return 0;
1336 }
1337 const AtNotations *ans=u.secho.my_tableconstraint->get_ans();
1338 Opentype_t *ot=(Opentype_t*)Malloc(sizeof(*ot));
1339 ot->anl.nElements = ans->get_nof_ans();
1340 ot->anl.elements = (AtNotation_t*)
1341 Malloc(ot->anl.nElements * sizeof(*ot->anl.elements));
1342 for(size_t i=0; i<ans->get_nof_ans(); i++) {
1343 AtNotation *an=ans->get_an_byIndex(i);
1344 AtNotation_t *an_t = ot->anl.elements + i;
1345 an_t->dispname = pool.add(an->get_dispname());
1346 an_t->parent_level=an->get_levels();
1347 an_t->parent_typename =
1348 pool.add(an->get_firstcomp()->get_genname_value(my_scope));
1349 an_t->type_name =
1350 pool.add(an->get_lastcomp()->get_genname_value(my_scope));
1351 an_t->sourcecode=memptystr();
1352 FieldName* cids=an->get_cids();
1353 Type *t_type=an->get_firstcomp();
1354 for(size_t j=0; j<cids->get_nof_fields(); j++) {
1355 CompField *cf=
1356 t_type->get_comp_byName(*cids->get_field_byIndex(j));
1357 if(j) an_t->sourcecode=mputstr(an_t->sourcecode, ".");
1358 an_t->sourcecode=mputprintf
1359 (an_t->sourcecode, "%s()",
1360 cf->get_name().get_name().c_str());
1361 if(cf->get_is_optional())
1362 an_t->sourcecode=mputstr(an_t->sourcecode, "()");
1363 t_type=cf->get_type();
1364 } // for j
1365 } // i
1366 const Identifier *oc_fieldname_t
1367 =u.secho.my_tableconstraint->get_oc_fieldname();
1368 Objects *objs
1369 =u.secho.my_tableconstraint->get_os()->get_refd_last()->get_objs();
1370 ot->oal.nElements = objs->get_nof_objs();
1371 ot->oal.elements = (OpentypeAlternative_t*)
1372 Malloc(ot->oal.nElements * sizeof(*ot->oal.elements));
1373 size_t nElements_missing=0;
1374 Value **val_prev=(Value**)
1375 Malloc(ans->get_nof_ans()*sizeof(*val_prev));
1376 boolean differs_from_prev=true;
1377 for(size_t i=0; i<objs->get_nof_objs(); i++) {
1378 Obj_defn *obj=objs->get_obj_byIndex(i);
1379 if(!obj->has_fs_withName_dflt(*oc_fieldname_t)) {
1380 nElements_missing++;
1381 continue;
1382 }
1383 OpentypeAlternative_t *oa_t = ot->oal.elements + i - nElements_missing;
1384 Type *t_type=dynamic_cast<Type*>
1385 (obj->get_setting_byName_dflt(*oc_fieldname_t));
1386 bool is_strange;
1387 const Identifier& altname = t_type->get_otaltname(is_strange);
1388 oa_t->alt = pool.add(altname.get_name());
1389 oa_t->alt_dispname = pool.add(altname.get_asnname());
1390 oa_t->alt_typename = pool.add(t_type->get_genname_value(my_scope));
1391 oa_t->alt_typedescrname =
1392 pool.add(t_type->get_genname_typedescriptor(my_scope));
1393 oa_t->valuenames=(const char**)Malloc
1394 (ans->get_nof_ans()*sizeof(*oa_t->valuenames));
1395 oa_t->const_valuenames=(const char**)Malloc
1396 (ans->get_nof_ans()*sizeof(*oa_t->const_valuenames));
1397 for(size_t j=0; j<ans->get_nof_ans(); j++) {
1398 AtNotation *an=ans->get_an_byIndex(j);
1399 const Identifier *oc_fieldname_v=an->get_oc_fieldname();
1400 Value *t_value=dynamic_cast<Value*>
1401 (obj->get_setting_byName_dflt(*oc_fieldname_v));
1402 oa_t->valuenames[j] = pool.add(t_value->get_genname_own(my_scope));
1403 if(!differs_from_prev && *val_prev[j]==*t_value)
1404 oa_t->const_valuenames[j]=0;
1405 else {
1406 oa_t->const_valuenames[j] =
1407 pool.add(t_value->get_genname_own(my_scope));
1408 differs_from_prev=true;
1409 }
1410 val_prev[j]=t_value;
1411 } //j
1412 differs_from_prev=false;
1413 } // i
1414 Free(val_prev);
1415 ot->oal.nElements -= nElements_missing;
1416 ot->oal.elements = (OpentypeAlternative_t*)
1417 Realloc(ot->oal.elements,
1418 ot->oal.nElements * sizeof(*ot->oal.elements));
1419 return ot;
1420 }
1421
1422 void Type::free_code_ot(Opentype_t* p_ot)
1423 {
1424 if (!p_ot) return;
1425 for (size_t i = 0; i < p_ot->oal.nElements; i++) {
1426 Free(p_ot->oal.elements[i].valuenames);
1427 Free(p_ot->oal.elements[i].const_valuenames);
1428 }
1429 Free(p_ot->oal.elements);
1430 for (size_t i = 0; i < p_ot->anl.nElements; i++)
1431 Free(p_ot->anl.elements[i].sourcecode);
1432 Free(p_ot->anl.elements);
1433 Free(p_ot);
1434 }
1435
1436 size_t Type::get_codegen_index(size_t index)
1437 {
1438 // This sorting is because of CER coding of SET types, see X.690 9.3.
1439 // see: Type::generate_code_Se()
1440 // TODO: maybe result should be cached into this type
1441 // ( inside u.secho as dynamic_array<size_t>* codegen_indexes ? )
1442 if (typetype==T_SET_A) {
1443 size_t nof_comps = get_nof_comps();
1444 map<Tag, void> se_index_map;
1445 for (size_t i=0; i<nof_comps; i++) {
1446 Tag *tag = get_comp_byIndex(i)->get_type()->get_smallest_tag();
1447 se_index_map.add(*tag, (void*)i); // hack: store size_t in void* to avoid Malloc()
1448 delete tag;
1449 }
1450 for(size_t i=0; i<nof_comps; i++) {
1451 if (se_index_map.get_nth_elem(i)==(void*)index) {
1452 se_index_map.clear();
1453 return i;
1454 }
1455 }
1456 FATAL_ERROR("Type::get_codegen_index()");
1457 }
1458 return index;
1459 }
1460
1461 void Type::generate_code_Se(output_struct *target)
1462 {
1463 stringpool pool;
1464 struct_def sdef;
1465 Type * last_field_type = 0;
1466 memset(&sdef, 0, sizeof(sdef));
1467 sdef.name = get_genname_own().c_str();
1468 sdef.dispname = get_fullname().c_str();
1469 //printf("generate_code_Se(%s)\n", sdef.dispname);
1470 switch(typetype) {
1471 case T_SEQ_A:
1472 sdef.kind=RECORD;
1473 sdef.isASN1=TRUE;
1474 break;
1475 case T_SEQ_T:
1476 sdef.kind=RECORD;
1477 sdef.isASN1=FALSE;
1478 break;
1479 case T_SET_A:
1480 sdef.kind=SET;
1481 sdef.isASN1=TRUE;
1482 break;
1483 case T_SET_T:
1484 sdef.kind=SET;
1485 sdef.isASN1=FALSE;
1486 break;
1487 default:
1488 FATAL_ERROR("Type::generate_code_Se()");
1489 } // switch
1490 sdef.hasText = textattrib!=NULL;
1491 sdef.nElements = sdef.totalElements = get_nof_comps();
1492 sdef.has_opentypes = get_has_opentypes();
1493 sdef.opentype_outermost = get_is_opentype_outermost();
1494 sdef.ot = NULL;
1495 sdef.hasXer = has_encoding(CT_XER);
1496 sdef.hasJson = has_encoding(CT_JSON);
1497 if (xerattrib){
1498 Module *my_module = get_my_scope()->get_scope_mod();
1499 sdef.xerHasNamespaces = my_module->get_nof_ns() != 0;
1500 const char *ns, *prefix;
1501 my_module->get_controlns(ns, prefix);
1502 sdef.control_ns_prefix = prefix;
1503 sdef.xerUntagged = xerattrib->untagged_;
1504 sdef.xerUntaggedOne = u.secho.has_single_charenc;
1505 sdef.xerUseNilPossible = use_nil_possible;
1506 sdef.xerEmbedValuesPossible = embed_values_possible;
1507 sdef.xerUseOrderPossible = use_order_possible;
1508 if (xerattrib->useOrder_ && xerattrib->useNil_) {
1509 // We need information about the fields of the USE-NIL component
1510 const CompField *cf = get_comp_byIndex(sdef.totalElements-1);
1511 last_field_type = cf->get_type()->get_type_refd_last();
1512 sdef.totalElements += last_field_type->get_nof_comps();
1513 }
1514 sdef.xerUseQName = xerattrib->useQName_;
1515 if (xerattrib->useType_ || xerattrib->useUnion_) {
1516 FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record
1517 }
1518 }
1519 sdef.elements = (struct_field*)
1520 Malloc(sdef.totalElements*sizeof(*sdef.elements));
1521 memset(sdef.elements, 0, sdef.totalElements * sizeof(*sdef.elements));
1522
1523 /* This sorting is because of CER coding of SET types, see X.690
1524 9.3. */
1525 vector<CompField> se_comps;
1526 if(typetype==T_SET_A) {
1527 map<Tag, CompField> se_comps_map;
1528 for(size_t i=0; i<sdef.nElements; i++) {
1529 CompField* cf=get_comp_byIndex(i);
1530 Tag *tag = cf->get_type()->get_smallest_tag();
1531 se_comps_map.add(*tag, cf);
1532 delete tag;
1533 }
1534 for(size_t i=0; i<sdef.nElements; i++)
1535 se_comps.add(se_comps_map.get_nth_elem(i));
1536 se_comps_map.clear();
1537 }
1538 else {
1539 for(size_t i=0; i<sdef.nElements; i++)
1540 se_comps.add(get_comp_byIndex(i));
1541 }
1542
1543 for(size_t i = 0; i < sdef.nElements; i++) {
1544 struct_field &cur = sdef.elements[i];
1545 CompField *cf = se_comps[i];
1546 const Identifier& id = cf->get_name();
1547 Type *type = cf->get_type();
1548 cur.type = pool.add(type->get_genname_value(my_scope));
1549 cur.typegen = pool.add(type->get_genname_own());
1550 cur.of_type = type->get_type_refd_last()->is_seof();
1551 cur.typedescrname =
1552 pool.add(type->get_genname_typedescriptor(my_scope));
1553 cur.name = id.get_name().c_str();
1554 cur.dispname = id.get_ttcnname().c_str();
1555 cur.isOptional = cf->get_is_optional();
1556 cur.isDefault = cf->has_default();
1557 cur.optimizedMemAlloc = cur.of_type && (type->get_optimize_attribute() == "memalloc");
1558 if (cur.isDefault) {
1559 Value *defval = cf->get_defval();
1560 const_def cdef;
1561 Code::init_cdef(&cdef);
1562 type->generate_code_object(&cdef, defval);
1563 cdef.init = defval->generate_code_init
1564 (cdef.init, defval->get_lhs_name().c_str());
1565 Code::merge_cdef(target, &cdef);
1566 Code::free_cdef(&cdef);
1567 cur.defvalname = defval->get_genname_own().c_str();
1568 }
1569
1570 if (type->xerattrib) {
1571 cur.xerAttribute = type->xerattrib->attribute_;
1572
1573 if (has_aa(type->xerattrib)) {
1574 cur.xerAnyNum = type->xerattrib->anyAttributes_.nElements_;
1575 cur.xerAnyKind = ANY_ATTRIB_BIT |
1576 (type->xerattrib->anyAttributes_.type_ == NamespaceRestriction::FROM ?
1577 ANY_FROM_BIT : ANY_EXCEPT_BIT);
1578 if (cur.xerAnyNum > 0)
1579 cur.xerAnyUris = (char**)Malloc(cur.xerAnyNum * sizeof(char*));
1580 for (size_t uu=0; uu<cur.xerAnyNum; ++uu)
1581 cur.xerAnyUris[uu] = type->xerattrib->anyAttributes_.uris_[uu];
1582 }
1583 else if(has_ae(type->xerattrib)) {
1584 cur.xerAnyNum = type->xerattrib->anyElement_.nElements_;
1585 cur.xerAnyKind = ANY_ELEM_BIT |
1586 (type->xerattrib->anyElement_.type_ == NamespaceRestriction::FROM ?
1587 ANY_FROM_BIT : ANY_EXCEPT_BIT);
1588 if (cur.xerAnyNum > 0)
1589 cur.xerAnyUris = (char**)Malloc(cur.xerAnyNum* sizeof(char*));
1590 for (size_t uu=0; uu<cur.xerAnyNum; ++uu)
1591 cur.xerAnyUris[uu] = type->xerattrib->anyElement_.uris_[uu];
1592 }
1593 } // if xerattrib
1594 if (type->jsonattrib) {
1595 cur.jsonOmitAsNull = type->jsonattrib->omit_as_null;
1596 cur.jsonAlias = type->jsonattrib->alias;
1597 cur.jsonDefaultValue = type->jsonattrib->default_value;
1598 cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound;
1599 } // if jsonattrib
1600 } // next element
1601
1602 if (last_field_type)
1603 for (size_t i = sdef.nElements; i < sdef.totalElements; i++) {
1604 struct_field &cur = sdef.elements[i];
1605 CompField *cf = last_field_type->get_comp_byIndex(i - sdef.nElements);
1606 const Identifier& id = cf->get_name();
1607 Type *type = cf->get_type();
1608 cur.type = pool.add(type->get_genname_value(my_scope));
1609 cur.typegen = pool.add(type->get_genname_own());
1610 cur.of_type = type->get_type_refd_last()->is_seof();
1611 cur.typedescrname =
1612 pool.add(type->get_genname_typedescriptor(my_scope));
1613 cur.name = id.get_name().c_str();
1614 cur.dispname = id.get_ttcnname().c_str();
1615 cur.isOptional = cf->get_is_optional();
1616 }
1617 se_comps.clear();
1618
1619 if(rawattrib) {
1620 copy_rawAST_to_struct(rawattrib,&(sdef.raw));
1621 sdef.hasRaw=true;
1622 // building taglist
1623 for(int c=0;c<rawattrib->taglist.nElements;c++) {
1624 if(rawattrib->taglist.tag[c].nElements)
1625 sdef.raw.taglist.list[c].fields=
1626 (rawAST_coding_field_list*)
1627 Malloc(rawattrib->taglist.tag[c].nElements
1628 *sizeof(rawAST_coding_field_list));
1629 else sdef.raw.taglist.list[c].fields=NULL;
1630 sdef.raw.taglist.list[c].nElements=
1631 rawattrib->taglist.tag[c].nElements;
1632 sdef.raw.taglist.list[c].fieldName=
1633 rawattrib->taglist.tag[c].fieldName->get_name().c_str();
1634 Identifier *idf=rawattrib->taglist.tag[c].fieldName;
1635 sdef.raw.taglist.list[c].fieldnum=get_comp_index_byName(*idf);
1636 for(int a=0;a<rawattrib->taglist.tag[c].nElements;a++){
1637 rawAST_coding_field_list* key=
1638 sdef.raw.taglist.list[c].fields+a;
1639 key->nElements=
1640 rawattrib->taglist.tag[c].keyList[a].keyField->nElements+1;
1641 key->value=rawattrib->taglist.tag[c].keyList[a].value;
1642 key->start_pos=0;
1643 key->fields=(rawAST_coding_fields*)
1644 Malloc(key->nElements*sizeof(rawAST_coding_fields));
1645
1646 CompField *cf=get_comp_byIndex(sdef.raw.taglist.list[c].fieldnum);
1647 Type *t=cf->get_type()->get_type_refd_last();
1648
1649 key->fields[0].nthfield = sdef.raw.taglist.list[c].fieldnum;
1650 key->fields[0].nthfieldname =
1651 rawattrib->taglist.tag[c].fieldName->get_name().c_str();
1652 if (cf->get_is_optional())
1653 key->fields[0].fieldtype = OPTIONAL_FIELD;
1654 else key->fields[0].fieldtype = MANDATORY_FIELD;
1655 key->fields[0].type = pool.add(t->get_genname_value(my_scope));
1656 key->fields[0].typedescr =
1657 pool.add(t->get_genname_typedescriptor(my_scope));
1658
1659 CompField *cf2;
1660 for (int b = 1; b < key->nElements; b++) {
1661 Identifier *idf2 =
1662 rawattrib->taglist.tag[c].keyList[a].keyField->names[b-1];
1663 size_t comp_index = t->get_comp_index_byName(*idf2);
1664 cf2 = t->get_comp_byIndex(comp_index);
1665 key->fields[b].nthfield = comp_index;
1666 key->fields[b].nthfieldname = idf2->get_name().c_str();
1667 if (t->typetype == T_CHOICE_T)
1668 key->fields[b].fieldtype = UNION_FIELD;
1669 else if (cf2->get_is_optional())
1670 key->fields[b].fieldtype = OPTIONAL_FIELD;
1671 else key->fields[b].fieldtype = MANDATORY_FIELD;
1672 Type *field_type = cf2->get_type();
1673 key->fields[b].type =
1674 pool.add(field_type->get_genname_value(my_scope));
1675 key->fields[b].typedescr =
1676 pool.add(field_type->get_genname_typedescriptor(my_scope));
1677 if (field_type->typetype == T_SEQ_T && field_type->rawattrib
1678 && (field_type->rawattrib->pointerto
1679 || field_type->rawattrib->lengthto_num))
1680 key->start_pos = -1;
1681
1682 if(t->typetype != T_CHOICE_T && t->typetype != T_SET_T){
1683 Type *t2;
1684 for(size_t i = 0; i < comp_index && key->start_pos >=0; i++)
1685 {
1686 t2 = t->get_comp_byIndex(i)->get_type();
1687 if(t2->get_raw_length() >= 0){
1688 if(t2->rawattrib)
1689 key->start_pos += t2->rawattrib->padding;
1690 key->start_pos += t2->get_raw_length();
1691 }else key->start_pos = -1;
1692 }
1693 }
1694 t = field_type->get_type_refd_last();
1695 }
1696 }
1697 }
1698 // building presence list
1699 for(int a=0;a<rawattrib->presence.nElements;a++) {
1700 rawAST_coding_field_list* presences=sdef.raw.presence.fields+a;
1701 presences->nElements=
1702 rawattrib->presence.keyList[a].keyField->nElements;
1703 presences->value=rawattrib->presence.keyList[a].value;
1704 presences->fields=(rawAST_coding_fields*)
1705 Malloc(presences->nElements*sizeof(rawAST_coding_fields));
1706 Type *t = this;
1707 for (int b = 0; b < presences->nElements; b++) {
1708 Identifier *idf = rawattrib->presence.keyList[a].keyField->names[b];
1709 size_t comp_index = t->get_comp_index_byName(*idf);
1710 CompField *cf = t->get_comp_byIndex(comp_index);
1711 presences->fields[b].nthfield = comp_index;
1712 presences->fields[b].nthfieldname = idf->get_name().c_str();
1713 if (t->typetype == T_CHOICE_T)
1714 presences->fields[b].fieldtype = UNION_FIELD;
1715 else if (cf->get_is_optional())
1716 presences->fields[b].fieldtype = OPTIONAL_FIELD;
1717 else presences->fields[b].fieldtype = MANDATORY_FIELD;
1718 Type *field_type = cf->get_type();
1719 presences->fields[b].type =
1720 pool.add(field_type->get_genname_value(my_scope));
1721 presences->fields[b].typedescr =
1722 pool.add(field_type->get_genname_typedescriptor(my_scope));
1723 t = field_type->get_type_refd_last();
1724 }
1725 }
1726 for(int c=0;c<rawattrib->ext_bit_goup_num;c++){
1727 Identifier *idf=rawattrib->ext_bit_groups[c].from;
1728 Identifier *idf2=rawattrib->ext_bit_groups[c].to;
1729 sdef.raw.ext_bit_groups[c].ext_bit=rawattrib->ext_bit_groups[c].ext_bit;
1730 sdef.raw.ext_bit_groups[c].from=(int)get_comp_index_byName(*idf);
1731 sdef.raw.ext_bit_groups[c].to=(int)get_comp_index_byName(*idf2);
1732 }
1733 for(size_t i=0; i<sdef.totalElements; i++) {
1734 CompField *cf = get_comp_byIndex(i);
1735 Type *t_field = cf->get_type();
1736 Type *t_field_last = t_field->get_type_refd_last();
1737 RawAST *rawpar = t_field->rawattrib;
1738 if(rawpar) {
1739 copy_rawAST_to_struct(rawpar,&(sdef.elements[i].raw));
1740 for(int j=0; j<rawpar->lengthto_num;j++){
1741 Identifier *idf=rawpar->lengthto[j];
1742 sdef.elements[i].raw.lengthto[j]=get_comp_index_byName(*idf);
1743 }
1744 if (rawpar->lengthto_num && rawpar->lengthindex) {
1745 Identifier *idf = rawpar->lengthindex->names[0];
1746 size_t comp_index = t_field_last->get_comp_index_byName(*idf);
1747 sdef.elements[i].raw.lengthindex->nthfield = comp_index;
1748 sdef.elements[i].raw.lengthindex->nthfieldname =
1749 idf->get_name().c_str();
1750 CompField *cf2 = t_field_last->get_comp_byIndex(comp_index);
1751 Type *t_field2 = cf2->get_type();
1752 if (t_field2->typetype == T_CHOICE_T)
1753 sdef.elements[i].raw.lengthindex->fieldtype = UNION_FIELD;
1754 else if (cf2->get_is_optional())
1755 sdef.elements[i].raw.lengthindex->fieldtype = OPTIONAL_FIELD;
1756 else sdef.elements[i].raw.lengthindex->fieldtype = MANDATORY_FIELD;
1757 sdef.elements[i].raw.lengthindex->type =
1758 pool.add(t_field2->get_genname_value(my_scope));
1759 sdef.elements[i].raw.lengthindex->typedescr =
1760 pool.add(t_field2->get_genname_typedescriptor(my_scope));
1761 }
1762 if (rawpar->lengthto_num && !rawpar->lengthindex &&
1763 t_field_last->is_secho()) {
1764 int comp_num=(int)t_field_last->get_nof_comps();
1765 sdef.elements[i].raw.union_member_num=comp_num;
1766 sdef.elements[i].raw.member_name=
1767 (const char **)Malloc((comp_num+1)*sizeof(const char*));
1768 sdef.elements[i].raw.member_name[0] =
1769 pool.add(t_field_last->get_genname_value(my_scope));
1770 for(int m=1;m<comp_num+1;m++){
1771 CompField *compf=t_field_last->get_comp_byIndex(m-1);
1772 sdef.elements[i].raw.member_name[m]=
1773 compf->get_name().get_name().c_str();
1774 }
1775 }
1776 if(rawpar->pointerto){
1777 Identifier *idf=rawpar->pointerto;
1778 sdef.elements[i].raw.pointerto=get_comp_index_byName(*idf);
1779 if(rawpar->ptrbase){
1780 Identifier *idf2=rawpar->ptrbase;
1781 sdef.elements[i].raw.pointerbase=get_comp_index_byName(*idf2);
1782 } else sdef.elements[i].raw.pointerbase=i;
1783 }
1784 // building presence list
1785 for(int a=0;a<rawpar->presence.nElements;a++) {
1786 rawAST_coding_field_list* presences=
1787 sdef.elements[i].raw.presence.fields+a;
1788 presences->nElements=
1789 rawpar->presence.keyList[a].keyField->nElements;
1790 presences->value=rawpar->presence.keyList[a].value;
1791 presences->fields=(rawAST_coding_fields*)
1792 Malloc(presences->nElements*sizeof(rawAST_coding_fields));
1793 Type *t = this;
1794 for (int b = 0; b < presences->nElements; b++) {
1795 Identifier *idf = rawpar->presence.keyList[a].keyField->names[b];
1796 size_t comp_index = t->get_comp_index_byName(*idf);
1797 CompField *cf2 = t->get_comp_byIndex(comp_index);
1798 presences->fields[b].nthfield = comp_index;
1799 presences->fields[b].nthfieldname = idf->get_name().c_str();
1800 if (t->typetype == T_CHOICE_T)
1801 presences->fields[b].fieldtype = UNION_FIELD;
1802 else if (cf2->get_is_optional())
1803 presences->fields[b].fieldtype = OPTIONAL_FIELD;
1804 else presences->fields[b].fieldtype = MANDATORY_FIELD;
1805 Type *field_type = cf2->get_type();
1806 presences->fields[b].type =
1807 pool.add(field_type->get_genname_value(my_scope));
1808 presences->fields[b].typedescr =
1809 pool.add(field_type->get_genname_typedescriptor(my_scope));
1810 t = field_type->get_type_refd_last();
1811 }
1812 }
1813 // building crosstaglist
1814 for(int c=0;c<rawpar->crosstaglist.nElements;c++){
1815 if(rawpar->crosstaglist.tag[c].nElements)
1816 sdef.elements[i].raw.crosstaglist.list[c].fields=
1817 (rawAST_coding_field_list*)
1818 Malloc(rawpar->crosstaglist.tag[c].nElements
1819 *sizeof(rawAST_coding_field_list));
1820 else sdef.elements[i].raw.crosstaglist.list[c].fields=NULL;
1821 sdef.elements[i].raw.crosstaglist.list[c].nElements=
1822 rawpar->crosstaglist.tag[c].nElements;
1823 sdef.elements[i].raw.crosstaglist.list[c].fieldName=
1824 rawpar->crosstaglist.tag[c].fieldName->get_name().c_str();
1825 Identifier *idf=rawpar->crosstaglist.tag[c].fieldName;
1826 sdef.elements[i].raw.crosstaglist.list[c].fieldnum=
1827 t_field_last->get_comp_index_byName(*idf);
1828 sdef.elements[i].raw.crosstaglist.list[c].fieldnum=
1829 t_field_last->get_comp_index_byName(*idf);
1830 for(int a=0;a<rawpar->crosstaglist.tag[c].nElements;a++) {
1831 rawAST_coding_field_list* key=
1832 sdef.elements[i].raw.crosstaglist.list[c].fields+a;
1833 key->nElements=
1834 rawpar->crosstaglist.tag[c].keyList[a].keyField->nElements;
1835 key->value=rawpar->crosstaglist.tag[c].keyList[a].value;
1836 key->fields=(rawAST_coding_fields*)
1837 Malloc(key->nElements*sizeof(rawAST_coding_fields));
1838 Type *t = this;
1839 for (int b = 0; b < key->nElements; b++) {
1840 Identifier *idf2 =
1841 rawpar->crosstaglist.tag[c].keyList[a].keyField->names[b];
1842 size_t comp_index = t->get_comp_index_byName(*idf2);
1843 CompField *cf2 = t->get_comp_byIndex(comp_index);
1844 key->fields[b].nthfield = comp_index;
1845 key->fields[b].nthfieldname = idf2->get_name().c_str();
1846 if (t->typetype == T_CHOICE_T)
1847 key->fields[b].fieldtype = UNION_FIELD;
1848 else if (cf2->get_is_optional())
1849 key->fields[b].fieldtype = OPTIONAL_FIELD;
1850 else key->fields[b].fieldtype = MANDATORY_FIELD;
1851 Type *field_type = cf2->get_type();
1852 key->fields[b].type =
1853 pool.add(field_type->get_genname_value(my_scope));
1854 key->fields[b].typedescr =
1855 pool.add(field_type->get_genname_typedescriptor(my_scope));
1856 t = field_type->get_type_refd_last();
1857 }
1858 }
1859 }
1860 sdef.elements[i].raw.length = t_field->get_raw_length();
1861 sdef.elements[i].hasRaw=true;
1862 }
1863 else {
1864 sdef.elements[i].hasRaw=false;
1865 }
1866 }
1867 }
1868 else {
1869 for(size_t i = 0; i < sdef.totalElements; i++) {
1870 sdef.elements[i].hasRaw=false;
1871 }
1872 sdef.hasRaw=false;
1873 }
1874
1875 defRecordClass(&sdef, target);
1876 defRecordTemplate(&sdef, target);
1877
1878 for(size_t i = 0; i < sdef.totalElements; i++) {
1879 // free the array but not the strings
1880 if (sdef.elements[i].xerAnyNum > 0) Free(sdef.elements[i].xerAnyUris);
1881 } // next i
1882
1883 if (rawattrib) {
1884 free_raw_attrib_struct(&sdef.raw);
1885 for (size_t i = 0; i < sdef.totalElements; i++) {
1886 if (sdef.elements[i].hasRaw) {
1887 free_raw_attrib_struct(&sdef.elements[i].raw);
1888 }
1889 }
1890 }
1891 Free(sdef.elements);
1892 }
1893
1894 bool Type::is_untagged() const { return xerattrib && xerattrib->untagged_; }
1895
1896 void Type::generate_code_SeOf(output_struct *target)
1897 {
1898 const Type *oftypelast = u.seof.ofType->get_type_refd_last();
1899 const string& oftypename = u.seof.ofType->get_genname_value(my_scope);
1900 boolean optimized_memalloc = !use_runtime_2 && get_optimize_attribute() == "memalloc";
1901
1902 if (is_pregenerated()) {
1903 switch(oftypelast->typetype) {
1904 case T_USTR:
1905 case T_UTF8STRING:
1906 case T_TELETEXSTRING:
1907 case T_VIDEOTEXSTRING:
1908 case T_GRAPHICSTRING:
1909 case T_GENERALSTRING:
1910 case T_UNIVERSALSTRING:
1911 case T_BMPSTRING:
1912 case T_OBJECTDESCRIPTOR:
1913 target->header.class_decls = mputprintf(target->header.class_decls,
1914 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s %s;\n"
1915 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s_template %s_template;\n",
1916 (typetype == T_SEQOF) ? "RECORD" : "SET",
1917 optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str(),
1918 (typetype == T_SEQOF) ? "RECORD" : "SET",
1919 optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str());
1920 return;
1921 default:
1922 // generate these in the class declarations part, they need to be
1923 // outside of the include guard in case of circular imports
1924 target->header.class_decls = mputprintf(target->header.class_decls,
1925 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s %s;\n"
1926 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s_template %s_template;\n",
1927 (typetype == T_SEQOF) ? "RECORD" : "SET", oftypename.c_str(),
1928 optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str(),
1929 (typetype == T_SEQOF) ? "RECORD" : "SET", oftypename.c_str(),
1930 optimized_memalloc ? "__OPTIMIZED" : "", get_genname_own().c_str());
1931 return;
1932 }
1933 }
1934
1935 stringpool pool;
1936 struct_of_def sofdef;
1937 memset(&sofdef, 0, sizeof(sofdef));
1938 sofdef.name = get_genname_own().c_str();
1939 sofdef.dispname = get_fullname().c_str();
1940 sofdef.kind = typetype == T_SEQOF ? RECORD_OF : SET_OF;
1941 sofdef.isASN1 = is_asn1();
1942 sofdef.hasText = textattrib!=NULL;
1943 sofdef.hasXer = has_encoding(CT_XER);
1944 sofdef.hasJson = has_encoding(CT_JSON);
1945 if (xerattrib) {
1946 //sofdef.xerList = xerattrib->list_;
1947 sofdef.xerAttribute = xerattrib->attribute_;
1948 }
1949 // If a record of UTF8String, we need to prepare for ANY-ATTRIBUTES and
1950 // ANY-ELEMENT
1951 sofdef.xerAnyAttrElem = oftypelast->typetype == T_USTR
1952 || oftypelast->typetype == T_UTF8STRING;
1953 sofdef.type = oftypename.c_str();
1954 sofdef.has_opentypes = get_has_opentypes();
1955 const string& oftypedescrname =
1956 u.seof.ofType->get_genname_typedescriptor(my_scope);
1957 sofdef.oftypedescrname = oftypedescrname.c_str();
1958
1959 if (xerattrib && xerattrib->untagged_
1960 && ((u.seof.ofType->xerattrib && has_ae(u.seof.ofType->xerattrib))
1961 || (xerattrib && has_ae(xerattrib)))) {
1962 // An untagged record-of which has an embedded type with ANY-ELEMENT,
1963 // or itself has ANY-ELEMENT
1964 if (parent_type && parent_type->typetype == T_SEQ_T) {
1965 /* The record-of needs to know the optional siblings following it,
1966 * to be able to stop consuming XML elements that belong
1967 * to the following fields. This is achieved by generating
1968 * a can_start() for the record-of which returns false for XML elements
1969 * that belong to those following fields. */
1970 size_t n_parent_comps = parent_type->get_nof_comps();
1971 boolean found_self = false;
1972 /* Go through the fields of the parent; skip everything until we find
1973 * the field that is this record-of; then collect fields until
1974 * the first non-disappearing field. */
1975 for (size_t pc = 0; pc < n_parent_comps; ++pc) {
1976 CompField *pcf = parent_type->get_comp_byIndex(pc); //"ParentCompField"
1977 Type *pcft = pcf->get_type();
1978 if (found_self) {
1979 const Identifier& cfid = pcf->get_name();
1980 sofdef.followers = (struct_field*)Realloc(sofdef.followers,
1981 (++sofdef.nFollowers) * sizeof(struct_field));
1982 sofdef.followers[sofdef.nFollowers-1].name = pool.add(cfid.get_name());
1983 sofdef.followers[sofdef.nFollowers-1].type =
1984 pool.add(pcft->get_genname_value(my_scope));
1985 sofdef.followers[sofdef.nFollowers-1].typegen =
1986 pool.add(pcft->get_genname_own());
1987
1988 Type *pcft_last = pcft->get_type_refd_last();
1989 if (pcf->get_is_optional()
1990 || (pcft->is_untagged() && pcft_last->has_empty_xml()))
1991 {} // can disappear, continue
1992 else break;
1993 }
1994 else if (pcft == this) found_self = true;
1995 } // next field
1996 } // if parent is record
1997 } // if A-E
1998
1999 switch (oftypelast->typetype) { // X.680/2002, Table 5 under 25.5
2000 // T_CHOICE_A and T_CHOICE_T do not set xmlValueList because choice types
2001 // already omit their own tag.
2002 case T_BOOL:
2003 case T_ENUM_A: case T_ENUM_T:
2004 case T_NULL:
2005 sofdef.xmlValueList = TRUE;
2006 break;
2007
2008 default:
2009 sofdef.xmlValueList = FALSE;
2010 break;
2011 }
2012
2013 if(rawattrib) {
2014 copy_rawAST_to_struct(rawattrib,&(sofdef.raw));
2015 sofdef.hasRaw=true;
2016 } else sofdef.hasRaw=false;
2017
2018 if (optimized_memalloc) {
2019 defRecordOfClassMemAllocOptimized(&sofdef, target);
2020 } else {
2021 defRecordOfClass(&sofdef, target);
2022 }
2023 defRecordOfTemplate(&sofdef, target);
2024
2025 if (sofdef.nFollowers) {
2026 Free(sofdef.followers);
2027 }
2028 }
2029
2030 void Type::generate_code_Array(output_struct *target)
2031 {
2032 if (!u.array.in_typedef) return;
2033 const char *own_name = get_genname_own().c_str();
2034 if (has_encoding(CT_JSON)) {
2035 target->header.class_decls = mputprintf(target->header.class_decls,
2036 "class %s;\n", own_name);
2037 target->header.class_defs = mputprintf(target->header.class_defs,
2038 "class %s : public %s {\n"
2039 "const TTCN_Typedescriptor_t* get_elem_descr() const;\n"
2040 "};\n\n",
2041 own_name,
2042 u.array.dimension->get_value_type(u.array.element_type, my_scope).c_str());
2043 target->source.class_defs = mputprintf(target->source.class_defs,
2044 "const TTCN_Typedescriptor_t* %s::get_elem_descr() const { return &%s_descr_; }\n\n",
2045 own_name, u.array.element_type->get_genname_typedescriptor(my_scope).c_str());
2046 } else {
2047 target->header.typedefs = mputprintf(target->header.typedefs,
2048 #ifndef NDEBUG
2049 "// written by %s in " __FILE__ " at %d\n"
2050 #endif
2051 "typedef %s %s;\n",
2052 #ifndef NDEBUG
2053 __FUNCTION__, __LINE__,
2054 #endif
2055 u.array.dimension->get_value_type(u.array.element_type, my_scope).c_str(),
2056 own_name);
2057 }
2058 target->header.typedefs = mputprintf(target->header.typedefs,
2059 "typedef %s %s_template;\n",
2060 u.array.dimension->get_template_type(u.array.element_type, my_scope).c_str(),
2061 own_name);
2062 }
2063
2064 void Type::generate_code_Fat(output_struct *target)
2065 {
2066 funcref_def fdef;
2067 memset(&fdef, 0, sizeof(fdef));
2068 fdef.name = get_genname_own().c_str();
2069 fdef.dispname = get_fullname().c_str();
2070 switch(typetype) {
2071 case T_FUNCTION:
2072 if(u.fatref.return_type)
2073 if(u.fatref.returns_template)
2074 fdef.return_type = mcopystr(u.fatref.return_type->
2075 get_genname_template(my_scope).c_str());
2076 else fdef.return_type = mcopystr(u.fatref.return_type->
2077 get_genname_value(my_scope).c_str());
2078 else fdef.return_type = NULL;
2079 fdef.type = FUNCTION;
2080 break;
2081 case T_ALTSTEP:
2082 fdef.return_type = NULL;
2083 fdef.type = ALTSTEP;
2084 break;
2085 case T_TESTCASE:
2086 fdef.return_type = NULL;
2087 fdef.type = TESTCASE;
2088 break;
2089 default:
2090 FATAL_ERROR("Type::generate_code_Fat()");
2091 }
2092 fdef.runs_on_self = u.fatref.runs_on.self ? TRUE : FALSE;
2093 fdef.is_startable = u.fatref.is_startable;
2094 fdef.formal_par_list = u.fatref.fp_list->generate_code(memptystr(),
2095 u.fatref.fp_list->get_nof_fps());
2096 u.fatref.fp_list->generate_code_defval(target);
2097 fdef.actual_par_list = u.fatref.fp_list
2098 ->generate_code_actual_parlist(memptystr(),"");
2099 if (typetype == T_TESTCASE) {
2100 if (u.fatref.fp_list->get_nof_fps() > 0) {
2101 fdef.formal_par_list = mputstr(fdef.formal_par_list, ", ");
2102 fdef.actual_par_list = mputstr(fdef.actual_par_list, ", ");
2103 }
2104 fdef.formal_par_list = mputstr(fdef.formal_par_list,
2105 "boolean has_timer, double timer_value");
2106 fdef.actual_par_list = mputstr(fdef.actual_par_list,
2107 "has_timer, timer_value");
2108 }
2109 fdef.nElements = u.fatref.fp_list->get_nof_fps();
2110 fdef.parameters = (const char**)
2111 Malloc(fdef.nElements * sizeof(*fdef.parameters));
2112 for(size_t i = 0;i < fdef.nElements; i++) {
2113 fdef.parameters[i] = u.fatref.fp_list->get_fp_byIndex(i)
2114 ->get_id().get_name().c_str();
2115 }
2116
2117 defFunctionrefClass(&fdef, target);
2118 defFunctionrefTemplate(&fdef, target);
2119 Free(fdef.return_type);
2120 Free(fdef.formal_par_list);
2121 Free(fdef.actual_par_list);
2122 Free(fdef.parameters);
2123 }
2124
2125 void Type::generate_code_Signature(output_struct *target)
2126 {
2127 stringpool pool;
2128 signature_def sdef;
2129 memset(&sdef, 0, sizeof(sdef));
2130 sdef.name = get_genname_own().c_str();
2131 sdef.dispname = get_fullname().c_str();
2132 if (u.signature.return_type) sdef.return_type =
2133 pool.add(u.signature.return_type->get_genname_value(my_scope));
2134 else sdef.return_type = NULL;
2135 if (u.signature.parameters) {
2136 sdef.parameters.nElements = u.signature.parameters->get_nof_params();
2137 sdef.parameters.elements = (signature_par*)
2138 Malloc(sdef.parameters.nElements * sizeof(*sdef.parameters.elements));
2139 for (size_t i = 0; i < sdef.parameters.nElements; i++) {
2140 SignatureParam *param = u.signature.parameters->get_param_byIndex(i);
2141 switch (param->get_direction()) {
2142 case SignatureParam::PARAM_IN:
2143 sdef.parameters.elements[i].direction = PAR_IN;
2144 break;
2145 case SignatureParam::PARAM_OUT:
2146 sdef.parameters.elements[i].direction = PAR_OUT;
2147 break;
2148 case SignatureParam::PARAM_INOUT:
2149 sdef.parameters.elements[i].direction = PAR_INOUT;
2150 break;
2151 default:
2152 FATAL_ERROR("Type::generate_code_Signature()");
2153 }
2154 sdef.parameters.elements[i].type =
2155 pool.add(param->get_type()->get_genname_value(my_scope));
2156 sdef.parameters.elements[i].name = param->get_id().get_name().c_str();
2157 sdef.parameters.elements[i].dispname =
2158 param->get_id().get_ttcnname().c_str();
2159 }
2160 } else {
2161 sdef.parameters.nElements = 0;
2162 sdef.parameters.elements = NULL;
2163 }
2164 sdef.is_noblock = u.signature.no_block;
2165 if (u.signature.exceptions) {
2166 sdef.exceptions.nElements = u.signature.exceptions->get_nof_types();
2167 sdef.exceptions.elements = (signature_exception*)
2168 Malloc(sdef.exceptions.nElements * sizeof(*sdef.exceptions.elements));
2169 for (size_t i = 0; i < sdef.exceptions.nElements; i++) {
2170 Type *type = u.signature.exceptions->get_type_byIndex(i);
2171 sdef.exceptions.elements[i].name =
2172 pool.add(type->get_genname_value(my_scope));
2173 sdef.exceptions.elements[i].dispname = pool.add(type->get_typename());
2174 sdef.exceptions.elements[i].altname = pool.add(type->get_genname_altname());
2175 }
2176 } else {
2177 sdef.exceptions.nElements = 0;
2178 sdef.exceptions.elements = NULL;
2179 }
2180 defSignatureClasses(&sdef, target);
2181 Free(sdef.parameters.elements);
2182 Free(sdef.exceptions.elements);
2183 }
2184
2185 bool Type::needs_alias()
2186 {
2187 /** The decision is actually based on the fullname of the type. If it
2188 * contains two or more dot (.) characters false is returned.
2189 * The following attributes cannot be used for the decision:
2190 * - parent_type, my_scope: types within ASN.1 object classes, objects
2191 * look the same as top-level aliased types, but they do not need alias. */
2192 const string& full_name = get_fullname();
2193 size_t fullname_len = full_name.size();
2194 size_t first_dot = full_name.find('.', 0);
2195 if (first_dot >= fullname_len) return true; // no dots
2196 else if (full_name.find('.', first_dot + 1) < fullname_len) return false;
2197 else return true;
2198 }
2199
2200
2201 void Type::generate_code_done(output_struct *target)
2202 {
2203 const string& t_genname = get_genname_value(my_scope);
2204 const char *genname_str = t_genname.c_str();
2205 const string& dispname = get_typename();
2206 const char *dispname_str = dispname.c_str();
2207 target->header.function_prototypes = mputprintf
2208 (target->header.function_prototypes,
2209 "extern alt_status done(const COMPONENT& component_reference, "
2210 "const %s_template& value_template, %s *value_ptr);\n",
2211 genname_str, genname_str);
2212 target->source.function_bodies = mputprintf
2213 (target->source.function_bodies,
2214 "alt_status done(const COMPONENT& component_reference, "
2215 "const %s_template& value_template, %s *value_ptr)\n"
2216 "{\n"
2217 "if (!component_reference.is_bound()) "
2218 "TTCN_error(\"Performing a done operation on an unbound component "
2219 "reference.\");\n"
2220 "Text_Buf *text_buf;\n"
2221 "alt_status ret_val = TTCN_Runtime::component_done("
2222 "(component)component_reference, \"%s\", text_buf);\n"
2223 "if (ret_val == ALT_YES) {\n"
2224 "%s return_value;\n"
2225 "return_value.decode_text(*text_buf);\n"
2226 "if (value_template.match(return_value)) {\n"
2227 "if (value_ptr != NULL) *value_ptr = return_value;\n"
2228 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
2229 "TTCN_Logger::log_event_str(\"PTC with component reference \");\n"
2230 "component_reference.log();\n"
2231 "TTCN_Logger::log_event_str(\" is done. Return value: %s : \");\n"
2232 "return_value.log();\n"
2233 "TTCN_Logger::end_event();\n"
2234 "return ALT_YES;\n"
2235 "} else {\n"
2236 "if (TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_DONE)) {\n"
2237 "TTCN_Logger::begin_event(TTCN_Logger::MATCHING_DONE);\n"
2238 "TTCN_Logger::log_event_str(\"Done operation with type %s on"
2239 " component reference \");\n"
2240 "component_reference.log();\n"
2241 "TTCN_Logger::log_event_str(\" failed: Return value does not match "
2242 "the template: \");\n"
2243 "value_template.log_match(return_value%s);\n"
2244 "TTCN_Logger::end_event();\n"
2245 "}\n"
2246 "return ALT_NO;\n"
2247 "}\n"
2248 "} else return ret_val;\n"
2249 "}\n\n",
2250 genname_str, genname_str, dispname_str, genname_str, dispname_str,
2251 dispname_str, omit_in_value_list ? ", TRUE" : "");
2252 }
2253
2254 bool Type::ispresent_anyvalue_embedded_field(Type* t,
2255 Ttcn::FieldOrArrayRefs *subrefs, size_t begin_index)
2256 {
2257 if (!subrefs) return true;
2258 size_t nof_refs = subrefs->get_nof_refs();
2259 for (size_t i = begin_index; i < nof_refs; i++) {
2260 t = t->get_type_refd_last();
2261 Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
2262 switch (ref->get_type()) {
2263 case Ttcn::FieldOrArrayRef::FIELD_REF: {
2264 CompField* cf = t->get_comp_byName(*ref->get_id());
2265 switch (t->typetype) {
2266 case T_CHOICE_T:
2267 case T_CHOICE_A:
2268 case T_OPENTYPE:
2269 case T_ANYTYPE:
2270 return false;
2271 case T_SEQ_T:
2272 case T_SET_T:
2273 case T_SEQ_A:
2274 case T_SET_A:
2275 if (cf->get_is_optional()) return false;
2276 break;
2277 default:
2278 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2279 }
2280 t = cf->get_type();
2281 } break;
2282 case Ttcn::FieldOrArrayRef::ARRAY_REF:
2283 switch (t->typetype) {
2284 case T_SEQOF:
2285 case T_SETOF:
2286 return false; // (the existence of a record of element is optional)
2287 case T_ARRAY:
2288 t = t->u.array.element_type;
2289 break;
2290 default:
2291 return true; // string types
2292 }
2293 break;
2294 default:
2295 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2296 }
2297 }
2298 return true;
2299 }
2300
2301 void Type::generate_code_ispresentbound(expression_struct *expr,
2302 Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
2303 const string& global_id, const string& external_id, const bool is_template,
2304 const bool isbound)
2305 {
2306 if (!subrefs) return;
2307
2308 Type *t = this;
2309 Type *next_t;
2310 bool next_o; // next is optional value
2311 size_t nof_refs = subrefs->get_nof_refs();
2312 subrefs->clear_string_element_ref();
2313 char *tmp_generalid_str = mcopystr(external_id.c_str());
2314 expstring_t closing_brackets = memptystr(); //The closing parts collected
2315 for (size_t i = 0; i < nof_refs; i++) {
2316 t = t->get_type_refd_last();
2317 // stop immediately if current type t is erroneous
2318 // (e.g. because of circular reference)
2319 if (t->typetype == T_ERROR) return;
2320
2321 if (is_template) {
2322 bool anyval_ret_val = true;
2323 if (!isbound) {
2324 anyval_ret_val = ispresent_anyvalue_embedded_field(t, subrefs, i);
2325 }
2326 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2327 expr->expr = mputprintf(expr->expr,
2328 "switch (%s.get_selection()) {\n"
2329 "case UNINITIALIZED_TEMPLATE:\n"
2330 "%s = false;\n"
2331 "break;\n"
2332 "case ANY_VALUE:\n"
2333 "%s = %s;\n"
2334 "break;\n"
2335 "case SPECIFIC_VALUE: {\n",
2336 tmp_generalid_str, global_id.c_str(), global_id.c_str(),
2337 anyval_ret_val ? "true" : "false");
2338
2339 expstring_t closing_brackets_switch = mprintf(
2340 "break;}\n"
2341 "default:\n"
2342 "%s = false;\n"
2343 "break;\n"
2344 "}\n"
2345 "}\n"
2346 "%s",
2347 global_id.c_str(), closing_brackets);
2348 Free(closing_brackets);
2349 closing_brackets = closing_brackets_switch;
2350 }
2351
2352 Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
2353 switch (ref->get_type()) {
2354 case Ttcn::FieldOrArrayRef::FIELD_REF: {
2355 const Identifier& id = *ref->get_id();
2356 CompField* cf = t->get_comp_byName(id);
2357 next_t = cf->get_type();
2358 next_o = !is_template && cf->get_is_optional();
2359
2360 switch (t->typetype) {
2361 case T_CHOICE_A:
2362 case T_CHOICE_T:
2363 case T_OPENTYPE:
2364 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2365 expr->expr = mputprintf(expr->expr,
2366 "%s = %s.ischosen(%s::ALT_%s);\n", global_id.c_str(),
2367 tmp_generalid_str,
2368 t->get_genname_value(module).c_str(),
2369 id.get_name().c_str());
2370 expr->expr = mputstr(expr->expr, "}\n");
2371 // intentionally missing break
2372 case T_SEQ_A:
2373 case T_SEQ_T:
2374 case T_SET_A:
2375 case T_SET_T:
2376 case T_ANYTYPE:
2377 break;
2378 default:
2379 FATAL_ERROR("Type::generate_code_isbound()");
2380 }
2381
2382 if (next_o) {
2383 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2384 expstring_t closing_brackets2 = mprintf("}\n%s", closing_brackets);
2385 Free(closing_brackets);
2386 closing_brackets = closing_brackets2;
2387
2388 const string& tmp_id = module->get_temporary_id();
2389 const char *tmp_id_str = tmp_id.c_str();
2390 expr->expr = mputprintf(expr->expr,
2391 "const OPTIONAL<%s%s>& %s = %s.%s();\n",
2392 next_t->get_genname_value(module).c_str(),
2393 is_template?"_template":"", tmp_id_str, tmp_generalid_str,
2394 id.get_name().c_str());
2395
2396 if (i==(nof_refs-1)) {
2397 // we are at the end of the reference chain
2398 expr->expr = mputprintf(expr->expr,
2399 "switch (%s.get_selection()) {\n"
2400 "case OPTIONAL_UNBOUND:\n"
2401 "%s = false;\n"
2402 "break;\n"
2403 "case OPTIONAL_OMIT:\n"
2404 "%s = %s;\n"
2405 "break;\n"
2406 "default:\n",
2407 tmp_id_str, global_id.c_str(),global_id.c_str(),
2408 isbound ? "true" : "false");
2409 Free(tmp_generalid_str);
2410 tmp_generalid_str = mcopystr(tmp_id_str);
2411
2412 expr->expr = mputstr(expr->expr, "{\n");
2413 const string& tmp_id2 = module->get_temporary_id();
2414 const char *tmp_id2_str = tmp_id2.c_str();
2415 expr->expr = mputprintf(expr->expr,
2416 "const %s%s& %s = (const %s%s&) %s;\n",
2417 next_t->get_genname_value(module).c_str(),
2418 is_template?"_template":"", tmp_id2_str,
2419 next_t->get_genname_value(module).c_str(),
2420 is_template?"_template":"", tmp_id_str);
2421
2422 expr->expr = mputprintf(expr->expr,
2423 "%s = %s.%s(%s);\n", global_id.c_str(),
2424 tmp_id2_str, isbound ? "is_bound" : "is_present",
2425 (!isbound && is_template && omit_in_value_list) ? "TRUE" : "");
2426 Free(tmp_generalid_str);
2427 tmp_generalid_str = mcopystr(tmp_id2_str);
2428
2429 expr->expr = mputprintf(expr->expr,
2430 "break;}\n"
2431 "}\n");
2432 } else {
2433 expr->expr = mputprintf(expr->expr,
2434 "switch (%s.get_selection()) {\n"
2435 "case OPTIONAL_UNBOUND:\n"
2436 "case OPTIONAL_OMIT:\n"
2437 "%s = false;\n"
2438 "break;\n"
2439 "default:\n"
2440 "break;\n"
2441 "}\n",
2442 tmp_id_str, global_id.c_str());
2443 Free(tmp_generalid_str);
2444 tmp_generalid_str = mcopystr(tmp_id_str);
2445
2446 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2447 closing_brackets2 = mprintf("}\n%s", closing_brackets);
2448 Free(closing_brackets);
2449 closing_brackets = closing_brackets2;
2450
2451 const string& tmp_id2 = module->get_temporary_id();
2452 const char *tmp_id2_str = tmp_id2.c_str();
2453 expr->expr = mputprintf(expr->expr,
2454 "const %s%s& %s = (const %s%s&) %s;\n",
2455 next_t->get_genname_value(module).c_str(),
2456 is_template?"_template":"", tmp_id2_str,
2457 next_t->get_genname_value(module).c_str(),
2458 is_template?"_template":"", tmp_id_str);
2459
2460 expr->expr = mputprintf(expr->expr,
2461 "%s = %s.is_bound();\n", global_id.c_str(),
2462 tmp_id2_str);
2463 Free(tmp_generalid_str);
2464 tmp_generalid_str = mcopystr(tmp_id2_str);
2465 }
2466 } else {
2467 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2468 expstring_t closing_brackets2 = mprintf("}\n%s", closing_brackets);
2469 Free(closing_brackets);
2470 closing_brackets = closing_brackets2;
2471
2472 const string& tmp_id = module->get_temporary_id();
2473 const char *tmp_id_str = tmp_id.c_str();
2474 expr->expr = mputprintf(expr->expr,
2475 "const %s%s& %s = %s.%s();\n",
2476 next_t->get_genname_value(module).c_str(),
2477 is_template?"_template":"", tmp_id_str, tmp_generalid_str,
2478 id.get_name().c_str());
2479
2480 expr->expr = mputprintf(expr->expr,
2481 "%s = %s.%s(%s);\n", global_id.c_str(),
2482 tmp_id_str, isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
2483 (!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
2484 Free(tmp_generalid_str);
2485 tmp_generalid_str = mcopystr(tmp_id_str);
2486 }
2487
2488 t = next_t;
2489 break; }
2490 case Ttcn::FieldOrArrayRef::ARRAY_REF: {
2491 Type *embedded_type = 0;
2492 bool is_string = true;
2493 bool is_string_element = false;
2494 switch (t->typetype) {
2495 case T_SEQOF:
2496 case T_SETOF:
2497 embedded_type = t->u.seof.ofType;
2498 is_string = false;
2499 break;
2500 case T_ARRAY:
2501 embedded_type = t->u.array.element_type;
2502 is_string = false;
2503 break;
2504 case T_BSTR:
2505 case T_BSTR_A:
2506 case T_HSTR:
2507 case T_OSTR:
2508 case T_CSTR:
2509 case T_USTR:
2510 case T_UTF8STRING:
2511 case T_NUMERICSTRING:
2512 case T_PRINTABLESTRING:
2513 case T_TELETEXSTRING:
2514 case T_VIDEOTEXSTRING:
2515 case T_IA5STRING:
2516 case T_GRAPHICSTRING:
2517 case T_VISIBLESTRING:
2518 case T_GENERALSTRING:
2519 case T_UNIVERSALSTRING:
2520 case T_BMPSTRING:
2521 case T_UTCTIME:
2522 case T_GENERALIZEDTIME:
2523 case T_OBJECTDESCRIPTOR:
2524 if (subrefs->refers_to_string_element()) {
2525 FATAL_ERROR("Type::generate_code_isbound()");
2526 } else {
2527 subrefs->set_string_element_ref();
2528 // string elements have the same type as the string itself
2529 embedded_type = t;
2530 is_string_element = true;
2531 break;
2532 }
2533 default:
2534 FATAL_ERROR("Type::generate_code_isbound()");
2535 }
2536
2537 next_t = embedded_type;
2538
2539 // check the index value
2540 Value *index_value = ref->get_val();
2541 Value *v_last = index_value->get_value_refd_last();
2542
2543 const string& tmp_index_id = module->get_temporary_id();
2544 const char *tmp_index_id_str = tmp_index_id.c_str();
2545 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2546
2547 expstring_t closing_brackets2 = mprintf("}\n%s", closing_brackets);
2548 Free(closing_brackets);
2549 closing_brackets = closing_brackets2;
2550
2551 expr->expr = mputprintf(expr->expr, "const int %s = ", tmp_index_id_str);
2552 v_last->generate_code_expr_mandatory(expr);
2553 expr->expr = mputstr(expr->expr, ";\n");
2554 expr->expr = mputprintf(expr->expr, "%s = (%s >= 0) && (%s.%s > %s);\n",
2555 global_id.c_str(), tmp_index_id_str, tmp_generalid_str,
2556 is_string ? "lengthof()": ( is_template ? "n_elem()" : "size_of()" ),
2557 tmp_index_id_str);
2558 expr->expr = mputprintf(expr->expr, "if(%s) {\n",global_id.c_str());
2559
2560 closing_brackets2 = mprintf("}\n%s", closing_brackets);
2561 Free(closing_brackets);
2562 closing_brackets = closing_brackets2;
2563
2564 const string& tmp_id = module->get_temporary_id();
2565 const char *tmp_id_str = tmp_id.c_str();
2566
2567 if (is_string_element) {
2568 expr->expr = mputprintf(expr->expr,
2569 "%s = %s[%s].%s(%s);\n", global_id.c_str(),
2570 tmp_generalid_str, tmp_index_id_str,
2571 isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
2572 (!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
2573 } else {
2574 if (is_template) {
2575 expr->expr = mputprintf(expr->expr,
2576 "const %s& %s = %s[%s];\n",
2577 next_t->get_genname_template(module).c_str(),
2578 tmp_id_str, tmp_generalid_str,
2579 tmp_index_id_str);
2580 } else {
2581 expr->expr = mputprintf(expr->expr,
2582 "const %s%s& %s = %s[%s];\n",
2583 next_t->get_genname_value(module).c_str(),
2584 is_template?"_template":"", tmp_id_str, tmp_generalid_str,
2585 tmp_index_id_str);
2586 }
2587
2588 expr->expr = mputprintf(expr->expr,
2589 "%s = %s.%s(%s);\n", global_id.c_str(), tmp_id_str,
2590 isbound||(i!=(nof_refs-1)) ? "is_bound" : "is_present",
2591 (!(isbound||(i!=(nof_refs-1))) && is_template && omit_in_value_list) ? "TRUE" : "");
2592 }
2593
2594 Free(tmp_generalid_str);
2595 tmp_generalid_str = mcopystr(tmp_id_str);
2596
2597 // change t to the embedded type
2598 t = next_t;
2599 break; }
2600 default:
2601 FATAL_ERROR("Type::generate_code_isbound(): invalid reference type");
2602 }
2603 }
2604
2605 Free(tmp_generalid_str);
2606 expr->expr = mputstr(expr->expr, closing_brackets);
2607 Free(closing_brackets);
2608 }
2609
2610 string Type::get_optimize_attribute()
2611 {
2612 if(w_attrib_path)
2613 {
2614 vector<SingleWithAttrib> const &real_attribs
2615 = w_attrib_path->get_real_attrib();
2616 for (size_t i = 0; i < real_attribs.size(); i++) {
2617 SingleWithAttrib * temp_single = real_attribs[i];
2618 if (temp_single->get_attribKeyword()
2619 == SingleWithAttrib::AT_EXTENSION
2620 && (!temp_single->get_attribQualifiers()
2621 || (temp_single->get_attribQualifiers()
2622 ->get_nof_qualifiers() == 0)))
2623 {
2624 const string& spec = temp_single->get_attribSpec().get_spec();
2625 // TODO: use a real parser to allow whitespaces, etc.
2626 if (spec.find("optimize:")==0 && spec.size()>9)
2627 {
2628 string spec_optimize_for_what = spec.substr(9);
2629 return spec_optimize_for_what;
2630 }
2631 }
2632 }
2633 }
2634 return string();
2635 }
2636
2637 string Type::get_sourcefile_attribute()
2638 {
2639 if(w_attrib_path)
2640 {
2641 vector<SingleWithAttrib> const &real_attribs
2642 = w_attrib_path->get_real_attrib();
2643
2644 for (size_t i = 0; i < real_attribs.size(); i++) {
2645 SingleWithAttrib * temp_single = real_attribs[i];
2646 if (temp_single->get_attribKeyword()
2647 == SingleWithAttrib::AT_EXTENSION
2648 && (!temp_single->get_attribQualifiers()
2649 || (temp_single->get_attribQualifiers()
2650 ->get_nof_qualifiers() == 0)))
2651 {
2652 const string& spec = temp_single->get_attribSpec().get_spec();
2653 if (spec.find("sourcefile:")==0 && spec.size()>11)
2654 {
2655 string spec_filename = spec.substr(11);
2656 // TODO: check if string can be a valid filename
2657 return spec_filename;
2658 }
2659 }
2660 }
2661 }
2662 return string();
2663 }
2664
2665 bool Type::has_done_attribute()
2666 {
2667 if(w_attrib_path)
2668 {
2669 vector<SingleWithAttrib> const &real_attribs
2670 = w_attrib_path->get_real_attrib();
2671
2672 for (size_t i = 0; i < real_attribs.size(); i++) {
2673 SingleWithAttrib * temp_single = real_attribs[i];
2674 if (temp_single->get_attribKeyword()
2675 == SingleWithAttrib::AT_EXTENSION
2676 && (!temp_single->get_attribQualifiers()
2677 || (temp_single->get_attribQualifiers()
2678 ->get_nof_qualifiers() == 0))
2679 && temp_single->get_attribSpec().get_spec() == "done")
2680 {
2681 return true;
2682 }
2683 }
2684 }
2685 return false;
2686 }
2687
2688 void Type::generate_code_object(const_def *cdef, Scope *p_scope,
2689 const string& name, const char *prefix, bool is_template)
2690 {
2691 string type_name;
2692 if (is_template) type_name = get_genname_template(p_scope);
2693 else type_name = get_genname_value(p_scope);
2694 const char *name_str = name.c_str();
2695 const char *type_name_str = type_name.c_str();
2696 if (prefix) {
2697 cdef->decl = mputprintf(cdef->decl, "extern const %s& %s;\n",
2698 type_name_str, name_str);
2699 cdef->def = mputprintf(cdef->def, "static %s %s%s;\n"
2700 "const %s& %s = %s%s;\n", type_name_str, prefix, name_str,
2701 type_name_str, name_str, prefix, name_str);
2702 } else {
2703 cdef->decl = mputprintf(cdef->decl, "extern %s %s;\n",
2704 type_name_str, name_str);
2705 cdef->def = mputprintf(cdef->def, "%s %s;\n",
2706 type_name_str, name_str);
2707 }
2708 }
2709
2710 void Type::generate_code_object(const_def *cdef, GovernedSimple *p_setting)
2711 {
2712 bool is_template = false;
2713 switch (p_setting->get_st()) {
2714 case S_TEMPLATE:
2715 is_template = true;
2716 break;
2717 case S_V:
2718 break;
2719 default:
2720 FATAL_ERROR("Type::generate_code_object()");
2721 }
2722 if (p_setting->get_err_descr()) {
2723 cdef->def = p_setting->get_err_descr()->generate_code_str(cdef->def,
2724 p_setting->get_genname_prefix() + p_setting->get_genname_own());
2725 }
2726 generate_code_object(cdef, p_setting->get_my_scope(),
2727 p_setting->get_genname_own(), p_setting->get_genname_prefix(),
2728 is_template);
2729 }
2730
2731 void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_value)
2732 {
2733 // add a new property for the type if it has its own definition
2734 if (!embedded) {
2735 json.put_next_token(JSON_TOKEN_NAME, get_dispname().c_str());
2736 }
2737
2738 // create an object containing the type's schema
2739 json.put_next_token(JSON_TOKEN_OBJECT_START);
2740
2741 // if this is a field of a record/set/union with an alias, the field's
2742 // original name must be stored ("originalName" property), it also needs to be
2743 // stored if this is a field of a union with the "as value" coding instruction
2744 if (ownertype == OT_COMP_FIELD) {
2745 CompField* cf = static_cast<CompField*>(owner);
2746 if (as_value || (cf->get_type()->jsonattrib != NULL
2747 && cf->get_type()->jsonattrib->alias != NULL)) {
2748 json.put_next_token(JSON_TOKEN_NAME, "originalName");
2749 char* field_str = mprintf("\"%s\"", cf->get_name().get_ttcnname().c_str());
2750 json.put_next_token(JSON_TOKEN_STRING, field_str);
2751 Free(field_str);
2752 }
2753
2754 // if the parent is a union with the "as value" coding instruction AND the field
2755 // has an alias, then the alias needs to be stored as well ("unusedAlias" property)
2756 if (as_value && cf->get_type()->jsonattrib != NULL
2757 && cf->get_type()->jsonattrib->alias != NULL) {
2758 json.put_next_token(JSON_TOKEN_NAME, "unusedAlias");
2759 char* alias_str = mprintf("\"%s\"", cf->get_type()->jsonattrib->alias);
2760 json.put_next_token(JSON_TOKEN_STRING, alias_str);
2761 Free(alias_str);
2762 }
2763 }
2764
2765 // get the type at the end of the reference chain
2766 Type* last = get_type_refd_last();
2767
2768 // check if this is a reference to another type that has its own definition
2769 Type* refd_type = NULL;
2770 if (is_ref()) {
2771 Type* iter = this;
2772 while (iter->is_ref()) {
2773 iter = iter->get_type_refd();
2774 if (iter->ownertype == OT_TYPE_DEF || /* TTCN-3 type definition */
2775 iter->ownertype == OT_TYPE_ASS) { /* ASN.1 type assignment */
2776 refd_type = iter;
2777 break;
2778 }
2779 }
2780 }
2781
2782 // check if there are any type restrictions
2783 boolean has_restrictions = sub_type != NULL && sub_type->has_json_schema();
2784
2785 // if it's a referenced type, then its schema already exists, only add a pointer to it
2786 // exception: instances of ASN.1 parameterized types, always embed their schemas
2787 if (refd_type != NULL && !get_type_refd()->pard_type_instance) {
2788 if (has_restrictions) {
2789 // an 'allOf' structure is needed if this is a subtype,
2790 // insert the pointer in the first part
2791 json.put_next_token(JSON_TOKEN_NAME, "allOf");
2792 json.put_next_token(JSON_TOKEN_ARRAY_START);
2793 json.put_next_token(JSON_TOKEN_OBJECT_START);
2794 }
2795 json.put_next_token(JSON_TOKEN_NAME, "$ref");
2796 char* ref_str = mprintf("\"#/definitions/%s/%s\"",
2797 refd_type->my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(),
2798 refd_type->get_dispname().c_str());
2799 json.put_next_token(JSON_TOKEN_STRING, ref_str);
2800 Free(ref_str);
2801 if (has_restrictions) {
2802 // close the first part of the 'allOf' and insert the type restrictions
2803 // in the second part
2804 json.put_next_token(JSON_TOKEN_OBJECT_END);
2805 json.put_next_token(JSON_TOKEN_OBJECT_START);
2806
2807 // pass the tokenizer to the subtype to insert the type restrictions' schema
2808 sub_type->generate_json_schema(json);
2809
2810 // close the second part and the 'allOf' structure itself
2811 json.put_next_token(JSON_TOKEN_OBJECT_END);
2812 json.put_next_token(JSON_TOKEN_ARRAY_END);
2813 }
2814 } else {
2815 // generate the schema for the referenced type
2816 switch (last->typetype) {
2817 case T_BOOL:
2818 // use the JSON boolean type
2819 json.put_next_token(JSON_TOKEN_NAME, "type");
2820 json.put_next_token(JSON_TOKEN_STRING, "\"boolean\"");
2821 break;
2822 case T_INT:
2823 case T_INT_A:
2824 // use the JSON integer type
2825 json.put_next_token(JSON_TOKEN_NAME, "type");
2826 json.put_next_token(JSON_TOKEN_STRING, "\"integer\"");
2827 break;
2828 case T_REAL:
2829 if (has_restrictions) {
2830 // adding restrictions after the type's schema wouldn't work here
2831 // if the restrictions affect the special values
2832 // use a special function that generates the schema segment for both
2833 // the float type and its restrictions
2834 sub_type->generate_json_schema_float(json);
2835 has_restrictions = false; // so they aren't generated twice
2836 }
2837 else {
2838 // any of: JSON number or the special values as strings (in an enum)
2839 json.put_next_token(JSON_TOKEN_NAME, "anyOf");
2840 json.put_next_token(JSON_TOKEN_ARRAY_START);
2841 json.put_next_token(JSON_TOKEN_OBJECT_START);
2842 json.put_next_token(JSON_TOKEN_NAME, "type");
2843 json.put_next_token(JSON_TOKEN_STRING, "\"number\"");
2844 json.put_next_token(JSON_TOKEN_OBJECT_END);
2845 json.put_next_token(JSON_TOKEN_OBJECT_START);
2846 json.put_next_token(JSON_TOKEN_NAME, "enum");
2847 json.put_next_token(JSON_TOKEN_ARRAY_START);
2848 json.put_next_token(JSON_TOKEN_STRING, "\"not_a_number\"");
2849 json.put_next_token(JSON_TOKEN_STRING, "\"infinity\"");
2850 json.put_next_token(JSON_TOKEN_STRING, "\"-infinity\"");
2851 json.put_next_token(JSON_TOKEN_ARRAY_END);
2852 json.put_next_token(JSON_TOKEN_OBJECT_END);
2853 json.put_next_token(JSON_TOKEN_ARRAY_END);
2854 }
2855 break;
2856 case T_BSTR:
2857 case T_BSTR_A:
2858 case T_HSTR:
2859 case T_OSTR:
2860 case T_ANY:
2861 // use the JSON string type and add a pattern to only allow bits or hex digits
2862 json.put_next_token(JSON_TOKEN_NAME, "type");
2863 json.put_next_token(JSON_TOKEN_STRING, "\"string\"");
2864 json.put_next_token(JSON_TOKEN_NAME, "subType");
2865 json.put_next_token(JSON_TOKEN_STRING,
2866 (last->typetype == T_OSTR || last->typetype == T_ANY) ? "\"octetstring\"" :
2867 ((last->typetype == T_HSTR) ? "\"hexstring\"" : "\"bitstring\""));
2868 json.put_next_token(JSON_TOKEN_NAME, "pattern");
2869 json.put_next_token(JSON_TOKEN_STRING,
2870 (last->typetype == T_OSTR || last->typetype == T_ANY) ? "\"^([0-9A-Fa-f][0-9A-Fa-f])*$\"" :
2871 ((last->typetype == T_HSTR) ? "\"^[0-9A-Fa-f]*$\"" : "\"^[01]*$\""));
2872 break;
2873 case T_CSTR:
2874 case T_NUMERICSTRING:
2875 case T_PRINTABLESTRING:
2876 case T_IA5STRING:
2877 case T_VISIBLESTRING:
2878 // use the JSON string type and add a "subType" property to distinguish it from
2879 // universal charstring types
2880 json.put_next_token(JSON_TOKEN_NAME, "type");
2881 json.put_next_token(JSON_TOKEN_STRING, "\"string\"");
2882 json.put_next_token(JSON_TOKEN_NAME, "subType");
2883 json.put_next_token(JSON_TOKEN_STRING, "\"charstring\"");
2884 break;
2885 case T_USTR:
2886 case T_GENERALSTRING:
2887 case T_UNIVERSALSTRING:
2888 case T_UTF8STRING:
2889 case T_BMPSTRING:
2890 case T_GRAPHICSTRING:
2891 case T_TELETEXSTRING:
2892 case T_VIDEOTEXSTRING:
2893 // use the JSON string type and add a "subType" property to distinguish it from
2894 // charstring types
2895 json.put_next_token(JSON_TOKEN_NAME, "type");
2896 json.put_next_token(JSON_TOKEN_STRING, "\"string\"");
2897 json.put_next_token(JSON_TOKEN_NAME, "subType");
2898 json.put_next_token(JSON_TOKEN_STRING, "\"universal charstring\"");
2899 break;
2900 case T_OID:
2901 case T_ROID:
2902 json.put_next_token(JSON_TOKEN_NAME, "type");
2903 json.put_next_token(JSON_TOKEN_STRING, "\"string\"");
2904 json.put_next_token(JSON_TOKEN_NAME, "subType");
2905 json.put_next_token(JSON_TOKEN_STRING, "\"objid\"");
2906 json.put_next_token(JSON_TOKEN_NAME, "pattern");
2907 json.put_next_token(JSON_TOKEN_STRING, "\"^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$\"");
2908 break;
2909 case T_VERDICT:
2910 if (has_restrictions) {
2911 // the restrictions would only add another JSON enum (after the one
2912 /// generated below), instead just insert the one with the restrictions
2913 sub_type->generate_json_schema(json);
2914 has_restrictions = false; // so they aren't generated twice
2915 }
2916 else {
2917 // enumerate the possible values
2918 json.put_next_token(JSON_TOKEN_NAME, "enum");
2919 json.put_next_token(JSON_TOKEN_ARRAY_START);
2920 json.put_next_token(JSON_TOKEN_STRING, "\"none\"");
2921 json.put_next_token(JSON_TOKEN_STRING, "\"pass\"");
2922 json.put_next_token(JSON_TOKEN_STRING, "\"inconc\"");
2923 json.put_next_token(JSON_TOKEN_STRING, "\"fail\"");
2924 json.put_next_token(JSON_TOKEN_STRING, "\"error\"");
2925 json.put_next_token(JSON_TOKEN_ARRAY_END);
2926 }
2927 break;
2928 case T_ENUM_T:
2929 case T_ENUM_A:
2930 // enumerate the possible values
2931 json.put_next_token(JSON_TOKEN_NAME, "enum");
2932 json.put_next_token(JSON_TOKEN_ARRAY_START);
2933 for (size_t i = 0; i < last->u.enums.eis->get_nof_eis(); ++i) {
2934 char* enum_str = mprintf("\"%s\"", last->get_ei_byIndex(i)->get_name().get_ttcnname().c_str());
2935 json.put_next_token(JSON_TOKEN_STRING, enum_str);
2936 Free(enum_str);
2937 }
2938 json.put_next_token(JSON_TOKEN_ARRAY_END);
2939 // list the numeric values for the enumerated items
2940 json.put_next_token(JSON_TOKEN_NAME, "numericValues");
2941 json.put_next_token(JSON_TOKEN_ARRAY_START);
2942 for (size_t i = 0; i < last->u.enums.eis->get_nof_eis(); ++i) {
2943 char* num_val_str = mprintf("%lli", last->get_ei_byIndex(i)->get_value()->get_val_Int()->get_val());
2944 json.put_next_token(JSON_TOKEN_NUMBER, num_val_str);
2945 Free(num_val_str);
2946 }
2947 json.put_next_token(JSON_TOKEN_ARRAY_END);
2948 break;
2949 case T_NULL:
2950 // use the JSON null value for the ASN.1 NULL type
2951 json.put_next_token(JSON_TOKEN_NAME, "type");
2952 json.put_next_token(JSON_TOKEN_STRING, "\"null\"");
2953 break;
2954 case T_SEQOF:
2955 case T_SETOF:
2956 case T_ARRAY:
2957 last->generate_json_schema_array(json);
2958 break;
2959 case T_SEQ_T:
2960 case T_SEQ_A:
2961 case T_SET_T:
2962 case T_SET_A:
2963 last->generate_json_schema_record(json);
2964 break;
2965 case T_CHOICE_T:
2966 case T_CHOICE_A:
2967 case T_ANYTYPE:
2968 case T_OPENTYPE:
2969 last->generate_json_schema_union(json);
2970 break;
2971 default:
2972 FATAL_ERROR("Type::generate_json_schema");
2973 }
2974
2975 if (has_restrictions) {
2976 // pass the tokenizer to the subtype to insert the type restrictions' schema
2977 sub_type->generate_json_schema(json);
2978 }
2979 }
2980
2981 // insert default value (if any)
2982 if (jsonattrib != NULL && jsonattrib->default_value != NULL) {
2983 json.put_next_token(JSON_TOKEN_NAME, "default");
2984 switch (last->typetype) {
2985 case T_BOOL:
2986 json.put_next_token((jsonattrib->default_value[0] == 't') ?
2987 JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE);
2988 break;
2989 case T_INT:
2990 case T_REAL:
2991 if (jsonattrib->default_value[0] != 'n' && jsonattrib->default_value[0] != 'i'
2992 && jsonattrib->default_value[1] != 'i') {
2993 json.put_next_token(JSON_TOKEN_NUMBER, jsonattrib->default_value);
2994 break;
2995 }
2996 // no break, insert the special float values as strings
2997 case T_BSTR:
2998 case T_HSTR:
2999 case T_OSTR:
3000 case T_CSTR:
3001 case T_USTR:
3002 case T_VERDICT:
3003 case T_ENUM_T: {
3004 char* default_str = mprintf("\"%s\"", jsonattrib->default_value);
3005 json.put_next_token(JSON_TOKEN_STRING, default_str);
3006 Free(default_str);
3007 break; }
3008 default:
3009 FATAL_ERROR("Type::generate_json_schema");
3010 }
3011 }
3012
3013 // insert schema extensions (if any)
3014 if (jsonattrib != NULL) {
3015 for (size_t i = 0; i < jsonattrib->schema_extensions.size(); ++i) {
3016 json.put_next_token(JSON_TOKEN_NAME, jsonattrib->schema_extensions[i]->key);
3017 char* value_str = mprintf("\"%s\"", jsonattrib->schema_extensions[i]->value);
3018 json.put_next_token(JSON_TOKEN_STRING, value_str);
3019 Free(value_str);
3020 }
3021 }
3022
3023 // end of type's schema
3024 json.put_next_token(JSON_TOKEN_OBJECT_END);
3025 }
3026
3027 void Type::generate_json_schema_array(JSON_Tokenizer& json)
3028 {
3029 // use the JSON array type
3030 json.put_next_token(JSON_TOKEN_NAME, "type");
3031 json.put_next_token(JSON_TOKEN_STRING, "\"array\"");
3032
3033 if (typetype != T_ARRAY) {
3034 // use the "subType" property to distinguish 'record of' from 'set of'
3035 json.put_next_token(JSON_TOKEN_NAME, "subType");
3036 json.put_next_token(JSON_TOKEN_STRING, (typetype == T_SEQOF) ?
3037 "\"record of\"" : "\"set of\"");
3038 } else {
3039 // set the number of elements for arrays
3040 char* size_str = mprintf("%lu", (unsigned long)(get_nof_comps()));
3041 json.put_next_token(JSON_TOKEN_NAME, "minItems");
3042 json.put_next_token(JSON_TOKEN_NUMBER, size_str);
3043 json.put_next_token(JSON_TOKEN_NAME, "maxItems");
3044 json.put_next_token(JSON_TOKEN_NUMBER, size_str);
3045 Free(size_str);
3046 }
3047
3048 // set the element type
3049 json.put_next_token(JSON_TOKEN_NAME, "items");
3050
3051 // pass the tokenizer to the elements' type object to insert its schema
3052 get_ofType()->generate_json_schema(json, true, false);
3053 }
3054
3055 void Type::generate_json_schema_record(JSON_Tokenizer& json)
3056 {
3057 // use the JSON object type
3058 json.put_next_token(JSON_TOKEN_NAME, "type");
3059 json.put_next_token(JSON_TOKEN_STRING, "\"object\"");
3060
3061 // use the "subType" property to distinguish records from sets
3062 json.put_next_token(JSON_TOKEN_NAME, "subType");
3063 json.put_next_token(JSON_TOKEN_STRING, (typetype == T_SEQ_T || typetype == T_SEQ_A) ?
3064 "\"record\"" : "\"set\"");
3065
3066 // set the fields
3067 json.put_next_token(JSON_TOKEN_NAME, "properties");
3068 json.put_next_token(JSON_TOKEN_OBJECT_START);
3069 size_t field_count = get_nof_comps();
3070 bool has_non_optional = false;
3071 for (size_t i = 0; i < field_count; ++i) {
3072 Type* field = get_comp_byIndex(i)->get_type();
3073
3074 // use the field's alias if it has one
3075 json.put_next_token(JSON_TOKEN_NAME,
3076 (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ?
3077 field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str());
3078
3079 // optional fields can also get the JSON null value
3080 if (get_comp_byIndex(i)->get_is_optional()) {
3081 // special case: ASN NULL type, since it uses the JSON literal "null" as a value
3082 if (T_NULL != field->get_type_refd_last()->typetype) {
3083 json.put_next_token(JSON_TOKEN_OBJECT_START);
3084 json.put_next_token(JSON_TOKEN_NAME, "anyOf");
3085 json.put_next_token(JSON_TOKEN_ARRAY_START);
3086 json.put_next_token(JSON_TOKEN_OBJECT_START);
3087 json.put_next_token(JSON_TOKEN_NAME, "type");
3088 json.put_next_token(JSON_TOKEN_STRING, "\"null\"");
3089 json.put_next_token(JSON_TOKEN_OBJECT_END);
3090 }
3091 } else if (!has_non_optional) {
3092 has_non_optional = true;
3093 }
3094
3095 // pass the tokenizer to the field's type to insert its schema
3096 field->generate_json_schema(json, true, false);
3097
3098 // for optional fields: specify the presence of the "omit as null" coding instruction
3099 // and close structures
3100 if (get_comp_byIndex(i)->get_is_optional() &&
3101 T_NULL != field->get_type_refd_last()->typetype) {
3102 json.put_next_token(JSON_TOKEN_ARRAY_END);
3103 json.put_next_token(JSON_TOKEN_NAME, "omitAsNull");
3104 json.put_next_token((field->jsonattrib != NULL && field->jsonattrib->omit_as_null) ?
3105 JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE);
3106 json.put_next_token(JSON_TOKEN_OBJECT_END);
3107 }
3108 }
3109
3110 // end of properties
3111 json.put_next_token(JSON_TOKEN_OBJECT_END);
3112
3113 // do not accept additional fields
3114 json.put_next_token(JSON_TOKEN_NAME, "additionalProperties");
3115 json.put_next_token(JSON_TOKEN_LITERAL_FALSE);
3116
3117 // set the field order
3118 if (field_count > 1) {
3119 json.put_next_token(JSON_TOKEN_NAME, "fieldOrder");
3120 json.put_next_token(JSON_TOKEN_ARRAY_START);
3121 for (size_t i = 0; i < field_count; ++i) {
3122 Type* field = get_comp_byIndex(i)->get_type();
3123 // use the field's alias if it has one
3124 char* field_str = mprintf("\"%s\"",
3125 (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ?
3126 field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str());
3127 json.put_next_token(JSON_TOKEN_STRING, field_str);
3128 Free(field_str);
3129 }
3130 json.put_next_token(JSON_TOKEN_ARRAY_END);
3131 }
3132
3133 // set the required (non-optional) fields
3134 if (has_non_optional) {
3135 json.put_next_token(JSON_TOKEN_NAME, "required");
3136 json.put_next_token(JSON_TOKEN_ARRAY_START);
3137 for (size_t i = 0; i < field_count; ++i) {
3138 if (!get_comp_byIndex(i)->get_is_optional()) {
3139 Type* field = get_comp_byIndex(i)->get_type();
3140 // use the field's alias if it has one
3141 char* field_str = mprintf("\"%s\"",
3142 (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ?
3143 field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str());
3144 json.put_next_token(JSON_TOKEN_STRING, field_str);
3145 Free(field_str);
3146 }
3147 }
3148 json.put_next_token(JSON_TOKEN_ARRAY_END);
3149 }
3150 }
3151
3152 void Type::generate_json_schema_union(JSON_Tokenizer& json)
3153 {
3154 // use an "anyOf" structure containing the union's alternatives
3155 json.put_next_token(JSON_TOKEN_NAME, "anyOf");
3156 json.put_next_token(JSON_TOKEN_ARRAY_START);
3157
3158 for (size_t i = 0; i < get_nof_comps(); ++i) {
3159 Type* field = get_comp_byIndex(i)->get_type();
3160
3161 if (jsonattrib != NULL && jsonattrib->as_value) {
3162 // only add the alternative's schema
3163 field->generate_json_schema(json, true, true);
3164 } else {
3165 // use a JSON object with one key-value pair for each alternative
3166 // the schema is the same as a record's with one field
3167 json.put_next_token(JSON_TOKEN_OBJECT_START);
3168
3169 json.put_next_token(JSON_TOKEN_NAME, "type");
3170 json.put_next_token(JSON_TOKEN_STRING, "\"object\"");
3171
3172 json.put_next_token(JSON_TOKEN_NAME, "properties");
3173 json.put_next_token(JSON_TOKEN_OBJECT_START);
3174
3175 // use the alternative's alias if it has one
3176 json.put_next_token(JSON_TOKEN_NAME,
3177 (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ?
3178 field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str());
3179
3180 // let the alternative's type insert its schema
3181 field->generate_json_schema(json, true, false);
3182
3183 // continue the schema for the record with one field
3184 json.put_next_token(JSON_TOKEN_OBJECT_END);
3185
3186 json.put_next_token(JSON_TOKEN_NAME, "additionalProperties");
3187 json.put_next_token(JSON_TOKEN_LITERAL_FALSE);
3188
3189 // the one field is non-optional
3190 json.put_next_token(JSON_TOKEN_NAME, "required");
3191 json.put_next_token(JSON_TOKEN_ARRAY_START);
3192
3193 // use the alternative's alias here as well
3194 char* field_str = mprintf("\"%s\"",
3195 (field->jsonattrib != NULL && field->jsonattrib->alias != NULL) ?
3196 field->jsonattrib->alias : get_comp_byIndex(i)->get_name().get_ttcnname().c_str());
3197 json.put_next_token(JSON_TOKEN_STRING, field_str);
3198 Free(field_str);
3199
3200 json.put_next_token(JSON_TOKEN_ARRAY_END);
3201
3202 json.put_next_token(JSON_TOKEN_OBJECT_END);
3203 }
3204 }
3205
3206 // close the "anyOf" array
3207 json.put_next_token(JSON_TOKEN_ARRAY_END);
3208 }
3209
3210 void Type::generate_json_schema_ref(JSON_Tokenizer& json)
3211 {
3212 // start the object containing the reference
3213 json.put_next_token(JSON_TOKEN_OBJECT_START);
3214
3215 // insert the reference
3216 json.put_next_token(JSON_TOKEN_NAME, "$ref");
3217 char* ref_str = mprintf("\"#/definitions/%s/%s\"",
3218 my_scope->get_scope_mod()->get_modid().get_ttcnname().c_str(),
3219 get_dispname().c_str());
3220 json.put_next_token(JSON_TOKEN_STRING, ref_str);
3221 Free(ref_str);
3222
3223 // the object will be closed later, as it may contain other properties
3224 }
3225
3226
3227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3228
3229 } // namespace Common
This page took 0.107713 seconds and 5 git commands to generate.