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
17 ******************************************************************************/
18 #include "../common/dbgnew.hh"
20 #include "CompField.hh"
21 #include "EnumItem.hh"
22 #include "SigParam.hh"
28 #include "record_of.h"
29 #include "functionref.h"
32 #include "ttcn3/Ttcnstuff.hh"
33 #include "ttcn3/ArrayDimensions.hh"
34 #include "ttcn3/Attributes.hh"
35 #include "ttcn3/signature.h"
36 #include "XerAttributes.hh"
38 #include "asn1/TableConstraint.hh"
39 #include "asn1/Object.hh"
40 #include "asn1/Tag.hh"
41 #include "asn1/Ref.hh"
43 #include "CodeGenHelper.hh"
45 #include "../common/JSON_Tokenizer.hh"
50 using Ttcn::SingleWithAttrib
;
52 void Type::generate_code(output_struct
*target
)
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
);
67 generate_code_Enum(target
);
73 generate_code_Choice(target
);
79 generate_code_Se(target
);
83 generate_code_SeOf(target
);
86 u
.port
->generate_code(target
);
89 generate_code_Array(target
);
92 generate_code_Signature(target
);
97 generate_code_Fat(target
);
100 generate_code_alias(target
);
104 generate_code_embedded_after(target
);
106 if (has_done_attribute()) generate_code_done(target
);
107 if (sub_type
) sub_type
->generate_code(*target
);
111 void Type::generate_code_include(const string
& sourcefile
, output_struct
*target
)
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
,
117 "class %s_template;\n",
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());
126 void Type::generate_code_embedded_before(output_struct
*target
)
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()
143 CodeGenHelper::GetInstance().finalize_generation(
144 cf
->get_type()->get_type_refd_last()
146 // escape from recursion loops
147 if (code_generated
) break;
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
);
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
);
171 if (u
.signature
.return_type
)
172 u
.signature
.return_type
->generate_code(target
);
175 u
.array
.element_type
->generate_code(target
);
182 void Type::generate_code_embedded_after(output_struct
*target
)
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
);
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
);
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
);
221 // generate code for the embedded type
222 if (!u
.seof
.ofType
->is_pure_refd()) u
.seof
.ofType
->generate_code(target
);
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
);
238 void Type::generate_code_typedescriptor(output_struct
*target
)
240 bool force_xer
= false;
241 switch (get_type_refd_last()->typetype
) {
244 // do not generate any type descriptor for these non-data types
257 force_xer
= has_encoding(CT_XER
); // && (is_ref() || (xerattrib && !xerattrib->empty()));
261 } // switch(ownertype)
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);
270 // FIXME: force_xer should be elminated. if a type needs a descriptor,
271 // it should say so via get_genname_typedescriptor()
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.
277 if (gennametypedescriptor
== gennameown
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
);
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
);
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
);
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());
302 const string
& gennamejsondescriptor
= get_genname_jsondescriptor();
303 bool generate_json
= has_encoding(CT_JSON
) && enable_json() &&
304 gennamejsondescriptor
== gennameown
;
306 generate_code_jsondescriptor(target
);
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());
319 target
->source
.global_vars
=mputprintf
320 (target
->source
.global_vars
,
321 "&%s_ber_, ", gennameberdescriptor
.c_str());
323 target
->source
.global_vars
=mputstr
324 (target
->source
.global_vars
, "NULL, ");
327 target
->source
.global_vars
=mputprintf
328 (target
->source
.global_vars
,
329 "&%s_raw_, ", gennamerawdescriptor
.c_str());
331 target
->source
.global_vars
=mputstr
332 (target
->source
.global_vars
, "NULL, ");
335 target
->source
.global_vars
=mputprintf
336 (target
->source
.global_vars
,
337 "&%s_text_, ", gennametextdescriptor
.c_str());
339 target
->source
.global_vars
=mputstr
340 (target
->source
.global_vars
, "NULL, ");
343 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
344 "&%s_xer_, ", gennamexerdescriptor
.c_str());
346 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
350 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
351 "&%s_json_, ", gennamejsondescriptor
.c_str());
353 switch(get_type_refd_last()->typetype
) {
365 case T_NUMERICSTRING
:
366 case T_PRINTABLESTRING
:
367 case T_TELETEXSTRING
:
368 case T_VIDEOTEXSTRING
:
370 case T_GRAPHICSTRING
:
371 case T_VISIBLESTRING
:
372 case T_GENERALSTRING
:
373 case T_UNIVERSALSTRING
:
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());
386 // use a predefined JSON descriptor for enumerated types
387 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
388 "&ENUMERATED_json_, ");
391 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
402 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
406 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
407 "TTCN_Typedescriptor_t::%s };\n"
411 , get_genname_typedescr_asnbasetype());
413 // the type uses the type descriptor of another type
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());
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())
431 } // if (gennameown == gennametypedescriptor)
434 void Type::generate_code_berdescriptor(output_struct
*target
)
436 const char *gennameown_str
= get_genname_own().c_str();
437 char *str
= mprintf("static const ASN_Tag_t %s_tag_[] = { ",
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());
448 str
= mputstr(str
, "};\n");
449 target
->source
.global_vars
= mputstr(target
->source
.global_vars
, 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
);
458 static const char* whitespace_action
[3] = {"PRESERVE", "REPLACE", "COLLAPSE"};
460 extern void change_name(string
&name
, XerAttributes::NameChange change
);
461 // implemented in Type_chk.cc
463 void Type::generate_code_xerdescriptor(output_struct
* target
)
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
);
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)
477 if ('&'==last_s
[0] // object class field ?
478 ||'<'==last_s
[0]) { // <oftype> and the like
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" */
487 else { // probably a built-in type, punt with the C++ class name
488 last_s
= ot
->get_genname_value(0);
495 // Name for basic XER which ignores all the EXER fanciness
496 string
bxer_name(last_s
);
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;
506 char* oftype_descr_name
= 0;
508 change_name(last_s
, xerattrib
->name_
);
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
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_
;
539 if (xerattrib
->defaultValue_
) {
540 Type
*t
= xerattrib
->defaultValue_
->get_my_governor();
541 dfe_str
= xerattrib
->defaultValue_
->get_genname_own().c_str();
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
);
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_
;
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_
;
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
);
573 Type
*last
= get_type_refd_last();
574 has_1untag
= last
->is_secho() && last
->u
.secho
.has_single_charenc
; // does not come from xerattrib
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
) {
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_
);
594 size_t last_len
= 2 + last_s
.size(); // 2 for > \n
595 size_t bxer_len
= 2 + bxer_name
.size(); // 2 for > \n
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());
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
] : "");
615 target
->source
.global_vars
= mputstrn(target
->source
.global_vars
, "};\n", 3);
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",
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"),
651 (ns_uris_var
? ns_uris_var
: "NULL"),
652 (oftype_descr_name
? oftype_descr_name
: "NULL")
656 Free(oftype_descr_name
);
659 void Type::generate_code_rawdescriptor(output_struct
*target
)
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_ = {",
666 if (rawattrib
->intx
) {
667 str
= mputstr(str
, "RAW_INTX,");
670 str
= mputprintf(str
, "%d,", rawattrib
->fieldlength
);
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
);
713 void Type::generate_code_textdescriptor(output_struct
*target
)
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
) {
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());
730 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
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());
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());
747 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
756 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
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());
773 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
776 union_member_name
= mprintf("(TTCN_TEXTdescriptor_param_values*)"
777 "&%s_bool_", gennameown_str
);
781 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
782 "static const TTCN_TEXTdescriptor_enum %s_enum_[] = { ",
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());
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
,
801 // a pattern must be always present for decoding
802 const char *decode_token
;
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
;
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();
815 // take the case sensitivity from the attribute
816 case_sensitive
= textattrib
->field_params
[i
]->value
.case_sensitive
;
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;
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());
830 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
832 union_member_name
= mprintf(
833 "(TTCN_TEXTdescriptor_param_values*)%s_enum_", gennameown_str
);
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_ = {",
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
);
865 union_member_name
=mprintf("&%s_par_", gennameown_str
);
870 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
871 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
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
);
888 union_member_name
=mprintf("&%s_par_", gennameown_str
);
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
);
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());
904 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
915 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
923 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
934 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
944 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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());
956 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
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());
967 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
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
);
976 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
981 void Type::generate_code_jsondescriptor(output_struct
*target
)
983 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
984 "extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str());
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());
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");
1008 void Type::generate_code_alias(output_struct
*target
)
1010 if (!needs_alias()) return;
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();
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
);
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
);
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
);
1039 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1040 "typedef %s_template %s_template;\n",
1041 refd_name
, own_name
);
1043 default: // value and template classes exist
1044 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1046 "// written by %s in " __FILE__
" at %d\n"
1049 "typedef %s_template %s_template;\n",
1051 __FUNCTION__
, __LINE__
,
1053 refd_name
, own_name
, refd_name
, own_name
);
1058 void Type::generate_code_Enum(output_struct
*target
)
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
);
1076 e_def
.xerUseNumber
= xerattrib
->useNumber_
;
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;
1084 e_def
.xerText
= TRUE
;
1085 e_def
.elements
[i
].text
= ei
->get_text().c_str();
1087 e_def
.elements
[i
].value
= ei
->get_value()->get_val_Int()->get_val();
1090 defEnumClass(&e_def
, target
);
1091 defEnumTemplate(&e_def
, target
);
1093 Free(e_def
.elements
);
1096 void Type::generate_code_Choice(output_struct
*target
)
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!
1109 sdef
.kind
= ANYTYPE
;
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
) {
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
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;
1144 sdef
.jsonAsValue
= jsonattrib
->as_value
;
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();
1157 if (cftype
->has_empty_xml()) sdef
.exerMaybeEmptyIndex
= i
;
1158 // This will overwrite lower values, which is what we want.
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
;
1166 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
;
1169 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
| JSON_STRING
;
1172 sdef
.elements
[i
].jsonValueType
= JSON_BOOLEAN
;
1175 sdef
.elements
[i
].jsonValueType
= JSON_NULL
;
1184 case T_NUMERICSTRING
:
1185 case T_PRINTABLESTRING
:
1186 case T_TELETEXSTRING
:
1187 case T_VIDEOTEXSTRING
:
1189 case T_GRAPHICSTRING
:
1190 case T_VISIBLESTRING
:
1191 case T_GENERALSTRING
:
1192 case T_UNIVERSALSTRING
:
1200 sdef
.elements
[i
].jsonValueType
= JSON_STRING
;
1210 sdef
.elements
[i
].jsonValueType
= JSON_OBJECT
;
1215 sdef
.elements
[i
].jsonValueType
= JSON_ARRAY
;
1218 FATAL_ERROR("Type::generate_code_Choice - invalid field type %d", tt
);
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
;
1230 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
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
;
1250 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1251 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
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();
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
));
1266 for (int b
= 1; b
< key
->nElements
; b
++) {
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;
1288 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1290 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1292 t2
= t
->get_comp_byIndex(i
)->get_type();
1293 if(t2
->get_raw_length() >= 0){
1295 key
->start_pos
+= t2
->rawattrib
->padding
;
1296 key
->start_pos
+= t2
->get_raw_length();
1297 }else key
->start_pos
= -1;
1300 t
= field_type
->get_type_refd_last();
1304 } else sdef
.hasRaw
=false;
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_
;
1314 defUnionClass(&sdef
, target
);
1315 defUnionTemplate(&sdef
, target
);
1317 free_code_ot(sdef
.ot
);
1320 free_raw_attrib_struct(&sdef
.raw
);
1322 Free(sdef
.elements
);
1325 Opentype_t
*Type::generate_code_ot(stringpool
& pool
)
1327 using namespace Asn
;
1328 if(typetype
!=T_OPENTYPE
)
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());
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
));
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
++) {
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();
1366 const Identifier
*oc_fieldname_t
1367 =u
.secho
.my_tableconstraint
->get_oc_fieldname();
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
++;
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
));
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;
1406 oa_t
->const_valuenames
[j
] =
1407 pool
.add(t_value
->get_genname_own(my_scope
));
1408 differs_from_prev
=true;
1410 val_prev
[j
]=t_value
;
1412 differs_from_prev
=false;
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
));
1422 void Type::free_code_ot(Opentype_t
* p_ot
)
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
);
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
);
1436 size_t Type::get_codegen_index(size_t index
)
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()
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();
1456 FATAL_ERROR("Type::get_codegen_index()");
1461 void Type::generate_code_Se(output_struct
*target
)
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);
1488 FATAL_ERROR("Type::generate_code_Se()");
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();
1495 sdef
.hasXer
= has_encoding(CT_XER
);
1496 sdef
.hasJson
= has_encoding(CT_JSON
);
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();
1514 sdef
.xerUseQName
= xerattrib
->useQName_
;
1515 if (xerattrib
->useType_
|| xerattrib
->useUnion_
) {
1516 FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record
1519 sdef
.elements
= (struct_field
*)
1520 Malloc(sdef
.totalElements
*sizeof(*sdef
.elements
));
1521 memset(sdef
.elements
, 0, sdef
.totalElements
* sizeof(*sdef
.elements
));
1523 /* This sorting is because of CER coding of SET types, see X.690
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
);
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();
1539 for(size_t i
=0; i
<sdef
.nElements
; i
++)
1540 se_comps
.add(get_comp_byIndex(i
));
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();
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();
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();
1570 if (type
->xerattrib
) {
1571 cur
.xerAttribute
= type
->xerattrib
->attribute_
;
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
];
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
];
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
;
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();
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();
1620 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
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
;
1640 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1641 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
1643 key
->fields
=(rawAST_coding_fields
*)
1644 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1646 CompField
*cf
=get_comp_byIndex(sdef
.raw
.taglist
.list
[c
].fieldnum
);
1647 Type
*t
=cf
->get_type()->get_type_refd_last();
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
));
1660 for (int b
= 1; b
< key
->nElements
; b
++) {
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;
1682 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1684 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1686 t2
= t
->get_comp_byIndex(i
)->get_type();
1687 if(t2
->get_raw_length() >= 0){
1689 key
->start_pos
+= t2
->rawattrib
->padding
;
1690 key
->start_pos
+= t2
->get_raw_length();
1691 }else key
->start_pos
= -1;
1694 t
= field_type
->get_type_refd_last();
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
));
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();
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
);
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
;
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
);
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
));
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();
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
;
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
));
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();
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
;
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
));
1839 for (int b
= 0; b
< key
->nElements
; b
++) {
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();
1860 sdef
.elements
[i
].raw
.length
= t_field
->get_raw_length();
1861 sdef
.elements
[i
].hasRaw
=true;
1864 sdef
.elements
[i
].hasRaw
=false;
1869 for(size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1870 sdef
.elements
[i
].hasRaw
=false;
1875 defRecordClass(&sdef
, target
);
1876 defRecordTemplate(&sdef
, target
);
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
);
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
);
1891 Free(sdef
.elements
);
1894 bool Type::is_untagged() const { return xerattrib
&& xerattrib
->untagged_
; }
1896 void Type::generate_code_SeOf(output_struct
*target
)
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";
1902 if (is_pregenerated()) {
1903 switch(oftypelast
->typetype
) {
1906 case T_TELETEXSTRING
:
1907 case T_VIDEOTEXSTRING
:
1908 case T_GRAPHICSTRING
:
1909 case T_GENERALSTRING
:
1910 case T_UNIVERSALSTRING
:
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());
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());
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
);
1946 //sofdef.xerList = xerattrib->list_;
1947 sofdef
.xerAttribute
= xerattrib
->attribute_
;
1949 // If a record of UTF8String, we need to prepare for ANY-ATTRIBUTES and
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();
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();
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());
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
1994 else if (pcft
== this) found_self
= true;
1996 } // if parent is record
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.
2003 case T_ENUM_A
: case T_ENUM_T
:
2005 sofdef
.xmlValueList
= TRUE
;
2009 sofdef
.xmlValueList
= FALSE
;
2014 copy_rawAST_to_struct(rawattrib
,&(sofdef
.raw
));
2016 } else sofdef
.hasRaw
=false;
2018 if (optimized_memalloc
) {
2019 defRecordOfClassMemAllocOptimized(&sofdef
, target
);
2021 defRecordOfClass(&sofdef
, target
);
2023 defRecordOfTemplate(&sofdef
, target
);
2025 if (sofdef
.nFollowers
) {
2026 Free(sofdef
.followers
);
2030 void Type::generate_code_Array(output_struct
*target
)
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"
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());
2047 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
2049 "// written by %s in " __FILE__
" at %d\n"
2053 __FUNCTION__
, __LINE__
,
2055 u
.array
.dimension
->get_value_type(u
.array
.element_type
, my_scope
).c_str(),
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(),
2064 void Type::generate_code_Fat(output_struct
*target
)
2067 memset(&fdef
, 0, sizeof(fdef
));
2068 fdef
.name
= get_genname_own().c_str();
2069 fdef
.dispname
= get_fullname().c_str();
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
;
2082 fdef
.return_type
= NULL
;
2083 fdef
.type
= ALTSTEP
;
2086 fdef
.return_type
= NULL
;
2087 fdef
.type
= TESTCASE
;
2090 FATAL_ERROR("Type::generate_code_Fat()");
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
, ", ");
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");
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();
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
);
2125 void Type::generate_code_Signature(output_struct
*target
)
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
;
2145 case SignatureParam::PARAM_OUT
:
2146 sdef
.parameters
.elements
[i
].direction
= PAR_OUT
;
2148 case SignatureParam::PARAM_INOUT
:
2149 sdef
.parameters
.elements
[i
].direction
= PAR_INOUT
;
2152 FATAL_ERROR("Type::generate_code_Signature()");
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();
2161 sdef
.parameters
.nElements
= 0;
2162 sdef
.parameters
.elements
= NULL
;
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());
2177 sdef
.exceptions
.nElements
= 0;
2178 sdef
.exceptions
.elements
= NULL
;
2180 defSignatureClasses(&sdef
, target
);
2181 Free(sdef
.parameters
.elements
);
2182 Free(sdef
.exceptions
.elements
);
2185 bool Type::needs_alias()
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;
2201 void Type::generate_code_done(output_struct
*target
)
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"
2217 "if (!component_reference.is_bound()) "
2218 "TTCN_error(\"Performing a done operation on an unbound component "
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"
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"
2248 "} else return ret_val;\n"
2250 genname_str
, genname_str
, dispname_str
, genname_str
, dispname_str
,
2251 dispname_str
, omit_in_value_list
? ", TRUE" : "");
2254 bool Type::ispresent_anyvalue_embedded_field(Type
* t
,
2255 Ttcn::FieldOrArrayRefs
*subrefs
, size_t begin_index
)
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
) {
2275 if (cf
->get_is_optional()) return false;
2278 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2282 case Ttcn::FieldOrArrayRef::ARRAY_REF
:
2283 switch (t
->typetype
) {
2286 return false; // (the existence of a record of element is optional)
2288 t
= t
->u
.array
.element_type
;
2291 return true; // string types
2295 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
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
,
2306 if (!subrefs
) return;
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;
2322 bool anyval_ret_val
= true;
2324 anyval_ret_val
= ispresent_anyvalue_embedded_field(t
, subrefs
, i
);
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"
2335 "case SPECIFIC_VALUE: {\n",
2336 tmp_generalid_str
, global_id
.c_str(), global_id
.c_str(),
2337 anyval_ret_val
? "true" : "false");
2339 expstring_t closing_brackets_switch
= mprintf(
2347 global_id
.c_str(), closing_brackets
);
2348 Free(closing_brackets
);
2349 closing_brackets
= closing_brackets_switch
;
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();
2360 switch (t
->typetype
) {
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(),
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
2379 FATAL_ERROR("Type::generate_code_isbound()");
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
;
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());
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"
2403 "case OPTIONAL_OMIT:\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
);
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
);
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
);
2429 expr
->expr
= mputprintf(expr
->expr
,
2433 expr
->expr
= mputprintf(expr
->expr
,
2434 "switch (%s.get_selection()) {\n"
2435 "case OPTIONAL_UNBOUND:\n"
2436 "case OPTIONAL_OMIT:\n"
2442 tmp_id_str
, global_id
.c_str());
2443 Free(tmp_generalid_str
);
2444 tmp_generalid_str
= mcopystr(tmp_id_str
);
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
;
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
);
2460 expr
->expr
= mputprintf(expr
->expr
,
2461 "%s = %s.is_bound();\n", global_id
.c_str(),
2463 Free(tmp_generalid_str
);
2464 tmp_generalid_str
= mcopystr(tmp_id2_str
);
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
;
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());
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
);
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
) {
2497 embedded_type
= t
->u
.seof
.ofType
;
2501 embedded_type
= t
->u
.array
.element_type
;
2511 case T_NUMERICSTRING
:
2512 case T_PRINTABLESTRING
:
2513 case T_TELETEXSTRING
:
2514 case T_VIDEOTEXSTRING
:
2516 case T_GRAPHICSTRING
:
2517 case T_VISIBLESTRING
:
2518 case T_GENERALSTRING
:
2519 case T_UNIVERSALSTRING
:
2522 case T_GENERALIZEDTIME
:
2523 case T_OBJECTDESCRIPTOR
:
2524 if (subrefs
->refers_to_string_element()) {
2525 FATAL_ERROR("Type::generate_code_isbound()");
2527 subrefs
->set_string_element_ref();
2528 // string elements have the same type as the string itself
2530 is_string_element
= true;
2534 FATAL_ERROR("Type::generate_code_isbound()");
2537 next_t
= embedded_type
;
2539 // check the index value
2540 Value
*index_value
= ref
->get_val();
2541 Value
*v_last
= index_value
->get_value_refd_last();
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());
2547 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2548 Free(closing_brackets
);
2549 closing_brackets
= closing_brackets2
;
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()" ),
2558 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2560 closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2561 Free(closing_brackets
);
2562 closing_brackets
= closing_brackets2
;
2564 const string
& tmp_id
= module
->get_temporary_id();
2565 const char *tmp_id_str
= tmp_id
.c_str();
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" : "");
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
,
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
,
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" : "");
2594 Free(tmp_generalid_str
);
2595 tmp_generalid_str
= mcopystr(tmp_id_str
);
2597 // change t to the embedded type
2601 FATAL_ERROR("Type::generate_code_isbound(): invalid reference type");
2605 Free(tmp_generalid_str
);
2606 expr
->expr
= mputstr(expr
->expr
, closing_brackets
);
2607 Free(closing_brackets
);
2610 string
Type::get_optimize_attribute()
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)))
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)
2628 string spec_optimize_for_what
= spec
.substr(9);
2629 return spec_optimize_for_what
;
2637 string
Type::get_sourcefile_attribute()
2641 vector
<SingleWithAttrib
> const &real_attribs
2642 = w_attrib_path
->get_real_attrib();
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)))
2652 const string
& spec
= temp_single
->get_attribSpec().get_spec();
2653 if (spec
.find("sourcefile:")==0 && spec
.size()>11)
2655 string spec_filename
= spec
.substr(11);
2656 // TODO: check if string can be a valid filename
2657 return spec_filename
;
2665 bool Type::has_done_attribute()
2669 vector
<SingleWithAttrib
> const &real_attribs
2670 = w_attrib_path
->get_real_attrib();
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")
2688 void Type::generate_code_object(const_def
*cdef
, Scope
*p_scope
,
2689 const string
& name
, const char *prefix
, bool is_template
)
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();
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
);
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
);
2710 void Type::generate_code_object(const_def
*cdef
, GovernedSimple
*p_setting
)
2712 bool is_template
= false;
2713 switch (p_setting
->get_st()) {
2720 FATAL_ERROR("Type::generate_code_object()");
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());
2726 generate_code_object(cdef
, p_setting
->get_my_scope(),
2727 p_setting
->get_genname_own(), p_setting
->get_genname_prefix(),
2731 void Type::generate_json_schema(JSON_Tokenizer
& json
, bool embedded
, bool as_value
)
2733 // add a new property for the type if it has its own definition
2735 json
.put_next_token(JSON_TOKEN_NAME
, get_dispname().c_str());
2738 // create an object containing the type's schema
2739 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
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
);
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
);
2765 // get the type at the end of the reference chain
2766 Type
* last
= get_type_refd_last();
2768 // check if this is a reference to another type that has its own definition
2769 Type
* refd_type
= NULL
;
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 */
2782 // check if there are any type restrictions
2783 boolean has_restrictions
= sub_type
!= NULL
&& sub_type
->has_json_schema();
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
);
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
);
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
);
2807 // pass the tokenizer to the subtype to insert the type restrictions' schema
2808 sub_type
->generate_json_schema(json
);
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
);
2815 // generate the schema for the referenced type
2816 switch (last
->typetype
) {
2818 // use the JSON boolean type
2819 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2820 json
.put_next_token(JSON_TOKEN_STRING
, "\"boolean\"");
2824 // use the JSON integer type
2825 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2826 json
.put_next_token(JSON_TOKEN_STRING
, "\"integer\"");
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
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
);
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]*$\""));
2874 case T_NUMERICSTRING
:
2875 case T_PRINTABLESTRING
:
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\"");
2886 case T_GENERALSTRING
:
2887 case T_UNIVERSALSTRING
:
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
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\"");
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]+))*$\"");
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
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
);
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
);
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
);
2947 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
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\"");
2957 last
->generate_json_schema_array(json
);
2963 last
->generate_json_schema_record(json
);
2969 last
->generate_json_schema_union(json
);
2972 FATAL_ERROR("Type::generate_json_schema");
2975 if (has_restrictions
) {
2976 // pass the tokenizer to the subtype to insert the type restrictions' schema
2977 sub_type
->generate_json_schema(json
);
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
) {
2986 json
.put_next_token((jsonattrib
->default_value
[0] == 't') ?
2987 JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
);
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
);
2996 // no break, insert the special float values as strings
3004 char* default_str
= mprintf("\"%s\"", jsonattrib
->default_value
);
3005 json
.put_next_token(JSON_TOKEN_STRING
, default_str
);
3009 FATAL_ERROR("Type::generate_json_schema");
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
);
3023 // end of type's schema
3024 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3027 void Type::generate_json_schema_array(JSON_Tokenizer
& json
)
3029 // use the JSON array type
3030 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3031 json
.put_next_token(JSON_TOKEN_STRING
, "\"array\"");
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\"");
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
);
3048 // set the element type
3049 json
.put_next_token(JSON_TOKEN_NAME
, "items");
3051 // pass the tokenizer to the elements' type object to insert its schema
3052 get_ofType()->generate_json_schema(json
, true, false);
3055 void Type::generate_json_schema_record(JSON_Tokenizer
& json
)
3057 // use the JSON object type
3058 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3059 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
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\"");
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();
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());
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
);
3091 } else if (!has_non_optional
) {
3092 has_non_optional
= true;
3095 // pass the tokenizer to the field's type to insert its schema
3096 field
->generate_json_schema(json
, true, false);
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
);
3110 // end of properties
3111 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3113 // do not accept additional fields
3114 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3115 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
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
);
3130 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
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
);
3148 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3152 void Type::generate_json_schema_union(JSON_Tokenizer
& json
)
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
);
3158 for (size_t i
= 0; i
< get_nof_comps(); ++i
) {
3159 Type
* field
= get_comp_byIndex(i
)->get_type();
3161 if (jsonattrib
!= NULL
&& jsonattrib
->as_value
) {
3162 // only add the alternative's schema
3163 field
->generate_json_schema(json
, true, true);
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
);
3169 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3170 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
3172 json
.put_next_token(JSON_TOKEN_NAME
, "properties");
3173 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
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());
3180 // let the alternative's type insert its schema
3181 field
->generate_json_schema(json
, true, false);
3183 // continue the schema for the record with one field
3184 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3186 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3187 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
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
);
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
);
3200 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3202 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3206 // close the "anyOf" array
3207 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3210 void Type::generate_json_schema_ref(JSON_Tokenizer
& json
)
3212 // start the object containing the reference
3213 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
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
);
3223 // the object will be closed later, as it may contain other properties
3227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3229 } // namespace Common