1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "../common/dbgnew.hh"
10 #include "CompField.hh"
11 #include "EnumItem.hh"
12 #include "SigParam.hh"
18 #include "record_of.h"
19 #include "functionref.h"
22 #include "ttcn3/Ttcnstuff.hh"
23 #include "ttcn3/ArrayDimensions.hh"
24 #include "ttcn3/Attributes.hh"
25 #include "ttcn3/signature.h"
26 #include "XerAttributes.hh"
28 #include "asn1/TableConstraint.hh"
29 #include "asn1/Object.hh"
30 #include "asn1/Tag.hh"
31 #include "asn1/Ref.hh"
33 #include "CodeGenHelper.hh"
35 #include "../common/JSON_Tokenizer.hh"
40 using Ttcn::SingleWithAttrib
;
42 void Type::generate_code(output_struct
*target
)
44 if (code_generated
) return;
45 generate_code_embedded_before(target
);
46 // escape from recursion loops
47 if (code_generated
) return;
48 code_generated
= true;
49 generate_code_typedescriptor(target
);
50 string sourcefile
= get_sourcefile_attribute();
51 if (!sourcefile
.empty()) {
52 generate_code_include(sourcefile
, target
);
57 generate_code_Enum(target
);
63 generate_code_Choice(target
);
69 generate_code_Se(target
);
73 generate_code_SeOf(target
);
76 u
.port
->generate_code(target
);
79 generate_code_Array(target
);
82 generate_code_Signature(target
);
87 generate_code_Fat(target
);
90 generate_code_alias(target
);
94 generate_code_embedded_after(target
);
96 if (has_done_attribute()) generate_code_done(target
);
97 if (sub_type
) sub_type
->generate_code(*target
);
101 void Type::generate_code_include(const string
& sourcefile
, output_struct
*target
)
103 const char* name
= get_genname_own().c_str();
104 const char* dispname
= get_fullname().c_str();
105 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
107 "class %s_template;\n",
110 target
->header
.class_defs
= mputprintf(target
->header
.class_defs
,
111 "// Implementation of type %s\n"
112 "#include \"%s.hh\"\n",
113 dispname
, sourcefile
.c_str());
116 void Type::generate_code_embedded_before(output_struct
*target
)
123 size_t nof_comps
= get_nof_comps();
124 for (size_t i
= 0; i
< nof_comps
; i
++) {
125 CompField
*cf
= get_comp_byIndex(i
);
126 if (!cf
->get_is_optional()) {
127 // generate code for mandatory record/set fields only
128 cf
->get_type()->generate_code(
129 CodeGenHelper::GetInstance().get_outputstruct(
130 cf
->get_type()->get_type_refd_last()
133 CodeGenHelper::GetInstance().finalize_generation(
134 cf
->get_type()->get_type_refd_last()
136 // escape from recursion loops
137 if (code_generated
) break;
145 Type
*type_refd
= get_type_refd();
146 // generate code for the referenced type only if it is defined
147 // in the same module
148 if (my_scope
->get_scope_mod_gen() ==
149 type_refd
->my_scope
->get_scope_mod_gen())
150 type_refd
->generate_code(target
);
153 // the parameter types and the return type shall be generated
154 if (u
.signature
.parameters
) {
155 size_t nof_params
= u
.signature
.parameters
->get_nof_params();
156 for (size_t i
= 0; i
< nof_params
; i
++) {
157 u
.signature
.parameters
->get_param_byIndex(i
)->get_type()
158 ->generate_code(target
);
161 if (u
.signature
.return_type
)
162 u
.signature
.return_type
->generate_code(target
);
165 u
.array
.element_type
->generate_code(target
);
172 void Type::generate_code_embedded_after(output_struct
*target
)
179 size_t nof_comps
= get_nof_comps();
180 for (size_t i
= 0; i
< nof_comps
; i
++) {
181 CompField
*cf
= get_comp_byIndex(i
);
182 if (cf
->get_is_optional()) {
183 // generate code for optional record/set fields only
184 // mandatory fields are already completed
185 Type
*t
= cf
->get_type();
186 if (!t
->is_pure_refd()) t
->generate_code(target
);
193 size_t nof_comps
= get_nof_comps();
194 for (size_t i
= 0; i
< nof_comps
; i
++) {
195 // generate code for all union fields
196 Type
*t
= get_comp_byIndex(i
)->get_type();
197 if (!t
->is_pure_refd()) t
->generate_code(target
);
201 if (u
.secho
.my_tableconstraint
) {
202 // generate code for all embedded settings of the object set
203 // that is used in the table constraint
204 Asn::ObjectSet
*os
= u
.secho
.my_tableconstraint
->get_os();
205 if (os
->get_my_scope()->get_scope_mod_gen() ==
206 my_scope
->get_scope_mod_gen()) os
->generate_code(target
);
211 // generate code for the embedded type
212 if (!u
.seof
.ofType
->is_pure_refd()) u
.seof
.ofType
->generate_code(target
);
217 size_t nof_params
= u
.fatref
.fp_list
->get_nof_fps();
218 for(size_t i
= 0; i
< nof_params
; i
++) {
219 u
.fatref
.fp_list
->get_fp_byIndex(i
)->get_Type()
220 ->generate_code(target
);
228 void Type::generate_code_typedescriptor(output_struct
*target
)
230 bool force_xer
= false;
231 switch (get_type_refd_last()->typetype
) {
234 // do not generate any type descriptor for these non-data types
247 force_xer
= has_encoding(CT_XER
); // && (is_ref() || (xerattrib && !xerattrib->empty()));
251 } // switch(ownertype)
255 const string
& gennameown
= get_genname_own();
256 const char *gennameown_str
= gennameown
.c_str();
257 const string
& gennametypedescriptor
= get_genname_typedescriptor(my_scope
);
258 //printf("generate_code_typedescriptor(%s)\n", gennameown_str);
260 // FIXME: force_xer should be elminated. if a type needs a descriptor,
261 // it should say so via get_genname_typedescriptor()
263 /* genname{type,ber,raw,text,xer}descriptor == gennameown is true if
264 * the type needs its own {type,ber,raw,text,xer}descriptor
265 * and can't use the descriptor of one of the built-in types.
267 if (gennametypedescriptor
== gennameown
269 // the type has its own type descriptor
270 bool generate_ber
= has_encoding(CT_BER
) && enable_ber();
271 const string
& gennameberdescriptor
= get_genname_berdescriptor();
272 if (generate_ber
&& gennameberdescriptor
== gennameown
)
273 generate_code_berdescriptor(target
);
275 bool generate_raw
= has_encoding(CT_RAW
) && enable_raw();
276 const string
& gennamerawdescriptor
= get_genname_rawdescriptor();
277 if (generate_raw
&& gennamerawdescriptor
== gennameown
)
278 generate_code_rawdescriptor(target
);
280 bool generate_text
= has_encoding(CT_TEXT
) && enable_text();
281 const string
& gennametextdescriptor
= get_genname_textdescriptor();
282 if (generate_text
&& gennametextdescriptor
== gennameown
)
283 generate_code_textdescriptor(target
);
285 bool generate_xer
= has_encoding(CT_XER
) && enable_xer();
286 const string
& gennamexerdescriptor
= get_genname_xerdescriptor();
287 if (generate_xer
&& gennamexerdescriptor
== gennameown
)
288 generate_code_xerdescriptor(target
);
289 else target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
290 "// No XER for %s\n", gennamexerdescriptor
.c_str());
292 const string
& gennamejsondescriptor
= get_genname_jsondescriptor();
293 bool generate_json
= has_encoding(CT_JSON
) && enable_json() &&
294 gennamejsondescriptor
== gennameown
;
296 generate_code_jsondescriptor(target
);
299 // the type descriptor must be always exported.
300 // embedded (possibly unnamed) types can be referenced from other modules
301 // using field/array sub-references
302 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
303 "extern const TTCN_Typedescriptor_t %s_descr_;\n", gennameown_str
);
304 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
305 "const TTCN_Typedescriptor_t %s_descr_ = { \"%s\", ", gennameown_str
,
306 get_fullname().c_str());
309 target
->source
.global_vars
=mputprintf
310 (target
->source
.global_vars
,
311 "&%s_ber_, ", gennameberdescriptor
.c_str());
313 target
->source
.global_vars
=mputstr
314 (target
->source
.global_vars
, "NULL, ");
317 target
->source
.global_vars
=mputprintf
318 (target
->source
.global_vars
,
319 "&%s_raw_, ", gennamerawdescriptor
.c_str());
321 target
->source
.global_vars
=mputstr
322 (target
->source
.global_vars
, "NULL, ");
325 target
->source
.global_vars
=mputprintf
326 (target
->source
.global_vars
,
327 "&%s_text_, ", gennametextdescriptor
.c_str());
329 target
->source
.global_vars
=mputstr
330 (target
->source
.global_vars
, "NULL, ");
333 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
334 "&%s_xer_, ", gennamexerdescriptor
.c_str());
336 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
340 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
341 "&%s_json_, ", gennamejsondescriptor
.c_str());
343 switch(get_type_refd_last()->typetype
) {
355 case T_NUMERICSTRING
:
356 case T_PRINTABLESTRING
:
357 case T_TELETEXSTRING
:
358 case T_VIDEOTEXSTRING
:
360 case T_GRAPHICSTRING
:
361 case T_VISIBLESTRING
:
362 case T_GENERALSTRING
:
363 case T_UNIVERSALSTRING
:
370 // use predefined JSON descriptors instead of null pointers for basic types
371 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
372 "&%s_json_, ", gennamejsondescriptor
.c_str());
376 // use a predefined JSON descriptor for enumerated types
377 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
378 "&ENUMERATED_json_, ");
381 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
386 if (T_SEQOF
== get_type_refd_last()->typetype
||
387 T_SETOF
== get_type_refd_last()->typetype
) {
388 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
389 "&%s_descr_, ", get_type_refd_last()->u
.seof
.ofType
->get_genname_typedescriptor(my_scope
).c_str());
392 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
396 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
397 "TTCN_Typedescriptor_t::%s };\n"
401 , get_genname_typedescr_asnbasetype());
403 // the type uses the type descriptor of another type
405 // we need to generate an aliased type descriptor only if the type is
406 // directly accessible by the user
407 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
408 "extern const TTCN_Typedescriptor_t& %s_descr_;\n", gennameown_str
);
409 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
410 "const TTCN_Typedescriptor_t& %s_descr_ = %s_descr_;\n",
411 gennameown_str
, gennametypedescriptor
.c_str());
415 target
->source
.global_vars
= mputprintf( target
->source
.global_vars
,
416 "// %s_descr_ not needed, use %s_descr_\n",
417 gennameown_str
, gennametypedescriptor
.c_str());
418 } // if(needs_alias())
421 } // if (gennameown == gennametypedescriptor)
424 void Type::generate_code_berdescriptor(output_struct
*target
)
426 const char *gennameown_str
= get_genname_own().c_str();
427 char *str
= mprintf("static const ASN_Tag_t %s_tag_[] = { ",
429 Tags
*joinedtags
= build_tags_joined();
430 size_t tagarraysize
= joinedtags
->get_nof_tags();
431 for (size_t i
= 0; i
< tagarraysize
; i
++) {
432 if (i
> 0) str
= mputstr(str
, ", ");
433 Tag
*t_tag
= joinedtags
->get_tag_byIndex(i
);
434 str
= mputprintf(str
, "{ %s, %su }", t_tag
->get_tagclass_str(),
435 Int2string(t_tag
->get_tagvalue()).c_str());
438 str
= mputstr(str
, "};\n");
439 target
->source
.global_vars
= mputstr(target
->source
.global_vars
, str
);
441 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
442 "extern const ASN_BERdescriptor_t %s_ber_;\n", gennameown_str
);
443 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
444 "const ASN_BERdescriptor_t %s_ber_ = { %luu, %s_tag_ };\n",
445 gennameown_str
, (unsigned long)tagarraysize
, gennameown_str
);
448 static const char* whitespace_action
[3] = {"PRESERVE", "REPLACE", "COLLAPSE"};
450 extern void change_name(string
&name
, XerAttributes::NameChange change
);
451 // implemented in Type_chk.cc
453 void Type::generate_code_xerdescriptor(output_struct
* target
)
455 const char *gennameown_str
= get_genname_own().c_str();
456 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
457 "extern const XERdescriptor_t %s_xer_;\n", gennameown_str
);
462 string full_s
= ot
->get_fullname();
463 size_t dot_pos
= full_s
.rfind('.');
464 if (full_s
.size() == dot_pos
) dot_pos
= 0;
465 last_s
= full_s
.substr(dot_pos
+1); // FIXME: may be better to use replace(pos, n, s)
467 if ('&'==last_s
[0] // object class field ?
468 ||'<'==last_s
[0]) { // <oftype> and the like
470 ot
= ot
->get_type_refd();
471 /* Fetch the referenced type and use that. Do not use
472 * get_type_refd_last() here. In case of a record-of user-defined type:
473 * <ttcn>type integer MyInt; type record of MyInt MyRecof;</ttcn>
474 * we want "MyInt" and not "integer" */
477 else { // probably a built-in type, punt with the C++ class name
478 last_s
= ot
->get_genname_value(0);
485 // Name for basic XER which ignores all the EXER fanciness
486 string
bxer_name(last_s
);
489 //fprintf(stderr, "%2d gno='%s'\tfn='%s'\n", typetype, gennameown_str, last_s.c_str());
490 int atrib
=0, any_atr
=0, any_elem
=0, base64
=0, decimal
=0, embed
=0, list
=0,
491 text
=0, untagged
=0, use_nil
=0, use_number
=0, use_order
=0, use_qname
=0,
492 use_type_attr
=0, ws
=0, has_1untag
=0, form_qualified
=0, any_from
=0,
493 any_except
=0, nof_ns_uris
=0, blocked
=0;
494 const char* dfe_str
= 0;
496 char* oftype_descr_name
= 0;
498 change_name(last_s
, xerattrib
->name_
);
500 if (xerattrib
->namespace_
.uri
&& xerattrib
->namespace_
.prefix
) {
501 ns_index
= my_scope
->get_scope_mod()->get_ns_index(
502 xerattrib
->namespace_
.prefix
);
503 // This is known to have succeeded
506 any_atr
= has_aa(xerattrib
);
507 any_elem
= has_ae(xerattrib
);
508 atrib
= xerattrib
->attribute_
;
509 base64
= xerattrib
->base64_
;
510 blocked
= xerattrib
->abstract_
|| xerattrib
->block_
;
511 decimal
= xerattrib
->decimal_
;
512 embed
= xerattrib
->embedValues_
;
513 form_qualified
= (xerattrib
->form_
& XerAttributes::QUALIFIED
)
514 || (xerattrib
->element_
); // a global element is always qualified
515 list
= xerattrib
->list_
;
516 untagged
= xerattrib
->untagged_
;
517 ws
= xerattrib
->whitespace_
;
518 // only set TEXT if it has no TextToBeUsed (plain "text" for a bool)
519 text
= xerattrib
->num_text_
&& xerattrib
->text_
->prefix
== 0;
520 use_nil
= xerattrib
->useNil_
;
521 use_number
= xerattrib
->useNumber_
;
522 use_order
= xerattrib
->useOrder_
;
523 use_qname
= xerattrib
->useQName_
;
524 // In ASN.1, the use of a type identification attribute is optional
525 // (encoder's choice) for USE-UNION. However, TTCN-3 removes this choice:
526 // it is mandatory to use it when possible (valid choice for ASN.1 too).
527 use_type_attr
= xerattrib
->useType_
|| xerattrib
->useUnion_
;
529 if (xerattrib
->defaultValue_
) {
530 Type
*t
= xerattrib
->defaultValue_
->get_my_governor();
531 dfe_str
= xerattrib
->defaultValue_
->get_genname_own().c_str();
533 Code::init_cdef(&cdef
);
534 t
->generate_code_object(&cdef
, xerattrib
->defaultValue_
);
535 cdef
.init
= xerattrib
->defaultValue_
->generate_code_init
536 (cdef
.init
, xerattrib
->defaultValue_
->get_lhs_name().c_str());
537 Code::merge_cdef(target
, &cdef
);
538 Code::free_cdef(&cdef
);
542 // data needed for "anyElement from ..." and "anyElement except ..." encoding instructions
543 any_from
= xerattrib
->anyElement_
.type_
== NamespaceRestriction::FROM
;
544 any_except
= xerattrib
->anyElement_
.type_
== NamespaceRestriction::EXCEPT
;
545 nof_ns_uris
= xerattrib
->anyElement_
.nElements_
;
546 ns_uris
= xerattrib
->anyElement_
.uris_
;
549 // data needed for "anyAttributes from ..." and "anyAttributes except ..." encoding instructions
550 any_from
= xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::FROM
;
551 any_except
= xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::EXCEPT
;
552 nof_ns_uris
= xerattrib
->anyAttributes_
.nElements_
;
553 ns_uris
= xerattrib
->anyAttributes_
.uris_
;
556 else if (ownertype
== OT_COMP_FIELD
557 && parent_type
&& parent_type
->xerattrib
) {
558 //no xerattrib, this must be an element; apply element default
559 form_qualified
= (parent_type
->xerattrib
->form_
560 & XerAttributes::ELEMENT_DEFAULT_QUALIFIED
);
563 Type
*last
= get_type_refd_last();
564 has_1untag
= last
->is_secho() && last
->u
.secho
.has_single_charenc
; // does not come from xerattrib
566 /* If this is a string type whose grandparent is a record
567 * (containing a record-of (this)string) which has EMBED-VALUES,
568 * then reuse this string's any_element field in the XER descriptor
569 * to signal this (ANY-ELEMENT causes the tag to be omitted,
570 * which is what we want in EMBED-VALUES) */
571 if (parent_type
&& parent_type
->parent_type
) switch (last
->typetype
) {
573 case T_USTR
: // the TTCN equivalent of UTF8String
574 if ( T_SEQOF
== parent_type
->typetype
575 && (T_SEQ_T
== parent_type
->parent_type
->typetype
576 ||T_SEQ_A
== parent_type
->parent_type
->typetype
)
577 && parent_type
->parent_type
->xerattrib
) {
578 embed
|= (parent_type
->parent_type
->xerattrib
->embedValues_
);
584 size_t last_len
= 2 + last_s
.size(); // 2 for > \n
585 size_t bxer_len
= 2 + bxer_name
.size(); // 2 for > \n
587 if ((T_SEQOF
== last
->typetype
|| T_SETOF
== last
->typetype
) &&
588 T_ANYTYPE
!= last
->u
.seof
.ofType
->get_type_refd_last()->typetype
) {
589 // anytypes don't have XER descriptors
590 oftype_descr_name
= mprintf("&%s_xer_", last
->u
.seof
.ofType
->get_genname_typedescriptor(my_scope
).c_str());
593 // Generate a separate variable for the namespace URIs, if there are any
594 char* ns_uris_var
= 0;
595 if (ns_uris
&& nof_ns_uris
) {
596 ns_uris_var
= mputprintf(ns_uris_var
, "%s_ns_uris_", gennameown_str
);
597 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
598 "const char* %s[] = {", ns_uris_var
);
599 for (int idx
= 0; idx
< nof_ns_uris
; ++idx
) {
600 // The unqualified namespace is sometimes stored as an empty string and
601 // sometimes as a null pointer -> unify it, always store it as an empty string
602 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
603 "%s\"%s\"", (idx
!= 0) ? ", " : "", ns_uris
[idx
] ? ns_uris
[idx
] : "");
605 target
->source
.global_vars
= mputstrn(target
->source
.global_vars
, "};\n", 3);
608 // Generate the XER descriptor itself
609 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
610 "const XERdescriptor_t %s_xer_ = { {\"%s>\\n\", \"%s>\\n\"},"
611 " {%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, "
612 "&%s, %ld, %u, %s, %s };\n",
614 bxer_name
.c_str(), last_s
.c_str(), // names
615 (unsigned long)bxer_len
, (unsigned long)last_len
, // lengths
616 (any_atr
? "ANY_ATTRIBUTES" : "0"),
617 (any_elem
? " |ANY_ELEMENT" : ""),
618 (atrib
? " |XER_ATTRIBUTE" : ""),
619 (base64
? " |BASE_64" : ""),
620 (blocked
? " |BLOCKED" : ""),
621 (decimal
? " |XER_DECIMAL" : ""),
622 (embed
? " |EMBED_VALUES" : ""),
623 (list
? " |XER_LIST" : ""),
624 (text
? " |XER_TEXT" : ""),
625 (untagged
? " |UNTAGGED" : ""),
626 (use_nil
? " |USE_NIL" : ""),
627 (use_number
? " |USE_NUMBER" : ""),
628 (use_order
? " |USE_ORDER" : ""),
629 (use_qname
? " |USE_QNAME" : ""),
630 (use_type_attr
? " |USE_TYPE_ATTR" : ""),
631 (has_1untag
? " |HAS_1UNTAGGED" : ""),
632 (form_qualified
? "" : " |FORM_UNQUALIFIED"),
633 (any_from
? " |ANY_FROM" : ""),
634 (any_except
? " |ANY_EXCEPT" : ""),
635 (is_optional_field() ? " |XER_OPTIONAL" : ""),
636 whitespace_action
[ws
],
637 (dfe_str
? '&' : ' '), (dfe_str
? dfe_str
: "NULL"),
641 (ns_uris_var
? ns_uris_var
: "NULL"),
642 (oftype_descr_name
? oftype_descr_name
: "NULL")
646 Free(oftype_descr_name
);
649 void Type::generate_code_rawdescriptor(output_struct
*target
)
651 const char *gennameown_str
= get_genname_own().c_str();
652 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
653 "extern const TTCN_RAWdescriptor_t %s_raw_;\n", gennameown_str
);
654 char *str
= mprintf("const TTCN_RAWdescriptor_t %s_raw_ = {",
656 if (rawattrib
->intx
) {
657 str
= mputstr(str
, "RAW_INTX,");
660 str
= mputprintf(str
, "%d,", rawattrib
->fieldlength
);
662 if (rawattrib
->comp
== XDEFCOMPL
) str
= mputstr(str
, "SG_2COMPL,");
663 else if (rawattrib
->comp
== XDEFSIGNBIT
) str
= mputstr(str
, "SG_SG_BIT,");
664 else str
= mputstr(str
, "SG_NO,");
665 if (rawattrib
->byteorder
== XDEFLAST
) str
= mputstr(str
, "ORDER_MSB,");
666 else str
= mputstr(str
, "ORDER_LSB,");
667 if (rawattrib
->align
== XDEFLEFT
) str
= mputstr(str
, "ORDER_MSB,");
668 else str
= mputstr(str
, "ORDER_LSB,");
669 if (rawattrib
->bitorderinfield
== XDEFMSB
)
670 str
= mputstr(str
, "ORDER_MSB,");
671 else str
= mputstr(str
, "ORDER_LSB,");
672 if (rawattrib
->bitorderinoctet
== XDEFMSB
)
673 str
= mputstr(str
, "ORDER_MSB,");
674 else str
= mputstr(str
, "ORDER_LSB,");
675 if (rawattrib
->extension_bit
== XDEFYES
)
676 str
= mputstr(str
, "EXT_BIT_YES,");
677 else if (rawattrib
->extension_bit
== XDEFREVERSE
)
678 str
= mputstr(str
, "EXT_BIT_REVERSE,");
679 else str
= mputstr(str
, "EXT_BIT_NO,");
680 if (rawattrib
->hexorder
== XDEFHIGH
) str
= mputstr(str
, "ORDER_MSB,");
681 else str
= mputstr(str
, "ORDER_LSB,");
682 if (rawattrib
->fieldorder
== XDEFMSB
) str
= mputstr(str
, "ORDER_MSB,");
683 else str
= mputstr(str
, "ORDER_LSB,");
684 if (rawattrib
->topleveleind
) {
685 if (rawattrib
->toplevel
.bitorder
==XDEFLSB
)
686 str
= mputstr(str
, "TOP_BIT_LEFT,");
687 else str
= mputstr(str
, "TOP_BIT_RIGHT,");
688 } else str
= mputstr(str
, "TOP_BIT_INHERITED,");
689 str
= mputprintf(str
, "%d,", rawattrib
->padding
);
690 str
= mputprintf(str
, "%d,", rawattrib
->prepadding
);
691 str
= mputprintf(str
, "%d,", rawattrib
->ptroffset
);
692 str
= mputprintf(str
, "%d,", rawattrib
->unit
);
693 str
= mputprintf(str
, "%d,", rawattrib
->padding_pattern_length
);
694 if (rawattrib
->padding_pattern_length
> 0)
695 str
= mputprintf(str
, "%s,", my_scope
->get_scope_mod_gen()
696 ->add_padding_pattern(string(rawattrib
->padding_pattern
)).c_str());
697 else str
= mputstr(str
, "NULL,");
698 str
= mputprintf(str
, "%d};\n", rawattrib
->length_restrition
);
699 target
->source
.global_vars
= mputstr(target
->source
.global_vars
, str
);
703 void Type::generate_code_textdescriptor(output_struct
*target
)
705 const char *gennameown_str
= get_genname_own().c_str();
706 char *union_member_name
=NULL
;
707 Common::Module
*mymod
=my_scope
->get_scope_mod();
708 Type
*t
= get_type_refd_last();
709 switch (t
->typetype
) {
711 if (textattrib
->true_params
|| textattrib
->false_params
) {
712 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
713 "static const TTCN_TEXTdescriptor_bool %s_bool_ = {", gennameown_str
);
714 if (textattrib
->true_params
&&
715 textattrib
->true_params
->encode_token
) {
716 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
717 "&%s,", mymod
->add_charstring_literal(
718 string(textattrib
->true_params
->encode_token
)).c_str());
720 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
723 if (textattrib
->true_params
&&
724 textattrib
->true_params
->decode_token
) {
725 char *pstr
= make_posix_str_code(
726 textattrib
->true_params
->decode_token
,
727 textattrib
->true_params
->case_sensitive
);
728 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
729 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
731 } else if (textattrib
->true_params
&&
732 !textattrib
->true_params
->case_sensitive
) {
733 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
734 "&%s,", mymod
->add_matching_literal(
735 string("N^(true).*$")).c_str());
737 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
740 if (textattrib
->false_params
&&
741 textattrib
->false_params
->encode_token
) {
742 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
743 "&%s,",mymod
->add_charstring_literal(
744 string(textattrib
->false_params
->encode_token
)).c_str());
746 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
749 if (textattrib
->false_params
&&
750 textattrib
->false_params
->decode_token
) {
751 char *pstr
= make_posix_str_code(
752 textattrib
->false_params
->decode_token
,
753 textattrib
->false_params
->case_sensitive
);
754 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
755 "&%s};\n", mymod
->add_matching_literal(string(pstr
)).c_str());
757 } else if (textattrib
->false_params
&&
758 !textattrib
->false_params
->case_sensitive
) {
759 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
760 "&%s};\n", mymod
->add_matching_literal(
761 string("N^(false).*$")).c_str());
763 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
766 union_member_name
= mprintf("(TTCN_TEXTdescriptor_param_values*)"
767 "&%s_bool_", gennameown_str
);
771 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
772 "static const TTCN_TEXTdescriptor_enum %s_enum_[] = { ",
774 for (size_t i
= 0; i
< t
->u
.enums
.eis
->get_nof_eis(); i
++) {
775 if (i
> 0) target
->source
.global_vars
=
776 mputstr(target
->source
.global_vars
, ", ");
777 target
->source
.global_vars
=
778 mputstr(target
->source
.global_vars
, "{ ");
779 if (textattrib
->field_params
&& textattrib
->field_params
[i
] &&
780 textattrib
->field_params
[i
]->value
.encode_token
) {
781 // the encode token is present
782 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
783 "&%s, ", mymod
->add_charstring_literal(
784 string(textattrib
->field_params
[i
]->value
.encode_token
)).c_str());
786 // the encode token is not present: generate a NULL pointer and the
787 // RTE will substitute the enumerated value
788 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
791 // a pattern must be always present for decoding
792 const char *decode_token
;
794 if (textattrib
->field_params
&& textattrib
->field_params
[i
]) {
795 if (textattrib
->field_params
[i
]->value
.decode_token
) {
796 // the decode token is present
797 decode_token
= textattrib
->field_params
[i
]->value
.decode_token
;
799 // there is an attribute for the enumerated value,
800 // but the decode token is omitted
801 // use the value as decode token
802 decode_token
= t
->u
.enums
.eis
->get_ei_byIndex(i
)->get_name()
803 .get_dispname().c_str();
805 // take the case sensitivity from the attribute
806 case_sensitive
= textattrib
->field_params
[i
]->value
.case_sensitive
;
808 // there is no attribute for the enumerated value
809 // use the value as decode token
810 decode_token
= t
->u
.enums
.eis
->get_ei_byIndex(i
)->get_name()
811 .get_dispname().c_str();
812 // it is always case sensitive
813 case_sensitive
= true;
815 char *pstr
= make_posix_str_code(decode_token
, case_sensitive
);
816 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
817 " &%s }", mymod
->add_matching_literal(string(pstr
)).c_str());
820 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
822 union_member_name
= mprintf(
823 "(TTCN_TEXTdescriptor_param_values*)%s_enum_", gennameown_str
);
827 if(textattrib
->coding_params
.leading_zero
||
828 textattrib
->coding_params
.min_length
!=-1 ||
829 textattrib
->coding_params
.max_length
!=-1 ||
830 textattrib
->coding_params
.convert
!=0 ||
831 textattrib
->coding_params
.just
!=1 ||
832 textattrib
->decoding_params
.leading_zero
||
833 textattrib
->decoding_params
.min_length
!=-1 ||
834 textattrib
->decoding_params
.max_length
!=-1 ||
835 textattrib
->decoding_params
.convert
!=0 ||
836 textattrib
->decoding_params
.just
!=1 ){
837 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
838 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
840 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
841 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
842 ,textattrib
->coding_params
.leading_zero
?"true":"false"
843 ,textattrib
->coding_params
.repeatable
?"true":"false"
844 ,textattrib
->coding_params
.min_length
845 ,textattrib
->coding_params
.max_length
846 ,textattrib
->coding_params
.convert
847 ,textattrib
->coding_params
.just
848 ,textattrib
->decoding_params
.leading_zero
?"true":"false"
849 ,textattrib
->decoding_params
.repeatable
?"true":"false"
850 ,textattrib
->decoding_params
.min_length
851 ,textattrib
->decoding_params
.max_length
852 ,textattrib
->decoding_params
.convert
853 ,textattrib
->decoding_params
.just
);
855 union_member_name
=mprintf("&%s_par_", gennameown_str
);
860 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
861 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
863 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
864 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
865 ,textattrib
->coding_params
.leading_zero
?"true":"false"
866 ,textattrib
->coding_params
.repeatable
?"true":"false"
867 ,textattrib
->coding_params
.min_length
868 ,textattrib
->coding_params
.max_length
869 ,textattrib
->coding_params
.convert
870 ,textattrib
->coding_params
.just
871 ,textattrib
->decoding_params
.leading_zero
?"true":"false"
872 ,textattrib
->decoding_params
.repeatable
?"true":"false"
873 ,textattrib
->decoding_params
.min_length
874 ,textattrib
->decoding_params
.max_length
875 ,textattrib
->decoding_params
.convert
876 ,textattrib
->decoding_params
.just
);
878 union_member_name
=mprintf("&%s_par_", gennameown_str
);
884 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
885 "extern const TTCN_TEXTdescriptor_t %s_text_;\n", gennameown_str
);
886 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
887 "const TTCN_TEXTdescriptor_t %s_text_ = {", gennameown_str
);
889 if (textattrib
->begin_val
&& textattrib
->begin_val
->encode_token
) {
890 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
891 "&%s,", mymod
->add_charstring_literal(
892 string(textattrib
->begin_val
->encode_token
)).c_str());
894 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
897 if(textattrib
->begin_val
&& textattrib
->begin_val
->decode_token
){
898 char *pstr
= make_posix_str_code(
899 textattrib
->begin_val
->decode_token
,
900 textattrib
->begin_val
->case_sensitive
);
901 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
902 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
905 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
908 if (textattrib
->end_val
&& textattrib
->end_val
->encode_token
) {
909 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
910 "&%s,",mymod
->add_charstring_literal(
911 string(textattrib
->end_val
->encode_token
)).c_str());
913 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
916 if (textattrib
->end_val
&& textattrib
->end_val
->decode_token
) {
917 char *pstr
= make_posix_str_code(
918 textattrib
->end_val
->decode_token
,
919 textattrib
->end_val
->case_sensitive
);
920 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
921 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
924 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
928 if (textattrib
->separator_val
&&
929 textattrib
->separator_val
->encode_token
) {
930 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
931 "&%s,", mymod
->add_charstring_literal(
932 string(textattrib
->separator_val
->encode_token
)).c_str());
934 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
937 if(textattrib
->separator_val
&&
938 textattrib
->separator_val
->decode_token
) {
939 char *pstr
= make_posix_str_code(
940 textattrib
->separator_val
->decode_token
,
941 textattrib
->separator_val
->case_sensitive
);
942 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
943 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
946 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
950 if (textattrib
->decode_token
) {
951 char *pstr
= make_posix_str_code(textattrib
->decode_token
,
952 textattrib
->case_sensitive
);
953 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
954 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
957 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
961 if (union_member_name
) {
962 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
963 "{%s}};\n", union_member_name
);
964 Free(union_member_name
);
966 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
971 void Type::generate_code_jsondescriptor(output_struct
*target
)
973 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
974 "extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str());
976 if (NULL
== jsonattrib
) {
977 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
978 "const TTCN_JSONdescriptor_t %s_json_ = { false, NULL, false, NULL, false };\n"
979 , get_genname_own().c_str());
981 char* alias
= jsonattrib
->alias
? mputprintf(NULL
, "\"%s\"", jsonattrib
->alias
) : NULL
;
982 char* def_val
= jsonattrib
->default_value
?
983 mputprintf(NULL
, "\"%s\"", jsonattrib
->default_value
) : NULL
;
984 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
985 "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s };\n"
986 , get_genname_own().c_str()
987 , jsonattrib
->omit_as_null
? "true" : "false"
988 , alias
? alias
: "NULL"
989 , jsonattrib
->as_value
? "true" : "false"
990 , def_val
? def_val
: "NULL"
991 , jsonattrib
->metainfo_unbound
? "true" : "false");
998 void Type::generate_code_alias(output_struct
*target
)
1000 if (!needs_alias()) return;
1002 const string
& t_genname
= get_genname_value(my_scope
);
1003 const char *refd_name
= t_genname
.c_str();
1004 const char *own_name
= get_genname_own().c_str();
1006 Type
*t_last
= get_type_refd_last();
1007 switch (t_last
->typetype
) {
1008 case T_PORT
: // only value class exists
1009 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1010 "typedef %s %s;\n", refd_name
, own_name
);
1012 case T_SIGNATURE
: // special classes (7 pcs.) exist
1013 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1014 "typedef %s_call %s_call;\n"
1015 "typedef %s_call_redirect %s_call_redirect;\n",
1016 refd_name
, own_name
, refd_name
, own_name
);
1017 if (!t_last
->is_nonblocking_signature()) {
1018 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1019 "typedef %s_reply %s_reply;\n"
1020 "typedef %s_reply_redirect %s_reply_redirect;\n",
1021 refd_name
, own_name
, refd_name
, own_name
);
1023 if (t_last
->get_signature_exceptions()) {
1024 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1025 "typedef %s_exception %s_exception;\n"
1026 "typedef %s_exception_template %s_exception_template;\n",
1027 refd_name
, own_name
, refd_name
, own_name
);
1029 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1030 "typedef %s_template %s_template;\n",
1031 refd_name
, own_name
);
1033 default: // value and template classes exist
1034 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1036 "// written by %s in " __FILE__
" at %d\n"
1039 "typedef %s_template %s_template;\n",
1041 __FUNCTION__
, __LINE__
,
1043 refd_name
, own_name
, refd_name
, own_name
);
1048 void Type::generate_code_Enum(output_struct
*target
)
1052 memset(&e_def
, 0, sizeof(e_def
));
1053 e_def
.name
= get_genname_own().c_str();
1054 e_def
.dispname
= get_fullname().c_str();
1055 e_def
.isASN1
= is_asn1();
1056 e_def
.nElements
= u
.enums
.eis
->get_nof_eis();
1057 e_def
.elements
= (enum_field
*)
1058 Malloc(e_def
.nElements
*sizeof(*e_def
.elements
));
1059 e_def
.firstUnused
= u
.enums
.first_unused
;
1060 e_def
.secondUnused
= u
.enums
.second_unused
;
1061 e_def
.hasText
= textattrib
!=NULL
;
1062 e_def
.hasRaw
= rawattrib
!=NULL
;
1063 e_def
.hasXer
= has_encoding(CT_XER
);
1064 e_def
.hasJson
= has_encoding(CT_JSON
);
1066 e_def
.xerUseNumber
= xerattrib
->useNumber_
;
1068 for (size_t i
= 0; i
< e_def
.nElements
; i
++) {
1069 EnumItem
*ei
= u
.enums
.eis
->get_ei_byIndex(i
);
1070 e_def
.elements
[i
].name
= ei
->get_name().get_name().c_str();
1071 e_def
.elements
[i
].dispname
= ei
->get_name().get_ttcnname().c_str();
1072 if (ei
->get_text().empty()) e_def
.elements
[i
].text
= 0;
1074 e_def
.xerText
= TRUE
;
1075 e_def
.elements
[i
].text
= ei
->get_text().c_str();
1077 e_def
.elements
[i
].value
= ei
->get_value()->get_val_Int()->get_val();
1080 defEnumClass(&e_def
, target
);
1081 defEnumTemplate(&e_def
, target
);
1083 Free(e_def
.elements
);
1086 void Type::generate_code_Choice(output_struct
*target
)
1090 memset(&sdef
, 0, sizeof(sdef
));
1091 sdef
.name
= get_genname_own().c_str();
1092 sdef
.dispname
=get_fullname().c_str();
1093 if (T_ANYTYPE
==typetype
) {
1094 if (0 == get_nof_comps()) {
1095 //return; // don't generate code for empty anytype
1096 // XXX what to do with empty anytype ?
1097 // Easy: make sure it doesn't happen by filling it from the AST!
1099 sdef
.kind
= ANYTYPE
;
1101 else sdef
.kind
= UNION
;
1102 sdef
.isASN1
= is_asn1();
1103 sdef
.hasText
= textattrib
!=NULL
;
1104 sdef
.hasXer
= has_encoding(CT_XER
);
1105 sdef
.hasJson
= has_encoding(CT_JSON
);
1106 sdef
.has_opentypes
= get_has_opentypes();
1107 sdef
.opentype_outermost
= get_is_opentype_outermost();
1108 sdef
.ot
= generate_code_ot(pool
);
1109 sdef
.nElements
= get_nof_comps();
1110 sdef
.isOptional
= false;
1111 if (parent_type
!= NULL
) {
1112 switch (parent_type
->typetype
) {
1117 for (size_t x
= 0; x
< parent_type
->get_nof_comps(); ++x
) {
1118 CompField
* cf
= parent_type
->get_comp_byIndex(x
);
1119 if (cf
->get_type() == this && cf
->get_is_optional()) {
1120 sdef
.isOptional
= true;
1121 break; // from the for loop
1129 sdef
.elements
= (struct_field
*)
1130 Malloc(sdef
.nElements
*sizeof(*sdef
.elements
));
1131 memset(sdef
.elements
, 0, sdef
.nElements
*sizeof(*sdef
.elements
));
1132 sdef
.exerMaybeEmptyIndex
= -1;
1134 sdef
.jsonAsValue
= jsonattrib
->as_value
;
1136 for(size_t i
= 0; i
< sdef
.nElements
; i
++) {
1137 CompField
*cf
= get_comp_byIndex(i
);
1138 const Identifier
& id
= cf
->get_name();
1139 Type
*cftype
= cf
->get_type();
1140 sdef
.elements
[i
].type
= pool
.add(cftype
->get_genname_value(my_scope
));
1141 sdef
.elements
[i
].typedescrname
=
1142 pool
.add(cftype
->get_genname_typedescriptor(my_scope
));
1143 sdef
.elements
[i
].typegen
= pool
.add(cftype
->get_genname_xerdescriptor());
1144 sdef
.elements
[i
].name
= id
.get_name().c_str();
1145 sdef
.elements
[i
].dispname
= id
.get_ttcnname().c_str();
1147 if (cftype
->has_empty_xml()) sdef
.exerMaybeEmptyIndex
= i
;
1148 // This will overwrite lower values, which is what we want.
1150 if (sdef
.jsonAsValue
) {
1151 // Determine the JSON value type of each field to make decoding faster
1152 typetype_t tt
= cftype
->get_type_refd_last()->typetype
;
1156 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
;
1159 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
| JSON_STRING
;
1162 sdef
.elements
[i
].jsonValueType
= JSON_BOOLEAN
;
1165 sdef
.elements
[i
].jsonValueType
= JSON_NULL
;
1174 case T_NUMERICSTRING
:
1175 case T_PRINTABLESTRING
:
1176 case T_TELETEXSTRING
:
1177 case T_VIDEOTEXSTRING
:
1179 case T_GRAPHICSTRING
:
1180 case T_VISIBLESTRING
:
1181 case T_GENERALSTRING
:
1182 case T_UNIVERSALSTRING
:
1190 sdef
.elements
[i
].jsonValueType
= JSON_STRING
;
1200 sdef
.elements
[i
].jsonValueType
= JSON_OBJECT
;
1205 sdef
.elements
[i
].jsonValueType
= JSON_ARRAY
;
1208 FATAL_ERROR("Type::generate_code_Choice - invalid field type %d", tt
);
1211 if (cftype
->jsonattrib
) {
1212 sdef
.elements
[i
].jsonAlias
= cftype
->jsonattrib
->alias
;
1213 if (sdef
.jsonAsValue
&& cftype
->jsonattrib
->as_value
) {
1214 // Override the JSON_OBJECT value given in the switch
1215 sdef
.elements
[i
].jsonValueType
= JSON_ANY_VALUE
;
1220 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
1223 for(int c
=0;c
<rawattrib
->taglist
.nElements
;c
++){
1224 if(rawattrib
->taglist
.tag
[c
].nElements
)
1225 sdef
.raw
.taglist
.list
[c
].fields
=
1226 (rawAST_coding_field_list
*)
1227 Malloc(rawattrib
->taglist
.tag
[c
].nElements
1228 *sizeof(rawAST_coding_field_list
));
1229 else sdef
.raw
.taglist
.list
[c
].fields
=NULL
;
1230 sdef
.raw
.taglist
.list
[c
].nElements
=
1231 rawattrib
->taglist
.tag
[c
].nElements
;
1232 sdef
.raw
.taglist
.list
[c
].fieldName
=
1233 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1234 Identifier
*idf
=rawattrib
->taglist
.tag
[c
].fieldName
;
1235 sdef
.raw
.taglist
.list
[c
].fieldnum
=get_comp_index_byName(*idf
);
1236 for(int a
=0;a
<rawattrib
->taglist
.tag
[c
].nElements
;a
++){
1237 rawAST_coding_field_list
* key
=
1238 sdef
.raw
.taglist
.list
[c
].fields
+a
;
1240 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1241 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
1243 key
->fields
=(rawAST_coding_fields
*)
1244 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1245 CompField
*cf
=get_comp_byIndex(sdef
.raw
.taglist
.list
[c
].fieldnum
);
1246 Type
*t
=cf
->get_type()->get_type_refd_last();
1248 key
->fields
[0].nthfield
= sdef
.raw
.taglist
.list
[c
].fieldnum
;
1249 key
->fields
[0].nthfieldname
=
1250 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1251 key
->fields
[0].fieldtype
= UNION_FIELD
;
1252 key
->fields
[0].type
= pool
.add(t
->get_genname_value(my_scope
));
1253 key
->fields
[0].typedescr
=
1254 pool
.add(t
->get_genname_typedescriptor(my_scope
));
1256 for (int b
= 1; b
< key
->nElements
; b
++) {
1258 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->names
[b
-1];
1259 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1260 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1261 key
->fields
[b
].nthfield
= comp_index
;
1262 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1263 if (t
->typetype
== T_CHOICE_T
)
1264 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1265 else if (cf2
->get_is_optional()){
1266 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1267 }else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1268 Type
*field_type
= cf2
->get_type();
1269 key
->fields
[b
].type
=
1270 pool
.add(field_type
->get_genname_value(my_scope
));
1271 key
->fields
[b
].typedescr
=
1272 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1273 if (field_type
->typetype
== T_SEQ_T
&& field_type
->rawattrib
1274 && (field_type
->rawattrib
->pointerto
1275 || field_type
->rawattrib
->lengthto_num
))
1276 key
->start_pos
= -1;
1278 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1280 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1282 t2
= t
->get_comp_byIndex(i
)->get_type();
1283 if(t2
->get_raw_length() >= 0){
1285 key
->start_pos
+= t2
->rawattrib
->padding
;
1286 key
->start_pos
+= t2
->get_raw_length();
1287 }else key
->start_pos
= -1;
1290 t
= field_type
->get_type_refd_last();
1294 } else sdef
.hasRaw
=false;
1296 Module
*my_module
= get_my_scope()->get_scope_mod();
1297 sdef
.xerHasNamespaces
= my_module
->get_nof_ns() != 0;
1298 const char *ns
, *prefix
;
1299 my_module
->get_controlns(ns
, prefix
);
1300 sdef
.control_ns_prefix
= prefix
;
1301 sdef
.xerUseUnion
= xerattrib
->useUnion_
;
1302 sdef
.xerUseTypeAttr
= xerattrib
->useType_
|| xerattrib
->useUnion_
;
1304 defUnionClass(&sdef
, target
);
1305 defUnionTemplate(&sdef
, target
);
1307 free_code_ot(sdef
.ot
);
1310 free_raw_attrib_struct(&sdef
.raw
);
1312 Free(sdef
.elements
);
1315 Opentype_t
*Type::generate_code_ot(stringpool
& pool
)
1317 using namespace Asn
;
1318 if(typetype
!=T_OPENTYPE
)
1320 if(!u
.secho
.my_tableconstraint
1321 || !u
.secho
.my_tableconstraint
->get_ans()) {
1322 DEBUG(1, "Opentype ObjectClassFieldType without"
1323 " ComponentRelationConstraint: `%s'",
1324 get_fullname().c_str());
1327 const AtNotations
*ans
=u
.secho
.my_tableconstraint
->get_ans();
1328 Opentype_t
*ot
=(Opentype_t
*)Malloc(sizeof(*ot
));
1329 ot
->anl
.nElements
= ans
->get_nof_ans();
1330 ot
->anl
.elements
= (AtNotation_t
*)
1331 Malloc(ot
->anl
.nElements
* sizeof(*ot
->anl
.elements
));
1332 for(size_t i
=0; i
<ans
->get_nof_ans(); i
++) {
1333 AtNotation
*an
=ans
->get_an_byIndex(i
);
1334 AtNotation_t
*an_t
= ot
->anl
.elements
+ i
;
1335 an_t
->dispname
= pool
.add(an
->get_dispname());
1336 an_t
->parent_level
=an
->get_levels();
1337 an_t
->parent_typename
=
1338 pool
.add(an
->get_firstcomp()->get_genname_value(my_scope
));
1340 pool
.add(an
->get_lastcomp()->get_genname_value(my_scope
));
1341 an_t
->sourcecode
=memptystr();
1342 FieldName
* cids
=an
->get_cids();
1343 Type
*t_type
=an
->get_firstcomp();
1344 for(size_t j
=0; j
<cids
->get_nof_fields(); j
++) {
1346 t_type
->get_comp_byName(*cids
->get_field_byIndex(j
));
1347 if(j
) an_t
->sourcecode
=mputstr(an_t
->sourcecode
, ".");
1348 an_t
->sourcecode
=mputprintf
1349 (an_t
->sourcecode
, "%s()",
1350 cf
->get_name().get_name().c_str());
1351 if(cf
->get_is_optional())
1352 an_t
->sourcecode
=mputstr(an_t
->sourcecode
, "()");
1353 t_type
=cf
->get_type();
1356 const Identifier
*oc_fieldname_t
1357 =u
.secho
.my_tableconstraint
->get_oc_fieldname();
1359 =u
.secho
.my_tableconstraint
->get_os()->get_refd_last()->get_objs();
1360 ot
->oal
.nElements
= objs
->get_nof_objs();
1361 ot
->oal
.elements
= (OpentypeAlternative_t
*)
1362 Malloc(ot
->oal
.nElements
* sizeof(*ot
->oal
.elements
));
1363 size_t nElements_missing
=0;
1364 Value
**val_prev
=(Value
**)
1365 Malloc(ans
->get_nof_ans()*sizeof(*val_prev
));
1366 boolean differs_from_prev
=true;
1367 for(size_t i
=0; i
<objs
->get_nof_objs(); i
++) {
1368 Obj_defn
*obj
=objs
->get_obj_byIndex(i
);
1369 if(!obj
->has_fs_withName_dflt(*oc_fieldname_t
)) {
1370 nElements_missing
++;
1373 OpentypeAlternative_t
*oa_t
= ot
->oal
.elements
+ i
- nElements_missing
;
1374 Type
*t_type
=dynamic_cast<Type
*>
1375 (obj
->get_setting_byName_dflt(*oc_fieldname_t
));
1377 const Identifier
& altname
= t_type
->get_otaltname(is_strange
);
1378 oa_t
->alt
= pool
.add(altname
.get_name());
1379 oa_t
->alt_dispname
= pool
.add(altname
.get_asnname());
1380 oa_t
->alt_typename
= pool
.add(t_type
->get_genname_value(my_scope
));
1381 oa_t
->alt_typedescrname
=
1382 pool
.add(t_type
->get_genname_typedescriptor(my_scope
));
1383 oa_t
->valuenames
=(const char**)Malloc
1384 (ans
->get_nof_ans()*sizeof(*oa_t
->valuenames
));
1385 oa_t
->const_valuenames
=(const char**)Malloc
1386 (ans
->get_nof_ans()*sizeof(*oa_t
->const_valuenames
));
1387 for(size_t j
=0; j
<ans
->get_nof_ans(); j
++) {
1388 AtNotation
*an
=ans
->get_an_byIndex(j
);
1389 const Identifier
*oc_fieldname_v
=an
->get_oc_fieldname();
1390 Value
*t_value
=dynamic_cast<Value
*>
1391 (obj
->get_setting_byName_dflt(*oc_fieldname_v
));
1392 oa_t
->valuenames
[j
] = pool
.add(t_value
->get_genname_own(my_scope
));
1393 if(!differs_from_prev
&& *val_prev
[j
]==*t_value
)
1394 oa_t
->const_valuenames
[j
]=0;
1396 oa_t
->const_valuenames
[j
] =
1397 pool
.add(t_value
->get_genname_own(my_scope
));
1398 differs_from_prev
=true;
1400 val_prev
[j
]=t_value
;
1402 differs_from_prev
=false;
1405 ot
->oal
.nElements
-= nElements_missing
;
1406 ot
->oal
.elements
= (OpentypeAlternative_t
*)
1407 Realloc(ot
->oal
.elements
,
1408 ot
->oal
.nElements
* sizeof(*ot
->oal
.elements
));
1412 void Type::free_code_ot(Opentype_t
* p_ot
)
1415 for (size_t i
= 0; i
< p_ot
->oal
.nElements
; i
++) {
1416 Free(p_ot
->oal
.elements
[i
].valuenames
);
1417 Free(p_ot
->oal
.elements
[i
].const_valuenames
);
1419 Free(p_ot
->oal
.elements
);
1420 for (size_t i
= 0; i
< p_ot
->anl
.nElements
; i
++)
1421 Free(p_ot
->anl
.elements
[i
].sourcecode
);
1422 Free(p_ot
->anl
.elements
);
1426 size_t Type::get_codegen_index(size_t index
)
1428 // This sorting is because of CER coding of SET types, see X.690 9.3.
1429 // see: Type::generate_code_Se()
1430 // TODO: maybe result should be cached into this type
1431 // ( inside u.secho as dynamic_array<size_t>* codegen_indexes ? )
1432 if (typetype
==T_SET_A
) {
1433 size_t nof_comps
= get_nof_comps();
1434 map
<Tag
, void> se_index_map
;
1435 for (size_t i
=0; i
<nof_comps
; i
++) {
1436 Tag
*tag
= get_comp_byIndex(i
)->get_type()->get_smallest_tag();
1437 se_index_map
.add(*tag
, (void*)i
); // hack: store size_t in void* to avoid Malloc()
1440 for(size_t i
=0; i
<nof_comps
; i
++) {
1441 if (se_index_map
.get_nth_elem(i
)==(void*)index
) {
1442 se_index_map
.clear();
1446 FATAL_ERROR("Type::get_codegen_index()");
1451 void Type::generate_code_Se(output_struct
*target
)
1455 Type
* last_field_type
= 0;
1456 memset(&sdef
, 0, sizeof(sdef
));
1457 sdef
.name
= get_genname_own().c_str();
1458 sdef
.dispname
= get_fullname().c_str();
1459 //printf("generate_code_Se(%s)\n", sdef.dispname);
1478 FATAL_ERROR("Type::generate_code_Se()");
1480 sdef
.hasText
= textattrib
!=NULL
;
1481 sdef
.nElements
= sdef
.totalElements
= get_nof_comps();
1482 sdef
.has_opentypes
= get_has_opentypes();
1483 sdef
.opentype_outermost
= get_is_opentype_outermost();
1485 sdef
.hasXer
= has_encoding(CT_XER
);
1486 sdef
.hasJson
= has_encoding(CT_JSON
);
1488 Module
*my_module
= get_my_scope()->get_scope_mod();
1489 sdef
.xerHasNamespaces
= my_module
->get_nof_ns() != 0;
1490 const char *ns
, *prefix
;
1491 my_module
->get_controlns(ns
, prefix
);
1492 sdef
.control_ns_prefix
= prefix
;
1493 sdef
.xerUntagged
= xerattrib
->untagged_
;
1494 sdef
.xerUntaggedOne
= u
.secho
.has_single_charenc
;
1495 sdef
.xerUseNilPossible
= use_nil_possible
;
1496 sdef
.xerEmbedValuesPossible
= embed_values_possible
;
1497 sdef
.xerUseOrderPossible
= use_order_possible
;
1498 if (xerattrib
->useOrder_
&& xerattrib
->useNil_
) {
1499 // We need information about the fields of the USE-NIL component
1500 const CompField
*cf
= get_comp_byIndex(sdef
.totalElements
-1);
1501 last_field_type
= cf
->get_type()->get_type_refd_last();
1502 sdef
.totalElements
+= last_field_type
->get_nof_comps();
1504 sdef
.xerUseQName
= xerattrib
->useQName_
;
1505 if (xerattrib
->useType_
|| xerattrib
->useUnion_
) {
1506 FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record
1509 sdef
.elements
= (struct_field
*)
1510 Malloc(sdef
.totalElements
*sizeof(*sdef
.elements
));
1511 memset(sdef
.elements
, 0, sdef
.totalElements
* sizeof(*sdef
.elements
));
1513 /* This sorting is because of CER coding of SET types, see X.690
1515 vector
<CompField
> se_comps
;
1516 if(typetype
==T_SET_A
) {
1517 map
<Tag
, CompField
> se_comps_map
;
1518 for(size_t i
=0; i
<sdef
.nElements
; i
++) {
1519 CompField
* cf
=get_comp_byIndex(i
);
1520 Tag
*tag
= cf
->get_type()->get_smallest_tag();
1521 se_comps_map
.add(*tag
, cf
);
1524 for(size_t i
=0; i
<sdef
.nElements
; i
++)
1525 se_comps
.add(se_comps_map
.get_nth_elem(i
));
1526 se_comps_map
.clear();
1529 for(size_t i
=0; i
<sdef
.nElements
; i
++)
1530 se_comps
.add(get_comp_byIndex(i
));
1533 for(size_t i
= 0; i
< sdef
.nElements
; i
++) {
1534 struct_field
&cur
= sdef
.elements
[i
];
1535 CompField
*cf
= se_comps
[i
];
1536 const Identifier
& id
= cf
->get_name();
1537 Type
*type
= cf
->get_type();
1538 cur
.type
= pool
.add(type
->get_genname_value(my_scope
));
1539 cur
.typegen
= pool
.add(type
->get_genname_own());
1540 cur
.of_type
= type
->get_type_refd_last()->is_seof();
1542 pool
.add(type
->get_genname_typedescriptor(my_scope
));
1543 cur
.name
= id
.get_name().c_str();
1544 cur
.dispname
= id
.get_ttcnname().c_str();
1545 cur
.isOptional
= cf
->get_is_optional();
1546 cur
.isDefault
= cf
->has_default();
1547 cur
.optimizedMemAlloc
= cur
.of_type
&& (type
->get_optimize_attribute() == "memalloc");
1548 if (cur
.isDefault
) {
1549 Value
*defval
= cf
->get_defval();
1551 Code::init_cdef(&cdef
);
1552 type
->generate_code_object(&cdef
, defval
);
1553 cdef
.init
= defval
->generate_code_init
1554 (cdef
.init
, defval
->get_lhs_name().c_str());
1555 Code::merge_cdef(target
, &cdef
);
1556 Code::free_cdef(&cdef
);
1557 cur
.defvalname
= defval
->get_genname_own().c_str();
1560 if (type
->xerattrib
) {
1561 cur
.xerAttribute
= type
->xerattrib
->attribute_
;
1563 if (has_aa(type
->xerattrib
)) {
1564 cur
.xerAnyNum
= type
->xerattrib
->anyAttributes_
.nElements_
;
1565 cur
.xerAnyKind
= ANY_ATTRIB_BIT
|
1566 (type
->xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::FROM
?
1567 ANY_FROM_BIT
: ANY_EXCEPT_BIT
);
1568 if (cur
.xerAnyNum
> 0)
1569 cur
.xerAnyUris
= (char**)Malloc(cur
.xerAnyNum
* sizeof(char*));
1570 for (size_t uu
=0; uu
<cur
.xerAnyNum
; ++uu
)
1571 cur
.xerAnyUris
[uu
] = type
->xerattrib
->anyAttributes_
.uris_
[uu
];
1573 else if(has_ae(type
->xerattrib
)) {
1574 cur
.xerAnyNum
= type
->xerattrib
->anyElement_
.nElements_
;
1575 cur
.xerAnyKind
= ANY_ELEM_BIT
|
1576 (type
->xerattrib
->anyElement_
.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
->anyElement_
.uris_
[uu
];
1584 if (type
->jsonattrib
) {
1585 cur
.jsonOmitAsNull
= type
->jsonattrib
->omit_as_null
;
1586 cur
.jsonAlias
= type
->jsonattrib
->alias
;
1587 cur
.jsonDefaultValue
= type
->jsonattrib
->default_value
;
1588 cur
.jsonMetainfoUnbound
= type
->jsonattrib
->metainfo_unbound
;
1592 if (last_field_type
)
1593 for (size_t i
= sdef
.nElements
; i
< sdef
.totalElements
; i
++) {
1594 struct_field
&cur
= sdef
.elements
[i
];
1595 CompField
*cf
= last_field_type
->get_comp_byIndex(i
- sdef
.nElements
);
1596 const Identifier
& id
= cf
->get_name();
1597 Type
*type
= cf
->get_type();
1598 cur
.type
= pool
.add(type
->get_genname_value(my_scope
));
1599 cur
.typegen
= pool
.add(type
->get_genname_own());
1600 cur
.of_type
= type
->get_type_refd_last()->is_seof();
1602 pool
.add(type
->get_genname_typedescriptor(my_scope
));
1603 cur
.name
= id
.get_name().c_str();
1604 cur
.dispname
= id
.get_ttcnname().c_str();
1605 cur
.isOptional
= cf
->get_is_optional();
1610 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
1613 for(int c
=0;c
<rawattrib
->taglist
.nElements
;c
++) {
1614 if(rawattrib
->taglist
.tag
[c
].nElements
)
1615 sdef
.raw
.taglist
.list
[c
].fields
=
1616 (rawAST_coding_field_list
*)
1617 Malloc(rawattrib
->taglist
.tag
[c
].nElements
1618 *sizeof(rawAST_coding_field_list
));
1619 else sdef
.raw
.taglist
.list
[c
].fields
=NULL
;
1620 sdef
.raw
.taglist
.list
[c
].nElements
=
1621 rawattrib
->taglist
.tag
[c
].nElements
;
1622 sdef
.raw
.taglist
.list
[c
].fieldName
=
1623 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1624 Identifier
*idf
=rawattrib
->taglist
.tag
[c
].fieldName
;
1625 sdef
.raw
.taglist
.list
[c
].fieldnum
=get_comp_index_byName(*idf
);
1626 for(int a
=0;a
<rawattrib
->taglist
.tag
[c
].nElements
;a
++){
1627 rawAST_coding_field_list
* key
=
1628 sdef
.raw
.taglist
.list
[c
].fields
+a
;
1630 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1631 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
1633 key
->fields
=(rawAST_coding_fields
*)
1634 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1636 CompField
*cf
=get_comp_byIndex(sdef
.raw
.taglist
.list
[c
].fieldnum
);
1637 Type
*t
=cf
->get_type()->get_type_refd_last();
1639 key
->fields
[0].nthfield
= sdef
.raw
.taglist
.list
[c
].fieldnum
;
1640 key
->fields
[0].nthfieldname
=
1641 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1642 if (cf
->get_is_optional())
1643 key
->fields
[0].fieldtype
= OPTIONAL_FIELD
;
1644 else key
->fields
[0].fieldtype
= MANDATORY_FIELD
;
1645 key
->fields
[0].type
= pool
.add(t
->get_genname_value(my_scope
));
1646 key
->fields
[0].typedescr
=
1647 pool
.add(t
->get_genname_typedescriptor(my_scope
));
1650 for (int b
= 1; b
< key
->nElements
; b
++) {
1652 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->names
[b
-1];
1653 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1654 cf2
= t
->get_comp_byIndex(comp_index
);
1655 key
->fields
[b
].nthfield
= comp_index
;
1656 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1657 if (t
->typetype
== T_CHOICE_T
)
1658 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1659 else if (cf2
->get_is_optional())
1660 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1661 else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1662 Type
*field_type
= cf2
->get_type();
1663 key
->fields
[b
].type
=
1664 pool
.add(field_type
->get_genname_value(my_scope
));
1665 key
->fields
[b
].typedescr
=
1666 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1667 if (field_type
->typetype
== T_SEQ_T
&& field_type
->rawattrib
1668 && (field_type
->rawattrib
->pointerto
1669 || field_type
->rawattrib
->lengthto_num
))
1670 key
->start_pos
= -1;
1672 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1674 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1676 t2
= t
->get_comp_byIndex(i
)->get_type();
1677 if(t2
->get_raw_length() >= 0){
1679 key
->start_pos
+= t2
->rawattrib
->padding
;
1680 key
->start_pos
+= t2
->get_raw_length();
1681 }else key
->start_pos
= -1;
1684 t
= field_type
->get_type_refd_last();
1688 // building presence list
1689 for(int a
=0;a
<rawattrib
->presence
.nElements
;a
++) {
1690 rawAST_coding_field_list
* presences
=sdef
.raw
.presence
.fields
+a
;
1691 presences
->nElements
=
1692 rawattrib
->presence
.keyList
[a
].keyField
->nElements
;
1693 presences
->value
=rawattrib
->presence
.keyList
[a
].value
;
1694 presences
->fields
=(rawAST_coding_fields
*)
1695 Malloc(presences
->nElements
*sizeof(rawAST_coding_fields
));
1697 for (int b
= 0; b
< presences
->nElements
; b
++) {
1698 Identifier
*idf
= rawattrib
->presence
.keyList
[a
].keyField
->names
[b
];
1699 size_t comp_index
= t
->get_comp_index_byName(*idf
);
1700 CompField
*cf
= t
->get_comp_byIndex(comp_index
);
1701 presences
->fields
[b
].nthfield
= comp_index
;
1702 presences
->fields
[b
].nthfieldname
= idf
->get_name().c_str();
1703 if (t
->typetype
== T_CHOICE_T
)
1704 presences
->fields
[b
].fieldtype
= UNION_FIELD
;
1705 else if (cf
->get_is_optional())
1706 presences
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1707 else presences
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1708 Type
*field_type
= cf
->get_type();
1709 presences
->fields
[b
].type
=
1710 pool
.add(field_type
->get_genname_value(my_scope
));
1711 presences
->fields
[b
].typedescr
=
1712 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1713 t
= field_type
->get_type_refd_last();
1716 for(int c
=0;c
<rawattrib
->ext_bit_goup_num
;c
++){
1717 Identifier
*idf
=rawattrib
->ext_bit_groups
[c
].from
;
1718 Identifier
*idf2
=rawattrib
->ext_bit_groups
[c
].to
;
1719 sdef
.raw
.ext_bit_groups
[c
].ext_bit
=rawattrib
->ext_bit_groups
[c
].ext_bit
;
1720 sdef
.raw
.ext_bit_groups
[c
].from
=(int)get_comp_index_byName(*idf
);
1721 sdef
.raw
.ext_bit_groups
[c
].to
=(int)get_comp_index_byName(*idf2
);
1723 for(size_t i
=0; i
<sdef
.totalElements
; i
++) {
1724 CompField
*cf
= get_comp_byIndex(i
);
1725 Type
*t_field
= cf
->get_type();
1726 Type
*t_field_last
= t_field
->get_type_refd_last();
1727 RawAST
*rawpar
= t_field
->rawattrib
;
1729 copy_rawAST_to_struct(rawpar
,&(sdef
.elements
[i
].raw
));
1730 for(int j
=0; j
<rawpar
->lengthto_num
;j
++){
1731 Identifier
*idf
=rawpar
->lengthto
[j
];
1732 sdef
.elements
[i
].raw
.lengthto
[j
]=get_comp_index_byName(*idf
);
1734 if (rawpar
->lengthto_num
&& rawpar
->lengthindex
) {
1735 Identifier
*idf
= rawpar
->lengthindex
->names
[0];
1736 size_t comp_index
= t_field_last
->get_comp_index_byName(*idf
);
1737 sdef
.elements
[i
].raw
.lengthindex
->nthfield
= comp_index
;
1738 sdef
.elements
[i
].raw
.lengthindex
->nthfieldname
=
1739 idf
->get_name().c_str();
1740 CompField
*cf2
= t_field_last
->get_comp_byIndex(comp_index
);
1741 Type
*t_field2
= cf2
->get_type();
1742 if (t_field2
->typetype
== T_CHOICE_T
)
1743 sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= UNION_FIELD
;
1744 else if (cf2
->get_is_optional())
1745 sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= OPTIONAL_FIELD
;
1746 else sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= MANDATORY_FIELD
;
1747 sdef
.elements
[i
].raw
.lengthindex
->type
=
1748 pool
.add(t_field2
->get_genname_value(my_scope
));
1749 sdef
.elements
[i
].raw
.lengthindex
->typedescr
=
1750 pool
.add(t_field2
->get_genname_typedescriptor(my_scope
));
1752 if (rawpar
->lengthto_num
&& !rawpar
->lengthindex
&&
1753 t_field_last
->is_secho()) {
1754 int comp_num
=(int)t_field_last
->get_nof_comps();
1755 sdef
.elements
[i
].raw
.union_member_num
=comp_num
;
1756 sdef
.elements
[i
].raw
.member_name
=
1757 (const char **)Malloc((comp_num
+1)*sizeof(const char*));
1758 sdef
.elements
[i
].raw
.member_name
[0] =
1759 pool
.add(t_field_last
->get_genname_value(my_scope
));
1760 for(int m
=1;m
<comp_num
+1;m
++){
1761 CompField
*compf
=t_field_last
->get_comp_byIndex(m
-1);
1762 sdef
.elements
[i
].raw
.member_name
[m
]=
1763 compf
->get_name().get_name().c_str();
1766 if(rawpar
->pointerto
){
1767 Identifier
*idf
=rawpar
->pointerto
;
1768 sdef
.elements
[i
].raw
.pointerto
=get_comp_index_byName(*idf
);
1769 if(rawpar
->ptrbase
){
1770 Identifier
*idf2
=rawpar
->ptrbase
;
1771 sdef
.elements
[i
].raw
.pointerbase
=get_comp_index_byName(*idf2
);
1772 } else sdef
.elements
[i
].raw
.pointerbase
=i
;
1774 // building presence list
1775 for(int a
=0;a
<rawpar
->presence
.nElements
;a
++) {
1776 rawAST_coding_field_list
* presences
=
1777 sdef
.elements
[i
].raw
.presence
.fields
+a
;
1778 presences
->nElements
=
1779 rawpar
->presence
.keyList
[a
].keyField
->nElements
;
1780 presences
->value
=rawpar
->presence
.keyList
[a
].value
;
1781 presences
->fields
=(rawAST_coding_fields
*)
1782 Malloc(presences
->nElements
*sizeof(rawAST_coding_fields
));
1784 for (int b
= 0; b
< presences
->nElements
; b
++) {
1785 Identifier
*idf
= rawpar
->presence
.keyList
[a
].keyField
->names
[b
];
1786 size_t comp_index
= t
->get_comp_index_byName(*idf
);
1787 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1788 presences
->fields
[b
].nthfield
= comp_index
;
1789 presences
->fields
[b
].nthfieldname
= idf
->get_name().c_str();
1790 if (t
->typetype
== T_CHOICE_T
)
1791 presences
->fields
[b
].fieldtype
= UNION_FIELD
;
1792 else if (cf2
->get_is_optional())
1793 presences
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1794 else presences
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1795 Type
*field_type
= cf2
->get_type();
1796 presences
->fields
[b
].type
=
1797 pool
.add(field_type
->get_genname_value(my_scope
));
1798 presences
->fields
[b
].typedescr
=
1799 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1800 t
= field_type
->get_type_refd_last();
1803 // building crosstaglist
1804 for(int c
=0;c
<rawpar
->crosstaglist
.nElements
;c
++){
1805 if(rawpar
->crosstaglist
.tag
[c
].nElements
)
1806 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
=
1807 (rawAST_coding_field_list
*)
1808 Malloc(rawpar
->crosstaglist
.tag
[c
].nElements
1809 *sizeof(rawAST_coding_field_list
));
1810 else sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
=NULL
;
1811 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].nElements
=
1812 rawpar
->crosstaglist
.tag
[c
].nElements
;
1813 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldName
=
1814 rawpar
->crosstaglist
.tag
[c
].fieldName
->get_name().c_str();
1815 Identifier
*idf
=rawpar
->crosstaglist
.tag
[c
].fieldName
;
1816 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldnum
=
1817 t_field_last
->get_comp_index_byName(*idf
);
1818 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldnum
=
1819 t_field_last
->get_comp_index_byName(*idf
);
1820 for(int a
=0;a
<rawpar
->crosstaglist
.tag
[c
].nElements
;a
++) {
1821 rawAST_coding_field_list
* key
=
1822 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
+a
;
1824 rawpar
->crosstaglist
.tag
[c
].keyList
[a
].keyField
->nElements
;
1825 key
->value
=rawpar
->crosstaglist
.tag
[c
].keyList
[a
].value
;
1826 key
->fields
=(rawAST_coding_fields
*)
1827 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1829 for (int b
= 0; b
< key
->nElements
; b
++) {
1831 rawpar
->crosstaglist
.tag
[c
].keyList
[a
].keyField
->names
[b
];
1832 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1833 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1834 key
->fields
[b
].nthfield
= comp_index
;
1835 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1836 if (t
->typetype
== T_CHOICE_T
)
1837 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1838 else if (cf2
->get_is_optional())
1839 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1840 else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1841 Type
*field_type
= cf2
->get_type();
1842 key
->fields
[b
].type
=
1843 pool
.add(field_type
->get_genname_value(my_scope
));
1844 key
->fields
[b
].typedescr
=
1845 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1846 t
= field_type
->get_type_refd_last();
1850 sdef
.elements
[i
].raw
.length
= t_field
->get_raw_length();
1851 sdef
.elements
[i
].hasRaw
=true;
1854 sdef
.elements
[i
].hasRaw
=false;
1859 for(size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1860 sdef
.elements
[i
].hasRaw
=false;
1865 defRecordClass(&sdef
, target
);
1866 defRecordTemplate(&sdef
, target
);
1868 for(size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1869 // free the array but not the strings
1870 if (sdef
.elements
[i
].xerAnyNum
> 0) Free(sdef
.elements
[i
].xerAnyUris
);
1874 free_raw_attrib_struct(&sdef
.raw
);
1875 for (size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1876 if (sdef
.elements
[i
].hasRaw
) {
1877 free_raw_attrib_struct(&sdef
.elements
[i
].raw
);
1881 Free(sdef
.elements
);
1884 bool Type::is_untagged() const { return xerattrib
&& xerattrib
->untagged_
; }
1886 void Type::generate_code_SeOf(output_struct
*target
)
1888 const Type
*oftypelast
= u
.seof
.ofType
->get_type_refd_last();
1889 const string
& oftypename
= u
.seof
.ofType
->get_genname_value(my_scope
);
1890 boolean optimized_memalloc
= !use_runtime_2
&& get_optimize_attribute() == "memalloc";
1892 if (is_pregenerated()) {
1893 switch(oftypelast
->typetype
) {
1896 case T_TELETEXSTRING
:
1897 case T_VIDEOTEXSTRING
:
1898 case T_GRAPHICSTRING
:
1899 case T_GENERALSTRING
:
1900 case T_UNIVERSALSTRING
:
1902 case T_OBJECTDESCRIPTOR
:
1903 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
1904 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s %s;\n"
1905 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s_template %s_template;\n",
1906 (typetype
== T_SEQOF
) ? "RECORD" : "SET",
1907 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str(),
1908 (typetype
== T_SEQOF
) ? "RECORD" : "SET",
1909 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str());
1912 // generate these in the class declarations part, they need to be
1913 // outside of the include guard in case of circular imports
1914 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
1915 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s %s;\n"
1916 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s_template %s_template;\n",
1917 (typetype
== T_SEQOF
) ? "RECORD" : "SET", oftypename
.c_str(),
1918 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str(),
1919 (typetype
== T_SEQOF
) ? "RECORD" : "SET", oftypename
.c_str(),
1920 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str());
1926 struct_of_def sofdef
;
1927 memset(&sofdef
, 0, sizeof(sofdef
));
1928 sofdef
.name
= get_genname_own().c_str();
1929 sofdef
.dispname
= get_fullname().c_str();
1930 sofdef
.kind
= typetype
== T_SEQOF
? RECORD_OF
: SET_OF
;
1931 sofdef
.isASN1
= is_asn1();
1932 sofdef
.hasText
= textattrib
!=NULL
;
1933 sofdef
.hasXer
= has_encoding(CT_XER
);
1934 sofdef
.hasJson
= has_encoding(CT_JSON
);
1936 //sofdef.xerList = xerattrib->list_;
1937 sofdef
.xerAttribute
= xerattrib
->attribute_
;
1939 // If a record of UTF8String, we need to prepare for ANY-ATTRIBUTES and
1941 sofdef
.xerAnyAttrElem
= oftypelast
->typetype
== T_USTR
1942 || oftypelast
->typetype
== T_UTF8STRING
;
1943 sofdef
.type
= oftypename
.c_str();
1944 sofdef
.has_opentypes
= get_has_opentypes();
1945 const string
& oftypedescrname
=
1946 u
.seof
.ofType
->get_genname_typedescriptor(my_scope
);
1947 sofdef
.oftypedescrname
= oftypedescrname
.c_str();
1949 if (xerattrib
&& xerattrib
->untagged_
1950 && ((u
.seof
.ofType
->xerattrib
&& has_ae(u
.seof
.ofType
->xerattrib
))
1951 || (xerattrib
&& has_ae(xerattrib
)))) {
1952 // An untagged record-of which has an embedded type with ANY-ELEMENT,
1953 // or itself has ANY-ELEMENT
1954 if (parent_type
&& parent_type
->typetype
== T_SEQ_T
) {
1955 /* The record-of needs to know the optional siblings following it,
1956 * to be able to stop consuming XML elements that belong
1957 * to the following fields. This is achieved by generating
1958 * a can_start() for the record-of which returns false for XML elements
1959 * that belong to those following fields. */
1960 size_t n_parent_comps
= parent_type
->get_nof_comps();
1961 boolean found_self
= false;
1962 /* Go through the fields of the parent; skip everything until we find
1963 * the field that is this record-of; then collect fields until
1964 * the first non-disappearing field. */
1965 for (size_t pc
= 0; pc
< n_parent_comps
; ++pc
) {
1966 CompField
*pcf
= parent_type
->get_comp_byIndex(pc
); //"ParentCompField"
1967 Type
*pcft
= pcf
->get_type();
1969 const Identifier
& cfid
= pcf
->get_name();
1970 sofdef
.followers
= (struct_field
*)Realloc(sofdef
.followers
,
1971 (++sofdef
.nFollowers
) * sizeof(struct_field
));
1972 sofdef
.followers
[sofdef
.nFollowers
-1].name
= pool
.add(cfid
.get_name());
1973 sofdef
.followers
[sofdef
.nFollowers
-1].type
=
1974 pool
.add(pcft
->get_genname_value(my_scope
));
1975 sofdef
.followers
[sofdef
.nFollowers
-1].typegen
=
1976 pool
.add(pcft
->get_genname_own());
1978 Type
*pcft_last
= pcft
->get_type_refd_last();
1979 if (pcf
->get_is_optional()
1980 || (pcft
->is_untagged() && pcft_last
->has_empty_xml()))
1981 {} // can disappear, continue
1984 else if (pcft
== this) found_self
= true;
1986 } // if parent is record
1989 switch (oftypelast
->typetype
) { // X.680/2002, Table 5 under 25.5
1990 // T_CHOICE_A and T_CHOICE_T do not set xmlValueList because choice types
1991 // already omit their own tag.
1993 case T_ENUM_A
: case T_ENUM_T
:
1995 sofdef
.xmlValueList
= TRUE
;
1999 sofdef
.xmlValueList
= FALSE
;
2004 copy_rawAST_to_struct(rawattrib
,&(sofdef
.raw
));
2006 } else sofdef
.hasRaw
=false;
2008 if (optimized_memalloc
) {
2009 defRecordOfClassMemAllocOptimized(&sofdef
, target
);
2011 defRecordOfClass(&sofdef
, target
);
2013 defRecordOfTemplate(&sofdef
, target
);
2015 if (sofdef
.nFollowers
) {
2016 Free(sofdef
.followers
);
2020 void Type::generate_code_Array(output_struct
*target
)
2022 if (!u
.array
.in_typedef
) return;
2023 const char *own_name
= get_genname_own().c_str();
2024 if (has_encoding(CT_JSON
)) {
2025 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
2026 "class %s;\n", own_name
);
2027 target
->header
.class_defs
= mputprintf(target
->header
.class_defs
,
2028 "class %s : public %s {\n"
2029 "const TTCN_Typedescriptor_t* get_elem_descr() const;\n"
2032 u
.array
.dimension
->get_value_type(u
.array
.element_type
, my_scope
).c_str());
2033 target
->source
.class_defs
= mputprintf(target
->source
.class_defs
,
2034 "const TTCN_Typedescriptor_t* %s::get_elem_descr() const { return &%s_descr_; }\n\n",
2035 own_name
, u
.array
.element_type
->get_genname_typedescriptor(my_scope
).c_str());
2037 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
2039 "// written by %s in " __FILE__
" at %d\n"
2043 __FUNCTION__
, __LINE__
,
2045 u
.array
.dimension
->get_value_type(u
.array
.element_type
, my_scope
).c_str(),
2048 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
2049 "typedef %s %s_template;\n",
2050 u
.array
.dimension
->get_template_type(u
.array
.element_type
, my_scope
).c_str(),
2054 void Type::generate_code_Fat(output_struct
*target
)
2057 memset(&fdef
, 0, sizeof(fdef
));
2058 fdef
.name
= get_genname_own().c_str();
2059 fdef
.dispname
= get_fullname().c_str();
2062 if(u
.fatref
.return_type
)
2063 if(u
.fatref
.returns_template
)
2064 fdef
.return_type
= mcopystr(u
.fatref
.return_type
->
2065 get_genname_template(my_scope
).c_str());
2066 else fdef
.return_type
= mcopystr(u
.fatref
.return_type
->
2067 get_genname_value(my_scope
).c_str());
2068 else fdef
.return_type
= NULL
;
2069 fdef
.type
= FUNCTION
;
2072 fdef
.return_type
= NULL
;
2073 fdef
.type
= ALTSTEP
;
2076 fdef
.return_type
= NULL
;
2077 fdef
.type
= TESTCASE
;
2080 FATAL_ERROR("Type::generate_code_Fat()");
2082 fdef
.runs_on_self
= u
.fatref
.runs_on
.self
? TRUE
: FALSE
;
2083 fdef
.is_startable
= u
.fatref
.is_startable
;
2084 fdef
.formal_par_list
= u
.fatref
.fp_list
->generate_code(memptystr());
2085 u
.fatref
.fp_list
->generate_code_defval(target
);
2086 fdef
.actual_par_list
= u
.fatref
.fp_list
2087 ->generate_code_actual_parlist(memptystr(),"");
2088 if (typetype
== T_TESTCASE
) {
2089 if (u
.fatref
.fp_list
->get_nof_fps() > 0) {
2090 fdef
.formal_par_list
= mputstr(fdef
.formal_par_list
, ", ");
2091 fdef
.actual_par_list
= mputstr(fdef
.actual_par_list
, ", ");
2093 fdef
.formal_par_list
= mputstr(fdef
.formal_par_list
,
2094 "boolean has_timer, double timer_value");
2095 fdef
.actual_par_list
= mputstr(fdef
.actual_par_list
,
2096 "has_timer, timer_value");
2098 fdef
.nElements
= u
.fatref
.fp_list
->get_nof_fps();
2099 fdef
.parameters
= (const char**)
2100 Malloc(fdef
.nElements
* sizeof(*fdef
.parameters
));
2101 for(size_t i
= 0;i
< fdef
.nElements
; i
++) {
2102 fdef
.parameters
[i
] = u
.fatref
.fp_list
->get_fp_byIndex(i
)
2103 ->get_id().get_name().c_str();
2106 defFunctionrefClass(&fdef
, target
);
2107 defFunctionrefTemplate(&fdef
, target
);
2108 Free(fdef
.return_type
);
2109 Free(fdef
.formal_par_list
);
2110 Free(fdef
.actual_par_list
);
2111 Free(fdef
.parameters
);
2114 void Type::generate_code_Signature(output_struct
*target
)
2118 memset(&sdef
, 0, sizeof(sdef
));
2119 sdef
.name
= get_genname_own().c_str();
2120 sdef
.dispname
= get_fullname().c_str();
2121 if (u
.signature
.return_type
) sdef
.return_type
=
2122 pool
.add(u
.signature
.return_type
->get_genname_value(my_scope
));
2123 else sdef
.return_type
= NULL
;
2124 if (u
.signature
.parameters
) {
2125 sdef
.parameters
.nElements
= u
.signature
.parameters
->get_nof_params();
2126 sdef
.parameters
.elements
= (signature_par
*)
2127 Malloc(sdef
.parameters
.nElements
* sizeof(*sdef
.parameters
.elements
));
2128 for (size_t i
= 0; i
< sdef
.parameters
.nElements
; i
++) {
2129 SignatureParam
*param
= u
.signature
.parameters
->get_param_byIndex(i
);
2130 switch (param
->get_direction()) {
2131 case SignatureParam::PARAM_IN
:
2132 sdef
.parameters
.elements
[i
].direction
= PAR_IN
;
2134 case SignatureParam::PARAM_OUT
:
2135 sdef
.parameters
.elements
[i
].direction
= PAR_OUT
;
2137 case SignatureParam::PARAM_INOUT
:
2138 sdef
.parameters
.elements
[i
].direction
= PAR_INOUT
;
2141 FATAL_ERROR("Type::generate_code_Signature()");
2143 sdef
.parameters
.elements
[i
].type
=
2144 pool
.add(param
->get_type()->get_genname_value(my_scope
));
2145 sdef
.parameters
.elements
[i
].name
= param
->get_id().get_name().c_str();
2146 sdef
.parameters
.elements
[i
].dispname
=
2147 param
->get_id().get_ttcnname().c_str();
2150 sdef
.parameters
.nElements
= 0;
2151 sdef
.parameters
.elements
= NULL
;
2153 sdef
.is_noblock
= u
.signature
.no_block
;
2154 if (u
.signature
.exceptions
) {
2155 sdef
.exceptions
.nElements
= u
.signature
.exceptions
->get_nof_types();
2156 sdef
.exceptions
.elements
= (signature_exception
*)
2157 Malloc(sdef
.exceptions
.nElements
* sizeof(*sdef
.exceptions
.elements
));
2158 for (size_t i
= 0; i
< sdef
.exceptions
.nElements
; i
++) {
2159 Type
*type
= u
.signature
.exceptions
->get_type_byIndex(i
);
2160 sdef
.exceptions
.elements
[i
].name
=
2161 pool
.add(type
->get_genname_value(my_scope
));
2162 sdef
.exceptions
.elements
[i
].dispname
= pool
.add(type
->get_typename());
2163 sdef
.exceptions
.elements
[i
].altname
= pool
.add(type
->get_genname_altname());
2166 sdef
.exceptions
.nElements
= 0;
2167 sdef
.exceptions
.elements
= NULL
;
2169 defSignatureClasses(&sdef
, target
);
2170 Free(sdef
.parameters
.elements
);
2171 Free(sdef
.exceptions
.elements
);
2174 bool Type::needs_alias()
2176 /** The decision is actually based on the fullname of the type. If it
2177 * contains two or more dot (.) characters false is returned.
2178 * The following attributes cannot be used for the decision:
2179 * - parent_type, my_scope: types within ASN.1 object classes, objects
2180 * look the same as top-level aliased types, but they do not need alias. */
2181 const string
& full_name
= get_fullname();
2182 size_t fullname_len
= full_name
.size();
2183 size_t first_dot
= full_name
.find('.', 0);
2184 if (first_dot
>= fullname_len
) return true; // no dots
2185 else if (full_name
.find('.', first_dot
+ 1) < fullname_len
) return false;
2190 void Type::generate_code_done(output_struct
*target
)
2192 const string
& t_genname
= get_genname_value(my_scope
);
2193 const char *genname_str
= t_genname
.c_str();
2194 const string
& dispname
= get_typename();
2195 const char *dispname_str
= dispname
.c_str();
2196 target
->header
.function_prototypes
= mputprintf
2197 (target
->header
.function_prototypes
,
2198 "extern alt_status done(const COMPONENT& component_reference, "
2199 "const %s_template& value_template, %s *value_ptr);\n",
2200 genname_str
, genname_str
);
2201 target
->source
.function_bodies
= mputprintf
2202 (target
->source
.function_bodies
,
2203 "alt_status done(const COMPONENT& component_reference, "
2204 "const %s_template& value_template, %s *value_ptr)\n"
2206 "if (!component_reference.is_bound()) "
2207 "TTCN_error(\"Performing a done operation on an unbound component "
2209 "Text_Buf *text_buf;\n"
2210 "alt_status ret_val = TTCN_Runtime::component_done("
2211 "(component)component_reference, \"%s\", text_buf);\n"
2212 "if (ret_val == ALT_YES) {\n"
2213 "%s return_value;\n"
2214 "return_value.decode_text(*text_buf);\n"
2215 "if (value_template.match(return_value)) {\n"
2216 "if (value_ptr != NULL) *value_ptr = return_value;\n"
2217 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
2218 "TTCN_Logger::log_event_str(\"PTC with component reference \");\n"
2219 "component_reference.log();\n"
2220 "TTCN_Logger::log_event_str(\" is done. Return value: %s : \");\n"
2221 "return_value.log();\n"
2222 "TTCN_Logger::end_event();\n"
2225 "if (TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_DONE)) {\n"
2226 "TTCN_Logger::begin_event(TTCN_Logger::MATCHING_DONE);\n"
2227 "TTCN_Logger::log_event_str(\"Done operation with type %s on"
2228 " component reference \");\n"
2229 "component_reference.log();\n"
2230 "TTCN_Logger::log_event_str(\" failed: Return value does not match "
2231 "the template: \");\n"
2232 "value_template.log_match(return_value%s);\n"
2233 "TTCN_Logger::end_event();\n"
2237 "} else return ret_val;\n"
2239 genname_str
, genname_str
, dispname_str
, genname_str
, dispname_str
,
2240 dispname_str
, omit_in_value_list
? ", TRUE" : "");
2243 bool Type::ispresent_anyvalue_embedded_field(Type
* t
,
2244 Ttcn::FieldOrArrayRefs
*subrefs
, size_t begin_index
)
2246 if (!subrefs
) return true;
2247 size_t nof_refs
= subrefs
->get_nof_refs();
2248 for (size_t i
= begin_index
; i
< nof_refs
; i
++) {
2249 t
= t
->get_type_refd_last();
2250 Ttcn::FieldOrArrayRef
*ref
= subrefs
->get_ref(i
);
2251 switch (ref
->get_type()) {
2252 case Ttcn::FieldOrArrayRef::FIELD_REF
: {
2253 CompField
* cf
= t
->get_comp_byName(*ref
->get_id());
2254 switch (t
->typetype
) {
2264 if (cf
->get_is_optional()) return false;
2267 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2271 case Ttcn::FieldOrArrayRef::ARRAY_REF
:
2272 switch (t
->typetype
) {
2275 return false; // (the existence of a record of element is optional)
2277 t
= t
->u
.array
.element_type
;
2280 return true; // string types
2284 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2290 void Type::generate_code_ispresentbound(expression_struct
*expr
,
2291 Ttcn::FieldOrArrayRefs
*subrefs
, Common::Module
* module
,
2292 const string
& global_id
, const string
& external_id
, const bool is_template
,
2295 if (!subrefs
) return;
2299 bool next_o
; // next is optional value
2300 size_t nof_refs
= subrefs
->get_nof_refs();
2301 subrefs
->clear_string_element_ref();
2302 char *tmp_generalid_str
= mcopystr(external_id
.c_str());
2303 expstring_t closing_brackets
= memptystr(); //The closing parts collected
2304 for (size_t i
= 0; i
< nof_refs
; i
++) {
2305 t
= t
->get_type_refd_last();
2306 // stop immediately if current type t is erroneous
2307 // (e.g. because of circular reference)
2308 if (t
->typetype
== T_ERROR
) return;
2311 bool anyval_ret_val
= true;
2313 anyval_ret_val
= ispresent_anyvalue_embedded_field(t
, subrefs
, i
);
2315 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2316 expr
->expr
= mputprintf(expr
->expr
,
2317 "switch (%s.get_selection()) {\n"
2318 "case UNINITIALIZED_TEMPLATE:\n"
2324 "case SPECIFIC_VALUE: {\n",
2325 tmp_generalid_str
, global_id
.c_str(), global_id
.c_str(),
2326 anyval_ret_val
? "true" : "false");
2328 expstring_t closing_brackets_switch
= mprintf(
2336 global_id
.c_str(), closing_brackets
);
2337 Free(closing_brackets
);
2338 closing_brackets
= closing_brackets_switch
;
2341 Ttcn::FieldOrArrayRef
*ref
= subrefs
->get_ref(i
);
2342 switch (ref
->get_type()) {
2343 case Ttcn::FieldOrArrayRef::FIELD_REF
: {
2344 const Identifier
& id
= *ref
->get_id();
2345 CompField
* cf
= t
->get_comp_byName(id
);
2346 next_t
= cf
->get_type();
2347 next_o
= !is_template
&& cf
->get_is_optional();
2349 switch (t
->typetype
) {
2353 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2354 expr
->expr
= mputprintf(expr
->expr
,
2355 "%s = %s.ischosen(%s::ALT_%s);\n", global_id
.c_str(),
2357 t
->get_genname_value(module
).c_str(),
2358 id
.get_name().c_str());
2359 expr
->expr
= mputstr(expr
->expr
, "}\n");
2360 // intentionally missing break
2368 FATAL_ERROR("Type::generate_code_isbound()");
2372 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2373 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2374 Free(closing_brackets
);
2375 closing_brackets
= closing_brackets2
;
2377 const string
& tmp_id
= module
->get_temporary_id();
2378 const char *tmp_id_str
= tmp_id
.c_str();
2379 expr
->expr
= mputprintf(expr
->expr
,
2380 "const OPTIONAL<%s%s>& %s = %s.%s();\n",
2381 next_t
->get_genname_value(module
).c_str(),
2382 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2383 id
.get_name().c_str());
2385 if (i
==(nof_refs
-1)) {
2386 // we are at the end of the reference chain
2387 expr
->expr
= mputprintf(expr
->expr
,
2388 "switch (%s.get_selection()) {\n"
2389 "case OPTIONAL_UNBOUND:\n"
2392 "case OPTIONAL_OMIT:\n"
2396 tmp_id_str
, global_id
.c_str(),global_id
.c_str(),
2397 isbound
? "true" : "false");
2398 Free(tmp_generalid_str
);
2399 tmp_generalid_str
= mcopystr(tmp_id_str
);
2401 expr
->expr
= mputstr(expr
->expr
, "{\n");
2402 const string
& tmp_id2
= module
->get_temporary_id();
2403 const char *tmp_id2_str
= tmp_id2
.c_str();
2404 expr
->expr
= mputprintf(expr
->expr
,
2405 "const %s%s& %s = (const %s%s&) %s;\n",
2406 next_t
->get_genname_value(module
).c_str(),
2407 is_template
?"_template":"", tmp_id2_str
,
2408 next_t
->get_genname_value(module
).c_str(),
2409 is_template
?"_template":"", tmp_id_str
);
2411 expr
->expr
= mputprintf(expr
->expr
,
2412 "%s = %s.%s(%s);\n", global_id
.c_str(),
2413 tmp_id2_str
, isbound
? "is_bound" : "is_present",
2414 (!isbound
&& is_template
&& omit_in_value_list
) ? "TRUE" : "");
2415 Free(tmp_generalid_str
);
2416 tmp_generalid_str
= mcopystr(tmp_id2_str
);
2418 expr
->expr
= mputprintf(expr
->expr
,
2422 expr
->expr
= mputprintf(expr
->expr
,
2423 "switch (%s.get_selection()) {\n"
2424 "case OPTIONAL_UNBOUND:\n"
2425 "case OPTIONAL_OMIT:\n"
2431 tmp_id_str
, global_id
.c_str());
2432 Free(tmp_generalid_str
);
2433 tmp_generalid_str
= mcopystr(tmp_id_str
);
2435 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2436 closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2437 Free(closing_brackets
);
2438 closing_brackets
= closing_brackets2
;
2440 const string
& tmp_id2
= module
->get_temporary_id();
2441 const char *tmp_id2_str
= tmp_id2
.c_str();
2442 expr
->expr
= mputprintf(expr
->expr
,
2443 "const %s%s& %s = (const %s%s&) %s;\n",
2444 next_t
->get_genname_value(module
).c_str(),
2445 is_template
?"_template":"", tmp_id2_str
,
2446 next_t
->get_genname_value(module
).c_str(),
2447 is_template
?"_template":"", tmp_id_str
);
2449 expr
->expr
= mputprintf(expr
->expr
,
2450 "%s = %s.is_bound();\n", global_id
.c_str(),
2452 Free(tmp_generalid_str
);
2453 tmp_generalid_str
= mcopystr(tmp_id2_str
);
2456 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2457 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2458 Free(closing_brackets
);
2459 closing_brackets
= closing_brackets2
;
2461 const string
& tmp_id
= module
->get_temporary_id();
2462 const char *tmp_id_str
= tmp_id
.c_str();
2463 expr
->expr
= mputprintf(expr
->expr
,
2464 "const %s%s& %s = %s.%s();\n",
2465 next_t
->get_genname_value(module
).c_str(),
2466 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2467 id
.get_name().c_str());
2469 expr
->expr
= mputprintf(expr
->expr
,
2470 "%s = %s.%s(%s);\n", global_id
.c_str(),
2471 tmp_id_str
, isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2472 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2473 Free(tmp_generalid_str
);
2474 tmp_generalid_str
= mcopystr(tmp_id_str
);
2479 case Ttcn::FieldOrArrayRef::ARRAY_REF
: {
2480 Type
*embedded_type
= 0;
2481 bool is_string
= true;
2482 bool is_string_element
= false;
2483 switch (t
->typetype
) {
2486 embedded_type
= t
->u
.seof
.ofType
;
2490 embedded_type
= t
->u
.array
.element_type
;
2500 case T_NUMERICSTRING
:
2501 case T_PRINTABLESTRING
:
2502 case T_TELETEXSTRING
:
2503 case T_VIDEOTEXSTRING
:
2505 case T_GRAPHICSTRING
:
2506 case T_VISIBLESTRING
:
2507 case T_GENERALSTRING
:
2508 case T_UNIVERSALSTRING
:
2511 case T_GENERALIZEDTIME
:
2512 case T_OBJECTDESCRIPTOR
:
2513 if (subrefs
->refers_to_string_element()) {
2514 FATAL_ERROR("Type::generate_code_isbound()");
2516 subrefs
->set_string_element_ref();
2517 // string elements have the same type as the string itself
2519 is_string_element
= true;
2523 FATAL_ERROR("Type::generate_code_isbound()");
2526 next_t
= embedded_type
;
2528 // check the index value
2529 Value
*index_value
= ref
->get_val();
2530 Value
*v_last
= index_value
->get_value_refd_last();
2532 const string
& tmp_index_id
= module
->get_temporary_id();
2533 const char *tmp_index_id_str
= tmp_index_id
.c_str();
2534 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2536 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2537 Free(closing_brackets
);
2538 closing_brackets
= closing_brackets2
;
2540 expr
->expr
= mputprintf(expr
->expr
, "const int %s = ", tmp_index_id_str
);
2541 v_last
->generate_code_expr_mandatory(expr
);
2542 expr
->expr
= mputstr(expr
->expr
, ";\n");
2543 expr
->expr
= mputprintf(expr
->expr
, "%s = (%s >= 0) && (%s.%s > %s);\n",
2544 global_id
.c_str(), tmp_index_id_str
, tmp_generalid_str
,
2545 is_string
? "lengthof()": ( is_template
? "n_elem()" : "size_of()" ),
2547 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2549 closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2550 Free(closing_brackets
);
2551 closing_brackets
= closing_brackets2
;
2553 const string
& tmp_id
= module
->get_temporary_id();
2554 const char *tmp_id_str
= tmp_id
.c_str();
2556 if (is_string_element
) {
2557 expr
->expr
= mputprintf(expr
->expr
,
2558 "%s = %s[%s].%s(%s);\n", global_id
.c_str(),
2559 tmp_generalid_str
, tmp_index_id_str
,
2560 isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2561 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2564 expr
->expr
= mputprintf(expr
->expr
,
2565 "const %s& %s = %s[%s];\n",
2566 next_t
->get_genname_template(module
).c_str(),
2567 tmp_id_str
, tmp_generalid_str
,
2570 expr
->expr
= mputprintf(expr
->expr
,
2571 "const %s%s& %s = %s[%s];\n",
2572 next_t
->get_genname_value(module
).c_str(),
2573 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2577 expr
->expr
= mputprintf(expr
->expr
,
2578 "%s = %s.%s(%s);\n", global_id
.c_str(), tmp_id_str
,
2579 isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2580 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2583 Free(tmp_generalid_str
);
2584 tmp_generalid_str
= mcopystr(tmp_id_str
);
2586 // change t to the embedded type
2590 FATAL_ERROR("Type::generate_code_isbound(): invalid reference type");
2594 Free(tmp_generalid_str
);
2595 expr
->expr
= mputstr(expr
->expr
, closing_brackets
);
2596 Free(closing_brackets
);
2599 string
Type::get_optimize_attribute()
2603 vector
<SingleWithAttrib
> const &real_attribs
2604 = w_attrib_path
->get_real_attrib();
2605 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2606 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2607 if (temp_single
->get_attribKeyword()
2608 == SingleWithAttrib::AT_EXTENSION
2609 && (!temp_single
->get_attribQualifiers()
2610 || (temp_single
->get_attribQualifiers()
2611 ->get_nof_qualifiers() == 0)))
2613 const string
& spec
= temp_single
->get_attribSpec().get_spec();
2614 // TODO: use a real parser to allow whitespaces, etc.
2615 if (spec
.find("optimize:")==0 && spec
.size()>9)
2617 string spec_optimize_for_what
= spec
.substr(9);
2618 return spec_optimize_for_what
;
2626 string
Type::get_sourcefile_attribute()
2630 vector
<SingleWithAttrib
> const &real_attribs
2631 = w_attrib_path
->get_real_attrib();
2633 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2634 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2635 if (temp_single
->get_attribKeyword()
2636 == SingleWithAttrib::AT_EXTENSION
2637 && (!temp_single
->get_attribQualifiers()
2638 || (temp_single
->get_attribQualifiers()
2639 ->get_nof_qualifiers() == 0)))
2641 const string
& spec
= temp_single
->get_attribSpec().get_spec();
2642 if (spec
.find("sourcefile:")==0 && spec
.size()>11)
2644 string spec_filename
= spec
.substr(11);
2645 // TODO: check if string can be a valid filename
2646 return spec_filename
;
2654 bool Type::has_done_attribute()
2658 vector
<SingleWithAttrib
> const &real_attribs
2659 = w_attrib_path
->get_real_attrib();
2661 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2662 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2663 if (temp_single
->get_attribKeyword()
2664 == SingleWithAttrib::AT_EXTENSION
2665 && (!temp_single
->get_attribQualifiers()
2666 || (temp_single
->get_attribQualifiers()
2667 ->get_nof_qualifiers() == 0))
2668 && temp_single
->get_attribSpec().get_spec() == "done")
2677 void Type::generate_code_object(const_def
*cdef
, Scope
*p_scope
,
2678 const string
& name
, const char *prefix
, bool is_template
)
2681 if (is_template
) type_name
= get_genname_template(p_scope
);
2682 else type_name
= get_genname_value(p_scope
);
2683 const char *name_str
= name
.c_str();
2684 const char *type_name_str
= type_name
.c_str();
2686 cdef
->decl
= mputprintf(cdef
->decl
, "extern const %s& %s;\n",
2687 type_name_str
, name_str
);
2688 cdef
->def
= mputprintf(cdef
->def
, "static %s %s%s;\n"
2689 "const %s& %s = %s%s;\n", type_name_str
, prefix
, name_str
,
2690 type_name_str
, name_str
, prefix
, name_str
);
2692 cdef
->decl
= mputprintf(cdef
->decl
, "extern %s %s;\n",
2693 type_name_str
, name_str
);
2694 cdef
->def
= mputprintf(cdef
->def
, "%s %s;\n",
2695 type_name_str
, name_str
);
2699 void Type::generate_code_object(const_def
*cdef
, GovernedSimple
*p_setting
)
2701 bool is_template
= false;
2702 switch (p_setting
->get_st()) {
2709 FATAL_ERROR("Type::generate_code_object()");
2711 if (p_setting
->get_err_descr()) {
2712 cdef
->def
= p_setting
->get_err_descr()->generate_code_str(cdef
->def
,
2713 p_setting
->get_genname_prefix() + p_setting
->get_genname_own());
2715 generate_code_object(cdef
, p_setting
->get_my_scope(),
2716 p_setting
->get_genname_own(), p_setting
->get_genname_prefix(),
2720 void Type::generate_json_schema(JSON_Tokenizer
& json
, bool embedded
, bool as_value
)
2722 // add a new property for the type if it has its own definition
2724 json
.put_next_token(JSON_TOKEN_NAME
, get_dispname().c_str());
2727 // create an object containing the type's schema
2728 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2730 // if this is a field of a record/set/union with an alias, the field's
2731 // original name must be stored ("originalName" property), it also needs to be
2732 // stored if this is a field of a union with the "as value" coding instruction
2733 if (ownertype
== OT_COMP_FIELD
) {
2734 CompField
* cf
= static_cast<CompField
*>(owner
);
2735 if (as_value
|| (cf
->get_type()->jsonattrib
!= NULL
2736 && cf
->get_type()->jsonattrib
->alias
!= NULL
)) {
2737 json
.put_next_token(JSON_TOKEN_NAME
, "originalName");
2738 char* field_str
= mprintf("\"%s\"", cf
->get_name().get_ttcnname().c_str());
2739 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
2743 // if the parent is a union with the "as value" coding instruction AND the field
2744 // has an alias, then the alias needs to be stored as well ("unusedAlias" property)
2745 if (as_value
&& cf
->get_type()->jsonattrib
!= NULL
2746 && cf
->get_type()->jsonattrib
->alias
!= NULL
) {
2747 json
.put_next_token(JSON_TOKEN_NAME
, "unusedAlias");
2748 char* alias_str
= mprintf("\"%s\"", cf
->get_type()->jsonattrib
->alias
);
2749 json
.put_next_token(JSON_TOKEN_STRING
, alias_str
);
2754 // get the type at the end of the reference chain
2755 Type
* last
= get_type_refd_last();
2757 // check if this is a reference to another type that has its own definition
2758 Type
* refd_type
= NULL
;
2761 while (iter
->is_ref()) {
2762 iter
= iter
->get_type_refd();
2763 if (iter
->ownertype
== OT_TYPE_DEF
|| /* TTCN-3 type definition */
2764 iter
->ownertype
== OT_TYPE_ASS
) { /* ASN.1 type assignment */
2771 // check if there are any type restrictions
2772 boolean has_restrictions
= sub_type
!= NULL
&& sub_type
->has_json_schema();
2774 // if it's a referenced type, then its schema already exists, only add a pointer to it
2775 // exception: instances of ASN.1 parameterized types, always embed their schemas
2776 if (refd_type
!= NULL
&& !get_type_refd()->pard_type_instance
) {
2777 if (has_restrictions
) {
2778 // an 'allOf' structure is needed if this is a subtype,
2779 // insert the pointer in the first part
2780 json
.put_next_token(JSON_TOKEN_NAME
, "allOf");
2781 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2782 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2784 json
.put_next_token(JSON_TOKEN_NAME
, "$ref");
2785 char* ref_str
= mprintf("\"#/definitions/%s/%s\"",
2786 refd_type
->my_scope
->get_scope_mod()->get_modid().get_ttcnname().c_str(),
2787 refd_type
->get_dispname().c_str());
2788 json
.put_next_token(JSON_TOKEN_STRING
, ref_str
);
2790 if (has_restrictions
) {
2791 // close the first part of the 'allOf' and insert the type restrictions
2792 // in the second part
2793 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2794 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2796 // pass the tokenizer to the subtype to insert the type restrictions' schema
2797 sub_type
->generate_json_schema(json
);
2799 // close the second part and the 'allOf' structure itself
2800 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2801 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2804 // generate the schema for the referenced type
2805 switch (last
->typetype
) {
2807 // use the JSON boolean type
2808 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2809 json
.put_next_token(JSON_TOKEN_STRING
, "\"boolean\"");
2813 // use the JSON integer type
2814 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2815 json
.put_next_token(JSON_TOKEN_STRING
, "\"integer\"");
2818 if (has_restrictions
) {
2819 // adding restrictions after the type's schema wouldn't work here
2820 // if the restrictions affect the special values
2821 // use a special function that generates the schema segment for both
2822 // the float type and its restrictions
2823 sub_type
->generate_json_schema_float(json
);
2824 has_restrictions
= false; // so they aren't generated twice
2827 // any of: JSON number or the special values as strings (in an enum)
2828 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
2829 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2830 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2831 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2832 json
.put_next_token(JSON_TOKEN_STRING
, "\"number\"");
2833 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2834 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2835 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2836 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2837 json
.put_next_token(JSON_TOKEN_STRING
, "\"not_a_number\"");
2838 json
.put_next_token(JSON_TOKEN_STRING
, "\"infinity\"");
2839 json
.put_next_token(JSON_TOKEN_STRING
, "\"-infinity\"");
2840 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2841 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2842 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2850 // use the JSON string type and add a pattern to only allow bits or hex digits
2851 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2852 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2853 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2854 json
.put_next_token(JSON_TOKEN_STRING
,
2855 (last
->typetype
== T_OSTR
|| last
->typetype
== T_ANY
) ? "\"octetstring\"" :
2856 ((last
->typetype
== T_HSTR
) ? "\"hexstring\"" : "\"bitstring\""));
2857 json
.put_next_token(JSON_TOKEN_NAME
, "pattern");
2858 json
.put_next_token(JSON_TOKEN_STRING
,
2859 (last
->typetype
== T_OSTR
|| last
->typetype
== T_ANY
) ? "\"^([0-9A-Fa-f][0-9A-Fa-f])*$\"" :
2860 ((last
->typetype
== T_HSTR
) ? "\"^[0-9A-Fa-f]*$\"" : "\"^[01]*$\""));
2863 case T_NUMERICSTRING
:
2864 case T_PRINTABLESTRING
:
2866 case T_VISIBLESTRING
:
2867 // use the JSON string type and add a "subType" property to distinguish it from
2868 // universal charstring types
2869 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2870 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2871 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2872 json
.put_next_token(JSON_TOKEN_STRING
, "\"charstring\"");
2875 case T_GENERALSTRING
:
2876 case T_UNIVERSALSTRING
:
2879 case T_GRAPHICSTRING
:
2880 case T_TELETEXSTRING
:
2881 case T_VIDEOTEXSTRING
:
2882 // use the JSON string type and add a "subType" property to distinguish it from
2884 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2885 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2886 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2887 json
.put_next_token(JSON_TOKEN_STRING
, "\"universal charstring\"");
2891 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2892 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2893 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2894 json
.put_next_token(JSON_TOKEN_STRING
, "\"objid\"");
2895 json
.put_next_token(JSON_TOKEN_NAME
, "pattern");
2896 json
.put_next_token(JSON_TOKEN_STRING
, "\"^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$\"");
2899 if (has_restrictions
) {
2900 // the restrictions would only add another JSON enum (after the one
2901 /// generated below), instead just insert the one with the restrictions
2902 sub_type
->generate_json_schema(json
);
2903 has_restrictions
= false; // so they aren't generated twice
2906 // enumerate the possible values
2907 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2908 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2909 json
.put_next_token(JSON_TOKEN_STRING
, "\"none\"");
2910 json
.put_next_token(JSON_TOKEN_STRING
, "\"pass\"");
2911 json
.put_next_token(JSON_TOKEN_STRING
, "\"inconc\"");
2912 json
.put_next_token(JSON_TOKEN_STRING
, "\"fail\"");
2913 json
.put_next_token(JSON_TOKEN_STRING
, "\"error\"");
2914 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2919 // enumerate the possible values
2920 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2921 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2922 for (size_t i
= 0; i
< last
->u
.enums
.eis
->get_nof_eis(); ++i
) {
2923 char* enum_str
= mprintf("\"%s\"", last
->get_ei_byIndex(i
)->get_name().get_ttcnname().c_str());
2924 json
.put_next_token(JSON_TOKEN_STRING
, enum_str
);
2927 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2928 // list the numeric values for the enumerated items
2929 json
.put_next_token(JSON_TOKEN_NAME
, "numericValues");
2930 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2931 for (size_t i
= 0; i
< last
->u
.enums
.eis
->get_nof_eis(); ++i
) {
2932 char* num_val_str
= mprintf("%lli", last
->get_ei_byIndex(i
)->get_value()->get_val_Int()->get_val());
2933 json
.put_next_token(JSON_TOKEN_NUMBER
, num_val_str
);
2936 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2939 // use the JSON null value for the ASN.1 NULL type
2940 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2941 json
.put_next_token(JSON_TOKEN_STRING
, "\"null\"");
2946 last
->generate_json_schema_array(json
);
2952 last
->generate_json_schema_record(json
);
2958 last
->generate_json_schema_union(json
);
2961 FATAL_ERROR("Type::generate_json_schema");
2964 if (has_restrictions
) {
2965 // pass the tokenizer to the subtype to insert the type restrictions' schema
2966 sub_type
->generate_json_schema(json
);
2970 // insert default value (if any)
2971 if (jsonattrib
!= NULL
&& jsonattrib
->default_value
!= NULL
) {
2972 json
.put_next_token(JSON_TOKEN_NAME
, "default");
2973 switch (last
->typetype
) {
2975 json
.put_next_token((jsonattrib
->default_value
[0] == 't') ?
2976 JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
);
2980 if (jsonattrib
->default_value
[0] != 'n' && jsonattrib
->default_value
[0] != 'i'
2981 && jsonattrib
->default_value
[1] != 'i') {
2982 json
.put_next_token(JSON_TOKEN_NUMBER
, jsonattrib
->default_value
);
2985 // no break, insert the special float values as strings
2993 char* default_str
= mprintf("\"%s\"", jsonattrib
->default_value
);
2994 json
.put_next_token(JSON_TOKEN_STRING
, default_str
);
2998 FATAL_ERROR("Type::generate_json_schema");
3002 // insert schema extensions (if any)
3003 if (jsonattrib
!= NULL
) {
3004 for (size_t i
= 0; i
< jsonattrib
->schema_extensions
.size(); ++i
) {
3005 json
.put_next_token(JSON_TOKEN_NAME
, jsonattrib
->schema_extensions
[i
]->key
);
3006 char* value_str
= mprintf("\"%s\"", jsonattrib
->schema_extensions
[i
]->value
);
3007 json
.put_next_token(JSON_TOKEN_STRING
, value_str
);
3012 // end of type's schema
3013 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3016 void Type::generate_json_schema_array(JSON_Tokenizer
& json
)
3018 // use the JSON array type
3019 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3020 json
.put_next_token(JSON_TOKEN_STRING
, "\"array\"");
3022 if (typetype
!= T_ARRAY
) {
3023 // use the "subType" property to distinguish 'record of' from 'set of'
3024 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
3025 json
.put_next_token(JSON_TOKEN_STRING
, (typetype
== T_SEQOF
) ?
3026 "\"record of\"" : "\"set of\"");
3028 // set the number of elements for arrays
3029 char* size_str
= mprintf("%lu", get_nof_comps());
3030 json
.put_next_token(JSON_TOKEN_NAME
, "minItems");
3031 json
.put_next_token(JSON_TOKEN_NUMBER
, size_str
);
3032 json
.put_next_token(JSON_TOKEN_NAME
, "maxItems");
3033 json
.put_next_token(JSON_TOKEN_NUMBER
, size_str
);
3037 // set the element type
3038 json
.put_next_token(JSON_TOKEN_NAME
, "items");
3040 // pass the tokenizer to the elements' type object to insert its schema
3041 get_ofType()->generate_json_schema(json
, true, false);
3044 void Type::generate_json_schema_record(JSON_Tokenizer
& json
)
3046 // use the JSON object type
3047 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3048 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
3050 // use the "subType" property to distinguish records from sets
3051 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
3052 json
.put_next_token(JSON_TOKEN_STRING
, (typetype
== T_SEQ_T
|| typetype
== T_SEQ_A
) ?
3053 "\"record\"" : "\"set\"");
3056 json
.put_next_token(JSON_TOKEN_NAME
, "properties");
3057 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3058 size_t field_count
= get_nof_comps();
3059 bool has_non_optional
= false;
3060 for (size_t i
= 0; i
< field_count
; ++i
) {
3061 Type
* field
= get_comp_byIndex(i
)->get_type();
3063 // use the field's alias if it has one
3064 json
.put_next_token(JSON_TOKEN_NAME
,
3065 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3066 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3068 // optional fields can also get the JSON null value
3069 if (get_comp_byIndex(i
)->get_is_optional()) {
3070 // special case: ASN NULL type, since it uses the JSON literal "null" as a value
3071 if (T_NULL
!= field
->get_type_refd_last()->typetype
) {
3072 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3073 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
3074 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3075 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3076 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3077 json
.put_next_token(JSON_TOKEN_STRING
, "\"null\"");
3078 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3080 } else if (!has_non_optional
) {
3081 has_non_optional
= true;
3084 // pass the tokenizer to the field's type to insert its schema
3085 field
->generate_json_schema(json
, true, false);
3087 // for optional fields: specify the presence of the "omit as null" coding instruction
3088 // and close structures
3089 if (get_comp_byIndex(i
)->get_is_optional() &&
3090 T_NULL
!= field
->get_type_refd_last()->typetype
) {
3091 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3092 json
.put_next_token(JSON_TOKEN_NAME
, "omitAsNull");
3093 json
.put_next_token((field
->jsonattrib
!= NULL
&& field
->jsonattrib
->omit_as_null
) ?
3094 JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
);
3095 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3099 // end of properties
3100 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3102 // do not accept additional fields
3103 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3104 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
3106 // set the field order
3107 if (field_count
> 1) {
3108 json
.put_next_token(JSON_TOKEN_NAME
, "fieldOrder");
3109 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3110 for (size_t i
= 0; i
< field_count
; ++i
) {
3111 Type
* field
= get_comp_byIndex(i
)->get_type();
3112 // use the field's alias if it has one
3113 char* field_str
= mprintf("\"%s\"",
3114 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3115 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3116 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3119 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3122 // set the required (non-optional) fields
3123 if (has_non_optional
) {
3124 json
.put_next_token(JSON_TOKEN_NAME
, "required");
3125 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3126 for (size_t i
= 0; i
< field_count
; ++i
) {
3127 if (!get_comp_byIndex(i
)->get_is_optional()) {
3128 Type
* field
= get_comp_byIndex(i
)->get_type();
3129 // use the field's alias if it has one
3130 char* field_str
= mprintf("\"%s\"",
3131 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3132 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3133 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3137 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3141 void Type::generate_json_schema_union(JSON_Tokenizer
& json
)
3143 // use an "anyOf" structure containing the union's alternatives
3144 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
3145 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3147 for (size_t i
= 0; i
< get_nof_comps(); ++i
) {
3148 Type
* field
= get_comp_byIndex(i
)->get_type();
3150 if (jsonattrib
!= NULL
&& jsonattrib
->as_value
) {
3151 // only add the alternative's schema
3152 field
->generate_json_schema(json
, true, true);
3154 // use a JSON object with one key-value pair for each alternative
3155 // the schema is the same as a record's with one field
3156 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3158 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3159 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
3161 json
.put_next_token(JSON_TOKEN_NAME
, "properties");
3162 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3164 // use the alternative's alias if it has one
3165 json
.put_next_token(JSON_TOKEN_NAME
,
3166 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3167 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3169 // let the alternative's type insert its schema
3170 field
->generate_json_schema(json
, true, false);
3172 // continue the schema for the record with one field
3173 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3175 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3176 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
3178 // the one field is non-optional
3179 json
.put_next_token(JSON_TOKEN_NAME
, "required");
3180 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3182 // use the alternative's alias here as well
3183 char* field_str
= mprintf("\"%s\"",
3184 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3185 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3186 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3189 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3191 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3195 // close the "anyOf" array
3196 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3199 void Type::generate_json_schema_ref(JSON_Tokenizer
& json
)
3201 // start the object containing the reference
3202 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3204 // insert the reference
3205 json
.put_next_token(JSON_TOKEN_NAME
, "$ref");
3206 char* ref_str
= mprintf("\"#/definitions/%s/%s\"",
3207 my_scope
->get_scope_mod()->get_modid().get_ttcnname().c_str(),
3208 get_dispname().c_str());
3209 json
.put_next_token(JSON_TOKEN_STRING
, ref_str
);
3212 // the object will be closed later, as it may contain other properties
3216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3218 } // namespace Common