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;
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 decimal
= xerattrib
->decimal_
;
511 embed
= xerattrib
->embedValues_
;
512 form_qualified
= (xerattrib
->form_
& XerAttributes::QUALIFIED
)
513 || (xerattrib
->element_
); // a global element is always qualified
514 list
= xerattrib
->list_
;
515 untagged
= xerattrib
->untagged_
;
516 ws
= xerattrib
->whitespace_
;
517 // only set TEXT if it has no TextToBeUsed (plain "text" for a bool)
518 text
= xerattrib
->num_text_
&& xerattrib
->text_
->prefix
== 0;
519 use_nil
= xerattrib
->useNil_
;
520 use_number
= xerattrib
->useNumber_
;
521 use_order
= xerattrib
->useOrder_
;
522 use_qname
= xerattrib
->useQName_
;
523 // In ASN.1, the use of a type identification attribute is optional
524 // (encoder's choice) for USE-UNION. However, TTCN-3 removes this choice:
525 // it is mandatory to use it when possible (valid choice for ASN.1 too).
526 use_type_attr
= xerattrib
->useType_
|| xerattrib
->useUnion_
;
528 if (xerattrib
->defaultValue_
) {
529 Type
*t
= xerattrib
->defaultValue_
->get_my_governor();
530 dfe_str
= xerattrib
->defaultValue_
->get_genname_own().c_str();
532 Code::init_cdef(&cdef
);
533 t
->generate_code_object(&cdef
, xerattrib
->defaultValue_
);
534 cdef
.init
= xerattrib
->defaultValue_
->generate_code_init
535 (cdef
.init
, xerattrib
->defaultValue_
->get_lhs_name().c_str());
536 Code::merge_cdef(target
, &cdef
);
537 Code::free_cdef(&cdef
);
541 // data needed for "anyElement from ..." and "anyElement except ..." encoding instructions
542 any_from
= xerattrib
->anyElement_
.type_
== NamespaceRestriction::FROM
;
543 any_except
= xerattrib
->anyElement_
.type_
== NamespaceRestriction::EXCEPT
;
544 nof_ns_uris
= xerattrib
->anyElement_
.nElements_
;
545 ns_uris
= xerattrib
->anyElement_
.uris_
;
548 // data needed for "anyAttributes from ..." and "anyAttributes except ..." encoding instructions
549 any_from
= xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::FROM
;
550 any_except
= xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::EXCEPT
;
551 nof_ns_uris
= xerattrib
->anyAttributes_
.nElements_
;
552 ns_uris
= xerattrib
->anyAttributes_
.uris_
;
555 else if (ownertype
== OT_COMP_FIELD
556 && parent_type
&& parent_type
->xerattrib
) {
557 //no xerattrib, this must be an element; apply element default
558 form_qualified
= (parent_type
->xerattrib
->form_
559 & XerAttributes::ELEMENT_DEFAULT_QUALIFIED
);
562 Type
*last
= get_type_refd_last();
563 has_1untag
= last
->is_secho() && last
->u
.secho
.has_single_charenc
; // does not come from xerattrib
565 /* If this is a string type whose grandparent is a record
566 * (containing a record-of (this)string) which has EMBED-VALUES,
567 * then reuse this string's any_element field in the XER descriptor
568 * to signal this (ANY-ELEMENT causes the tag to be omitted,
569 * which is what we want in EMBED-VALUES) */
570 if (parent_type
&& parent_type
->parent_type
) switch (last
->typetype
) {
572 case T_USTR
: // the TTCN equivalent of UTF8String
573 if ( T_SEQOF
== parent_type
->typetype
574 && (T_SEQ_T
== parent_type
->parent_type
->typetype
575 ||T_SEQ_A
== parent_type
->parent_type
->typetype
)
576 && parent_type
->parent_type
->xerattrib
) {
577 embed
|= (parent_type
->parent_type
->xerattrib
->embedValues_
);
583 size_t last_len
= 2 + last_s
.size(); // 2 for > \n
584 size_t bxer_len
= 2 + bxer_name
.size(); // 2 for > \n
586 if ((T_SEQOF
== last
->typetype
|| T_SETOF
== last
->typetype
) &&
587 T_ANYTYPE
!= last
->u
.seof
.ofType
->get_type_refd_last()->typetype
) {
588 // anytypes don't have XER descriptors
589 oftype_descr_name
= mprintf("&%s_xer_", last
->u
.seof
.ofType
->get_genname_typedescriptor(my_scope
).c_str());
592 // Generate a separate variable for the namespace URIs, if there are any
593 char* ns_uris_var
= 0;
594 if (ns_uris
&& nof_ns_uris
) {
595 ns_uris_var
= mputprintf(ns_uris_var
, "%s_ns_uris_", gennameown_str
);
596 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
597 "const char* %s[] = {", ns_uris_var
);
598 for (int idx
= 0; idx
< nof_ns_uris
; ++idx
) {
599 // The unqualified namespace is sometimes stored as an empty string and
600 // sometimes as a null pointer -> unify it, always store it as an empty string
601 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
602 "%s\"%s\"", (idx
!= 0) ? ", " : "", ns_uris
[idx
] ? ns_uris
[idx
] : "");
604 target
->source
.global_vars
= mputstrn(target
->source
.global_vars
, "};\n", 3);
607 // Generate the XER descriptor itself
608 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
609 "const XERdescriptor_t %s_xer_ = { {\"%s>\\n\", \"%s>\\n\"},"
610 " {%lu, %lu}, %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s, WHITESPACE_%s, %c%s, "
611 "&%s, %ld, %u, %s, %s };\n",
613 bxer_name
.c_str(), last_s
.c_str(), // names
614 (unsigned long)bxer_len
, (unsigned long)last_len
, // lengths
615 (any_atr
? "ANY_ATTRIBUTES" : "0"),
616 (any_elem
? " |ANY_ELEMENT" : ""),
617 (atrib
? " |XER_ATTRIBUTE" : ""),
618 (base64
? " |BASE_64" : ""),
619 (decimal
? " |XER_DECIMAL" : ""),
620 (embed
? " |EMBED_VALUES" : ""),
621 (list
? " |XER_LIST" : ""),
622 (text
? " |XER_TEXT" : ""),
623 (untagged
? " |UNTAGGED" : ""),
624 (use_nil
? " |USE_NIL" : ""),
625 (use_number
? " |USE_NUMBER" : ""),
626 (use_order
? " |USE_ORDER" : ""),
627 (use_qname
? " |USE_QNAME" : ""),
628 (use_type_attr
? " |USE_TYPE_ATTR" : ""),
629 (has_1untag
? " |HAS_1UNTAGGED" : ""),
630 (form_qualified
? "" : " |FORM_UNQUALIFIED"),
631 (any_from
? " |ANY_FROM" : ""),
632 (any_except
? " |ANY_EXCEPT" : ""),
633 whitespace_action
[ws
],
634 (dfe_str
? '&' : ' '), (dfe_str
? dfe_str
: "NULL"),
638 (ns_uris_var
? ns_uris_var
: "NULL"),
639 (oftype_descr_name
? oftype_descr_name
: "NULL")
643 Free(oftype_descr_name
);
646 void Type::generate_code_rawdescriptor(output_struct
*target
)
648 const char *gennameown_str
= get_genname_own().c_str();
649 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
650 "extern const TTCN_RAWdescriptor_t %s_raw_;\n", gennameown_str
);
651 char *str
= mprintf("const TTCN_RAWdescriptor_t %s_raw_ = {",
653 if (rawattrib
->intx
) {
654 str
= mputstr(str
, "RAW_INTX,");
657 str
= mputprintf(str
, "%d,", rawattrib
->fieldlength
);
659 if (rawattrib
->comp
== XDEFCOMPL
) str
= mputstr(str
, "SG_2COMPL,");
660 else if (rawattrib
->comp
== XDEFSIGNBIT
) str
= mputstr(str
, "SG_SG_BIT,");
661 else str
= mputstr(str
, "SG_NO,");
662 if (rawattrib
->byteorder
== XDEFLAST
) str
= mputstr(str
, "ORDER_MSB,");
663 else str
= mputstr(str
, "ORDER_LSB,");
664 if (rawattrib
->align
== XDEFLEFT
) str
= mputstr(str
, "ORDER_MSB,");
665 else str
= mputstr(str
, "ORDER_LSB,");
666 if (rawattrib
->bitorderinfield
== XDEFMSB
)
667 str
= mputstr(str
, "ORDER_MSB,");
668 else str
= mputstr(str
, "ORDER_LSB,");
669 if (rawattrib
->bitorderinoctet
== XDEFMSB
)
670 str
= mputstr(str
, "ORDER_MSB,");
671 else str
= mputstr(str
, "ORDER_LSB,");
672 if (rawattrib
->extension_bit
== XDEFYES
)
673 str
= mputstr(str
, "EXT_BIT_YES,");
674 else if (rawattrib
->extension_bit
== XDEFREVERSE
)
675 str
= mputstr(str
, "EXT_BIT_REVERSE,");
676 else str
= mputstr(str
, "EXT_BIT_NO,");
677 if (rawattrib
->hexorder
== XDEFHIGH
) str
= mputstr(str
, "ORDER_MSB,");
678 else str
= mputstr(str
, "ORDER_LSB,");
679 if (rawattrib
->fieldorder
== XDEFMSB
) str
= mputstr(str
, "ORDER_MSB,");
680 else str
= mputstr(str
, "ORDER_LSB,");
681 if (rawattrib
->topleveleind
) {
682 if (rawattrib
->toplevel
.bitorder
==XDEFLSB
)
683 str
= mputstr(str
, "TOP_BIT_LEFT,");
684 else str
= mputstr(str
, "TOP_BIT_RIGHT,");
685 } else str
= mputstr(str
, "TOP_BIT_INHERITED,");
686 str
= mputprintf(str
, "%d,", rawattrib
->padding
);
687 str
= mputprintf(str
, "%d,", rawattrib
->prepadding
);
688 str
= mputprintf(str
, "%d,", rawattrib
->ptroffset
);
689 str
= mputprintf(str
, "%d,", rawattrib
->unit
);
690 str
= mputprintf(str
, "%d,", rawattrib
->padding_pattern_length
);
691 if (rawattrib
->padding_pattern_length
> 0)
692 str
= mputprintf(str
, "%s,", my_scope
->get_scope_mod_gen()
693 ->add_padding_pattern(string(rawattrib
->padding_pattern
)).c_str());
694 else str
= mputstr(str
, "NULL,");
695 str
= mputprintf(str
, "%d};\n", rawattrib
->length_restrition
);
696 target
->source
.global_vars
= mputstr(target
->source
.global_vars
, str
);
700 void Type::generate_code_textdescriptor(output_struct
*target
)
702 const char *gennameown_str
= get_genname_own().c_str();
703 char *union_member_name
=NULL
;
704 Common::Module
*mymod
=my_scope
->get_scope_mod();
705 Type
*t
= get_type_refd_last();
706 switch (t
->typetype
) {
708 if (textattrib
->true_params
|| textattrib
->false_params
) {
709 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
710 "static const TTCN_TEXTdescriptor_bool %s_bool_ = {", gennameown_str
);
711 if (textattrib
->true_params
&&
712 textattrib
->true_params
->encode_token
) {
713 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
714 "&%s,", mymod
->add_charstring_literal(
715 string(textattrib
->true_params
->encode_token
)).c_str());
717 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
720 if (textattrib
->true_params
&&
721 textattrib
->true_params
->decode_token
) {
722 char *pstr
= make_posix_str_code(
723 textattrib
->true_params
->decode_token
,
724 textattrib
->true_params
->case_sensitive
);
725 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
726 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
728 } else if (textattrib
->true_params
&&
729 !textattrib
->true_params
->case_sensitive
) {
730 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
731 "&%s,", mymod
->add_matching_literal(
732 string("N^(true).*$")).c_str());
734 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
737 if (textattrib
->false_params
&&
738 textattrib
->false_params
->encode_token
) {
739 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
740 "&%s,",mymod
->add_charstring_literal(
741 string(textattrib
->false_params
->encode_token
)).c_str());
743 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
746 if (textattrib
->false_params
&&
747 textattrib
->false_params
->decode_token
) {
748 char *pstr
= make_posix_str_code(
749 textattrib
->false_params
->decode_token
,
750 textattrib
->false_params
->case_sensitive
);
751 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
752 "&%s};\n", mymod
->add_matching_literal(string(pstr
)).c_str());
754 } else if (textattrib
->false_params
&&
755 !textattrib
->false_params
->case_sensitive
) {
756 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
757 "&%s};\n", mymod
->add_matching_literal(
758 string("N^(false).*$")).c_str());
760 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
763 union_member_name
= mprintf("(TTCN_TEXTdescriptor_param_values*)"
764 "&%s_bool_", gennameown_str
);
768 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
769 "static const TTCN_TEXTdescriptor_enum %s_enum_[] = { ",
771 for (size_t i
= 0; i
< t
->u
.enums
.eis
->get_nof_eis(); i
++) {
772 if (i
> 0) target
->source
.global_vars
=
773 mputstr(target
->source
.global_vars
, ", ");
774 target
->source
.global_vars
=
775 mputstr(target
->source
.global_vars
, "{ ");
776 if (textattrib
->field_params
&& textattrib
->field_params
[i
] &&
777 textattrib
->field_params
[i
]->value
.encode_token
) {
778 // the encode token is present
779 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
780 "&%s, ", mymod
->add_charstring_literal(
781 string(textattrib
->field_params
[i
]->value
.encode_token
)).c_str());
783 // the encode token is not present: generate a NULL pointer and the
784 // RTE will substitute the enumerated value
785 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
788 // a pattern must be always present for decoding
789 const char *decode_token
;
791 if (textattrib
->field_params
&& textattrib
->field_params
[i
]) {
792 if (textattrib
->field_params
[i
]->value
.decode_token
) {
793 // the decode token is present
794 decode_token
= textattrib
->field_params
[i
]->value
.decode_token
;
796 // there is an attribute for the enumerated value,
797 // but the decode token is omitted
798 // use the value as decode token
799 decode_token
= t
->u
.enums
.eis
->get_ei_byIndex(i
)->get_name()
800 .get_dispname().c_str();
802 // take the case sensitivity from the attribute
803 case_sensitive
= textattrib
->field_params
[i
]->value
.case_sensitive
;
805 // there is no attribute for the enumerated value
806 // use the value as decode token
807 decode_token
= t
->u
.enums
.eis
->get_ei_byIndex(i
)->get_name()
808 .get_dispname().c_str();
809 // it is always case sensitive
810 case_sensitive
= true;
812 char *pstr
= make_posix_str_code(decode_token
, case_sensitive
);
813 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
814 " &%s }", mymod
->add_matching_literal(string(pstr
)).c_str());
817 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
819 union_member_name
= mprintf(
820 "(TTCN_TEXTdescriptor_param_values*)%s_enum_", gennameown_str
);
824 if(textattrib
->coding_params
.leading_zero
||
825 textattrib
->coding_params
.min_length
!=-1 ||
826 textattrib
->coding_params
.max_length
!=-1 ||
827 textattrib
->coding_params
.convert
!=0 ||
828 textattrib
->coding_params
.just
!=1 ||
829 textattrib
->decoding_params
.leading_zero
||
830 textattrib
->decoding_params
.min_length
!=-1 ||
831 textattrib
->decoding_params
.max_length
!=-1 ||
832 textattrib
->decoding_params
.convert
!=0 ||
833 textattrib
->decoding_params
.just
!=1 ){
834 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
835 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
837 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
838 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
839 ,textattrib
->coding_params
.leading_zero
?"true":"false"
840 ,textattrib
->coding_params
.repeatable
?"true":"false"
841 ,textattrib
->coding_params
.min_length
842 ,textattrib
->coding_params
.max_length
843 ,textattrib
->coding_params
.convert
844 ,textattrib
->coding_params
.just
845 ,textattrib
->decoding_params
.leading_zero
?"true":"false"
846 ,textattrib
->decoding_params
.repeatable
?"true":"false"
847 ,textattrib
->decoding_params
.min_length
848 ,textattrib
->decoding_params
.max_length
849 ,textattrib
->decoding_params
.convert
850 ,textattrib
->decoding_params
.just
);
852 union_member_name
=mprintf("&%s_par_", gennameown_str
);
857 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
858 "static const TTCN_TEXTdescriptor_param_values %s_par_ = {",
860 target
->source
.global_vars
=mputprintf(target
->source
.global_vars
,
861 "{%s,%s,%i,%i,%i,%i},{%s,%s,%i,%i,%i,%i}};\n"
862 ,textattrib
->coding_params
.leading_zero
?"true":"false"
863 ,textattrib
->coding_params
.repeatable
?"true":"false"
864 ,textattrib
->coding_params
.min_length
865 ,textattrib
->coding_params
.max_length
866 ,textattrib
->coding_params
.convert
867 ,textattrib
->coding_params
.just
868 ,textattrib
->decoding_params
.leading_zero
?"true":"false"
869 ,textattrib
->decoding_params
.repeatable
?"true":"false"
870 ,textattrib
->decoding_params
.min_length
871 ,textattrib
->decoding_params
.max_length
872 ,textattrib
->decoding_params
.convert
873 ,textattrib
->decoding_params
.just
);
875 union_member_name
=mprintf("&%s_par_", gennameown_str
);
881 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
882 "extern const TTCN_TEXTdescriptor_t %s_text_;\n", gennameown_str
);
883 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
884 "const TTCN_TEXTdescriptor_t %s_text_ = {", gennameown_str
);
886 if (textattrib
->begin_val
&& textattrib
->begin_val
->encode_token
) {
887 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
888 "&%s,", mymod
->add_charstring_literal(
889 string(textattrib
->begin_val
->encode_token
)).c_str());
891 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
894 if(textattrib
->begin_val
&& textattrib
->begin_val
->decode_token
){
895 char *pstr
= make_posix_str_code(
896 textattrib
->begin_val
->decode_token
,
897 textattrib
->begin_val
->case_sensitive
);
898 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
899 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
902 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
905 if (textattrib
->end_val
&& textattrib
->end_val
->encode_token
) {
906 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
907 "&%s,",mymod
->add_charstring_literal(
908 string(textattrib
->end_val
->encode_token
)).c_str());
910 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
913 if (textattrib
->end_val
&& textattrib
->end_val
->decode_token
) {
914 char *pstr
= make_posix_str_code(
915 textattrib
->end_val
->decode_token
,
916 textattrib
->end_val
->case_sensitive
);
917 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
918 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
921 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
925 if (textattrib
->separator_val
&&
926 textattrib
->separator_val
->encode_token
) {
927 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
928 "&%s,", mymod
->add_charstring_literal(
929 string(textattrib
->separator_val
->encode_token
)).c_str());
931 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
934 if(textattrib
->separator_val
&&
935 textattrib
->separator_val
->decode_token
) {
936 char *pstr
= make_posix_str_code(
937 textattrib
->separator_val
->decode_token
,
938 textattrib
->separator_val
->case_sensitive
);
939 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
940 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
943 target
->source
.global_vars
=mputstr(target
->source
.global_vars
,
947 if (textattrib
->decode_token
) {
948 char *pstr
= make_posix_str_code(textattrib
->decode_token
,
949 textattrib
->case_sensitive
);
950 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
951 "&%s,", mymod
->add_matching_literal(string(pstr
)).c_str());
954 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
958 if (union_member_name
) {
959 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
960 "{%s}};\n", union_member_name
);
961 Free(union_member_name
);
963 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
968 void Type::generate_code_jsondescriptor(output_struct
*target
)
970 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
971 "extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str());
973 if (NULL
== jsonattrib
) {
974 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
975 "const TTCN_JSONdescriptor_t %s_json_ = { false, NULL, false, NULL, false };\n"
976 , get_genname_own().c_str());
978 char* alias
= jsonattrib
->alias
? mputprintf(NULL
, "\"%s\"", jsonattrib
->alias
) : NULL
;
979 char* def_val
= jsonattrib
->default_value
?
980 mputprintf(NULL
, "\"%s\"", jsonattrib
->default_value
) : NULL
;
981 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
982 "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s };\n"
983 , get_genname_own().c_str()
984 , jsonattrib
->omit_as_null
? "true" : "false"
985 , alias
? alias
: "NULL"
986 , jsonattrib
->as_value
? "true" : "false"
987 , def_val
? def_val
: "NULL"
988 , jsonattrib
->metainfo_unbound
? "true" : "false");
995 void Type::generate_code_alias(output_struct
*target
)
997 if (!needs_alias()) return;
999 const string
& t_genname
= get_genname_value(my_scope
);
1000 const char *refd_name
= t_genname
.c_str();
1001 const char *own_name
= get_genname_own().c_str();
1003 Type
*t_last
= get_type_refd_last();
1004 switch (t_last
->typetype
) {
1005 case T_PORT
: // only value class exists
1006 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1007 "typedef %s %s;\n", refd_name
, own_name
);
1009 case T_SIGNATURE
: // special classes (7 pcs.) exist
1010 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1011 "typedef %s_call %s_call;\n"
1012 "typedef %s_call_redirect %s_call_redirect;\n",
1013 refd_name
, own_name
, refd_name
, own_name
);
1014 if (!t_last
->is_nonblocking_signature()) {
1015 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1016 "typedef %s_reply %s_reply;\n"
1017 "typedef %s_reply_redirect %s_reply_redirect;\n",
1018 refd_name
, own_name
, refd_name
, own_name
);
1020 if (t_last
->get_signature_exceptions()) {
1021 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1022 "typedef %s_exception %s_exception;\n"
1023 "typedef %s_exception_template %s_exception_template;\n",
1024 refd_name
, own_name
, refd_name
, own_name
);
1026 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1027 "typedef %s_template %s_template;\n",
1028 refd_name
, own_name
);
1030 default: // value and template classes exist
1031 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
1033 "// written by %s in " __FILE__
" at %d\n"
1036 "typedef %s_template %s_template;\n",
1038 __FUNCTION__
, __LINE__
,
1040 refd_name
, own_name
, refd_name
, own_name
);
1045 void Type::generate_code_Enum(output_struct
*target
)
1049 memset(&e_def
, 0, sizeof(e_def
));
1050 e_def
.name
= get_genname_own().c_str();
1051 e_def
.dispname
= get_fullname().c_str();
1052 e_def
.isASN1
= is_asn1();
1053 e_def
.nElements
= u
.enums
.eis
->get_nof_eis();
1054 e_def
.elements
= (enum_field
*)
1055 Malloc(e_def
.nElements
*sizeof(*e_def
.elements
));
1056 e_def
.firstUnused
= u
.enums
.first_unused
;
1057 e_def
.secondUnused
= u
.enums
.second_unused
;
1058 e_def
.hasText
= textattrib
!=NULL
;
1059 e_def
.hasRaw
= rawattrib
!=NULL
;
1060 e_def
.hasXer
= has_encoding(CT_XER
);
1061 e_def
.hasJson
= has_encoding(CT_JSON
);
1063 e_def
.xerUseNumber
= xerattrib
->useNumber_
;
1065 for (size_t i
= 0; i
< e_def
.nElements
; i
++) {
1066 EnumItem
*ei
= u
.enums
.eis
->get_ei_byIndex(i
);
1067 e_def
.elements
[i
].name
= ei
->get_name().get_name().c_str();
1068 e_def
.elements
[i
].dispname
= ei
->get_name().get_ttcnname().c_str();
1069 if (ei
->get_text().empty()) e_def
.elements
[i
].text
= 0;
1071 e_def
.xerText
= TRUE
;
1072 e_def
.elements
[i
].text
= ei
->get_text().c_str();
1074 e_def
.elements
[i
].value
= ei
->get_value()->get_val_Int()->get_val();
1077 defEnumClass(&e_def
, target
);
1078 defEnumTemplate(&e_def
, target
);
1080 Free(e_def
.elements
);
1083 void Type::generate_code_Choice(output_struct
*target
)
1087 memset(&sdef
, 0, sizeof(sdef
));
1088 sdef
.name
= get_genname_own().c_str();
1089 sdef
.dispname
=get_fullname().c_str();
1090 if (T_ANYTYPE
==typetype
) {
1091 if (0 == get_nof_comps()) {
1092 //return; // don't generate code for empty anytype
1093 // XXX what to do with empty anytype ?
1094 // Easy: make sure it doesn't happen by filling it from the AST!
1096 sdef
.kind
= ANYTYPE
;
1098 else sdef
.kind
= UNION
;
1099 sdef
.isASN1
= is_asn1();
1100 sdef
.hasText
= textattrib
!=NULL
;
1101 sdef
.hasXer
= has_encoding(CT_XER
);
1102 sdef
.hasJson
= has_encoding(CT_JSON
);
1103 sdef
.has_opentypes
= get_has_opentypes();
1104 sdef
.opentype_outermost
= get_is_opentype_outermost();
1105 sdef
.ot
= generate_code_ot(pool
);
1106 sdef
.nElements
= get_nof_comps();
1107 sdef
.isOptional
= false;
1108 if (parent_type
!= NULL
) {
1109 switch (parent_type
->typetype
) {
1114 for (size_t x
= 0; x
< parent_type
->get_nof_comps(); ++x
) {
1115 CompField
* cf
= parent_type
->get_comp_byIndex(x
);
1116 if (cf
->get_type() == this && cf
->get_is_optional()) {
1117 sdef
.isOptional
= true;
1118 break; // from the for loop
1126 sdef
.elements
= (struct_field
*)
1127 Malloc(sdef
.nElements
*sizeof(*sdef
.elements
));
1128 memset(sdef
.elements
, 0, sdef
.nElements
*sizeof(*sdef
.elements
));
1129 sdef
.exerMaybeEmptyIndex
= -1;
1131 sdef
.jsonAsValue
= jsonattrib
->as_value
;
1133 for(size_t i
= 0; i
< sdef
.nElements
; i
++) {
1134 CompField
*cf
= get_comp_byIndex(i
);
1135 const Identifier
& id
= cf
->get_name();
1136 Type
*cftype
= cf
->get_type();
1137 sdef
.elements
[i
].type
= pool
.add(cftype
->get_genname_value(my_scope
));
1138 sdef
.elements
[i
].typedescrname
=
1139 pool
.add(cftype
->get_genname_typedescriptor(my_scope
));
1140 sdef
.elements
[i
].typegen
= pool
.add(cftype
->get_genname_xerdescriptor());
1141 sdef
.elements
[i
].name
= id
.get_name().c_str();
1142 sdef
.elements
[i
].dispname
= id
.get_ttcnname().c_str();
1144 if (cftype
->has_empty_xml()) sdef
.exerMaybeEmptyIndex
= i
;
1145 // This will overwrite lower values, which is what we want.
1147 if (sdef
.jsonAsValue
) {
1148 // Determine the JSON value type of each field to make decoding faster
1149 typetype_t tt
= cftype
->get_type_refd_last()->typetype
;
1153 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
;
1156 sdef
.elements
[i
].jsonValueType
= JSON_NUMBER
| JSON_STRING
;
1159 sdef
.elements
[i
].jsonValueType
= JSON_BOOLEAN
;
1162 sdef
.elements
[i
].jsonValueType
= JSON_NULL
;
1171 case T_NUMERICSTRING
:
1172 case T_PRINTABLESTRING
:
1173 case T_TELETEXSTRING
:
1174 case T_VIDEOTEXSTRING
:
1176 case T_GRAPHICSTRING
:
1177 case T_VISIBLESTRING
:
1178 case T_GENERALSTRING
:
1179 case T_UNIVERSALSTRING
:
1187 sdef
.elements
[i
].jsonValueType
= JSON_STRING
;
1197 sdef
.elements
[i
].jsonValueType
= JSON_OBJECT
;
1202 sdef
.elements
[i
].jsonValueType
= JSON_ARRAY
;
1205 FATAL_ERROR("Type::generate_code_Choice - invalid field type %d", tt
);
1208 if (cftype
->jsonattrib
) {
1209 sdef
.elements
[i
].jsonAlias
= cftype
->jsonattrib
->alias
;
1210 if (sdef
.jsonAsValue
&& cftype
->jsonattrib
->as_value
) {
1211 // Override the JSON_OBJECT value given in the switch
1212 sdef
.elements
[i
].jsonValueType
= JSON_ANY_VALUE
;
1217 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
1220 for(int c
=0;c
<rawattrib
->taglist
.nElements
;c
++){
1221 if(rawattrib
->taglist
.tag
[c
].nElements
)
1222 sdef
.raw
.taglist
.list
[c
].fields
=
1223 (rawAST_coding_field_list
*)
1224 Malloc(rawattrib
->taglist
.tag
[c
].nElements
1225 *sizeof(rawAST_coding_field_list
));
1226 else sdef
.raw
.taglist
.list
[c
].fields
=NULL
;
1227 sdef
.raw
.taglist
.list
[c
].nElements
=
1228 rawattrib
->taglist
.tag
[c
].nElements
;
1229 sdef
.raw
.taglist
.list
[c
].fieldName
=
1230 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1231 Identifier
*idf
=rawattrib
->taglist
.tag
[c
].fieldName
;
1232 sdef
.raw
.taglist
.list
[c
].fieldnum
=get_comp_index_byName(*idf
);
1233 for(int a
=0;a
<rawattrib
->taglist
.tag
[c
].nElements
;a
++){
1234 rawAST_coding_field_list
* key
=
1235 sdef
.raw
.taglist
.list
[c
].fields
+a
;
1237 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1238 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
1240 key
->fields
=(rawAST_coding_fields
*)
1241 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1242 CompField
*cf
=get_comp_byIndex(sdef
.raw
.taglist
.list
[c
].fieldnum
);
1243 Type
*t
=cf
->get_type()->get_type_refd_last();
1245 key
->fields
[0].nthfield
= sdef
.raw
.taglist
.list
[c
].fieldnum
;
1246 key
->fields
[0].nthfieldname
=
1247 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1248 key
->fields
[0].fieldtype
= UNION_FIELD
;
1249 key
->fields
[0].type
= pool
.add(t
->get_genname_value(my_scope
));
1250 key
->fields
[0].typedescr
=
1251 pool
.add(t
->get_genname_typedescriptor(my_scope
));
1253 for (int b
= 1; b
< key
->nElements
; b
++) {
1255 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->names
[b
-1];
1256 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1257 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1258 key
->fields
[b
].nthfield
= comp_index
;
1259 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1260 if (t
->typetype
== T_CHOICE_T
)
1261 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1262 else if (cf2
->get_is_optional()){
1263 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1264 }else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1265 Type
*field_type
= cf2
->get_type();
1266 key
->fields
[b
].type
=
1267 pool
.add(field_type
->get_genname_value(my_scope
));
1268 key
->fields
[b
].typedescr
=
1269 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1270 if (field_type
->typetype
== T_SEQ_T
&& field_type
->rawattrib
1271 && (field_type
->rawattrib
->pointerto
1272 || field_type
->rawattrib
->lengthto_num
))
1273 key
->start_pos
= -1;
1275 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1277 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1279 t2
= t
->get_comp_byIndex(i
)->get_type();
1280 if(t2
->get_raw_length() >= 0){
1282 key
->start_pos
+= t2
->rawattrib
->padding
;
1283 key
->start_pos
+= t2
->get_raw_length();
1284 }else key
->start_pos
= -1;
1287 t
= field_type
->get_type_refd_last();
1291 } else sdef
.hasRaw
=false;
1293 Module
*my_module
= get_my_scope()->get_scope_mod();
1294 sdef
.xerHasNamespaces
= my_module
->get_nof_ns() != 0;
1295 const char *ns
, *prefix
;
1296 my_module
->get_controlns(ns
, prefix
);
1297 sdef
.control_ns_prefix
= prefix
;
1298 sdef
.xerUseUnion
= xerattrib
->useUnion_
;
1299 sdef
.xerUseTypeAttr
= xerattrib
->useType_
|| xerattrib
->useUnion_
;
1301 defUnionClass(&sdef
, target
);
1302 defUnionTemplate(&sdef
, target
);
1304 free_code_ot(sdef
.ot
);
1307 free_raw_attrib_struct(&sdef
.raw
);
1309 Free(sdef
.elements
);
1312 Opentype_t
*Type::generate_code_ot(stringpool
& pool
)
1314 using namespace Asn
;
1315 if(typetype
!=T_OPENTYPE
)
1317 if(!u
.secho
.my_tableconstraint
1318 || !u
.secho
.my_tableconstraint
->get_ans()) {
1319 DEBUG(1, "Opentype ObjectClassFieldType without"
1320 " ComponentRelationConstraint: `%s'",
1321 get_fullname().c_str());
1324 const AtNotations
*ans
=u
.secho
.my_tableconstraint
->get_ans();
1325 Opentype_t
*ot
=(Opentype_t
*)Malloc(sizeof(*ot
));
1326 ot
->anl
.nElements
= ans
->get_nof_ans();
1327 ot
->anl
.elements
= (AtNotation_t
*)
1328 Malloc(ot
->anl
.nElements
* sizeof(*ot
->anl
.elements
));
1329 for(size_t i
=0; i
<ans
->get_nof_ans(); i
++) {
1330 AtNotation
*an
=ans
->get_an_byIndex(i
);
1331 AtNotation_t
*an_t
= ot
->anl
.elements
+ i
;
1332 an_t
->dispname
= pool
.add(an
->get_dispname());
1333 an_t
->parent_level
=an
->get_levels();
1334 an_t
->parent_typename
=
1335 pool
.add(an
->get_firstcomp()->get_genname_value(my_scope
));
1337 pool
.add(an
->get_lastcomp()->get_genname_value(my_scope
));
1338 an_t
->sourcecode
=memptystr();
1339 FieldName
* cids
=an
->get_cids();
1340 Type
*t_type
=an
->get_firstcomp();
1341 for(size_t j
=0; j
<cids
->get_nof_fields(); j
++) {
1343 t_type
->get_comp_byName(*cids
->get_field_byIndex(j
));
1344 if(j
) an_t
->sourcecode
=mputstr(an_t
->sourcecode
, ".");
1345 an_t
->sourcecode
=mputprintf
1346 (an_t
->sourcecode
, "%s()",
1347 cf
->get_name().get_name().c_str());
1348 if(cf
->get_is_optional())
1349 an_t
->sourcecode
=mputstr(an_t
->sourcecode
, "()");
1350 t_type
=cf
->get_type();
1353 const Identifier
*oc_fieldname_t
1354 =u
.secho
.my_tableconstraint
->get_oc_fieldname();
1356 =u
.secho
.my_tableconstraint
->get_os()->get_refd_last()->get_objs();
1357 ot
->oal
.nElements
= objs
->get_nof_objs();
1358 ot
->oal
.elements
= (OpentypeAlternative_t
*)
1359 Malloc(ot
->oal
.nElements
* sizeof(*ot
->oal
.elements
));
1360 size_t nElements_missing
=0;
1361 Value
**val_prev
=(Value
**)
1362 Malloc(ans
->get_nof_ans()*sizeof(*val_prev
));
1363 boolean differs_from_prev
=true;
1364 for(size_t i
=0; i
<objs
->get_nof_objs(); i
++) {
1365 Obj_defn
*obj
=objs
->get_obj_byIndex(i
);
1366 if(!obj
->has_fs_withName_dflt(*oc_fieldname_t
)) {
1367 nElements_missing
++;
1370 OpentypeAlternative_t
*oa_t
= ot
->oal
.elements
+ i
- nElements_missing
;
1371 Type
*t_type
=dynamic_cast<Type
*>
1372 (obj
->get_setting_byName_dflt(*oc_fieldname_t
));
1374 const Identifier
& altname
= t_type
->get_otaltname(is_strange
);
1375 oa_t
->alt
= pool
.add(altname
.get_name());
1376 oa_t
->alt_dispname
= pool
.add(altname
.get_asnname());
1377 oa_t
->alt_typename
= pool
.add(t_type
->get_genname_value(my_scope
));
1378 oa_t
->alt_typedescrname
=
1379 pool
.add(t_type
->get_genname_typedescriptor(my_scope
));
1380 oa_t
->valuenames
=(const char**)Malloc
1381 (ans
->get_nof_ans()*sizeof(*oa_t
->valuenames
));
1382 oa_t
->const_valuenames
=(const char**)Malloc
1383 (ans
->get_nof_ans()*sizeof(*oa_t
->const_valuenames
));
1384 for(size_t j
=0; j
<ans
->get_nof_ans(); j
++) {
1385 AtNotation
*an
=ans
->get_an_byIndex(j
);
1386 const Identifier
*oc_fieldname_v
=an
->get_oc_fieldname();
1387 Value
*t_value
=dynamic_cast<Value
*>
1388 (obj
->get_setting_byName_dflt(*oc_fieldname_v
));
1389 oa_t
->valuenames
[j
] = pool
.add(t_value
->get_genname_own(my_scope
));
1390 if(!differs_from_prev
&& *val_prev
[j
]==*t_value
)
1391 oa_t
->const_valuenames
[j
]=0;
1393 oa_t
->const_valuenames
[j
] =
1394 pool
.add(t_value
->get_genname_own(my_scope
));
1395 differs_from_prev
=true;
1397 val_prev
[j
]=t_value
;
1399 differs_from_prev
=false;
1402 ot
->oal
.nElements
-= nElements_missing
;
1403 ot
->oal
.elements
= (OpentypeAlternative_t
*)
1404 Realloc(ot
->oal
.elements
,
1405 ot
->oal
.nElements
* sizeof(*ot
->oal
.elements
));
1409 void Type::free_code_ot(Opentype_t
* p_ot
)
1412 for (size_t i
= 0; i
< p_ot
->oal
.nElements
; i
++) {
1413 Free(p_ot
->oal
.elements
[i
].valuenames
);
1414 Free(p_ot
->oal
.elements
[i
].const_valuenames
);
1416 Free(p_ot
->oal
.elements
);
1417 for (size_t i
= 0; i
< p_ot
->anl
.nElements
; i
++)
1418 Free(p_ot
->anl
.elements
[i
].sourcecode
);
1419 Free(p_ot
->anl
.elements
);
1423 size_t Type::get_codegen_index(size_t index
)
1425 // This sorting is because of CER coding of SET types, see X.690 9.3.
1426 // see: Type::generate_code_Se()
1427 // TODO: maybe result should be cached into this type
1428 // ( inside u.secho as dynamic_array<size_t>* codegen_indexes ? )
1429 if (typetype
==T_SET_A
) {
1430 size_t nof_comps
= get_nof_comps();
1431 map
<Tag
, void> se_index_map
;
1432 for (size_t i
=0; i
<nof_comps
; i
++) {
1433 Tag
*tag
= get_comp_byIndex(i
)->get_type()->get_smallest_tag();
1434 se_index_map
.add(*tag
, (void*)i
); // hack: store size_t in void* to avoid Malloc()
1437 for(size_t i
=0; i
<nof_comps
; i
++) {
1438 if (se_index_map
.get_nth_elem(i
)==(void*)index
) {
1439 se_index_map
.clear();
1443 FATAL_ERROR("Type::get_codegen_index()");
1448 void Type::generate_code_Se(output_struct
*target
)
1452 Type
* last_field_type
= 0;
1453 memset(&sdef
, 0, sizeof(sdef
));
1454 sdef
.name
= get_genname_own().c_str();
1455 sdef
.dispname
= get_fullname().c_str();
1456 //printf("generate_code_Se(%s)\n", sdef.dispname);
1475 FATAL_ERROR("Type::generate_code_Se()");
1477 sdef
.hasText
= textattrib
!=NULL
;
1478 sdef
.nElements
= sdef
.totalElements
= get_nof_comps();
1479 sdef
.has_opentypes
= get_has_opentypes();
1480 sdef
.opentype_outermost
= get_is_opentype_outermost();
1482 sdef
.hasXer
= has_encoding(CT_XER
);
1483 sdef
.hasJson
= has_encoding(CT_JSON
);
1485 Module
*my_module
= get_my_scope()->get_scope_mod();
1486 sdef
.xerHasNamespaces
= my_module
->get_nof_ns() != 0;
1487 const char *ns
, *prefix
;
1488 my_module
->get_controlns(ns
, prefix
);
1489 sdef
.control_ns_prefix
= prefix
;
1490 sdef
.xerUntagged
= xerattrib
->untagged_
;
1491 sdef
.xerUntaggedOne
= u
.secho
.has_single_charenc
;
1492 sdef
.xerUseNilPossible
= use_nil_possible
;
1493 sdef
.xerEmbedValuesPossible
= embed_values_possible
;
1494 sdef
.xerUseOrderPossible
= use_order_possible
;
1495 if (xerattrib
->useOrder_
&& xerattrib
->useNil_
) {
1496 // We need information about the fields of the USE-NIL component
1497 const CompField
*cf
= get_comp_byIndex(sdef
.totalElements
-1);
1498 last_field_type
= cf
->get_type()->get_type_refd_last();
1499 sdef
.totalElements
+= last_field_type
->get_nof_comps();
1501 sdef
.xerUseQName
= xerattrib
->useQName_
;
1502 if (xerattrib
->useType_
|| xerattrib
->useUnion_
) {
1503 FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record
1506 sdef
.elements
= (struct_field
*)
1507 Malloc(sdef
.totalElements
*sizeof(*sdef
.elements
));
1508 memset(sdef
.elements
, 0, sdef
.totalElements
* sizeof(*sdef
.elements
));
1510 /* This sorting is because of CER coding of SET types, see X.690
1512 vector
<CompField
> se_comps
;
1513 if(typetype
==T_SET_A
) {
1514 map
<Tag
, CompField
> se_comps_map
;
1515 for(size_t i
=0; i
<sdef
.nElements
; i
++) {
1516 CompField
* cf
=get_comp_byIndex(i
);
1517 Tag
*tag
= cf
->get_type()->get_smallest_tag();
1518 se_comps_map
.add(*tag
, cf
);
1521 for(size_t i
=0; i
<sdef
.nElements
; i
++)
1522 se_comps
.add(se_comps_map
.get_nth_elem(i
));
1523 se_comps_map
.clear();
1526 for(size_t i
=0; i
<sdef
.nElements
; i
++)
1527 se_comps
.add(get_comp_byIndex(i
));
1530 for(size_t i
= 0; i
< sdef
.nElements
; i
++) {
1531 struct_field
&cur
= sdef
.elements
[i
];
1532 CompField
*cf
= se_comps
[i
];
1533 const Identifier
& id
= cf
->get_name();
1534 Type
*type
= cf
->get_type();
1535 cur
.type
= pool
.add(type
->get_genname_value(my_scope
));
1536 cur
.typegen
= pool
.add(type
->get_genname_own());
1537 cur
.of_type
= type
->get_type_refd_last()->is_seof();
1539 pool
.add(type
->get_genname_typedescriptor(my_scope
));
1540 cur
.name
= id
.get_name().c_str();
1541 cur
.dispname
= id
.get_ttcnname().c_str();
1542 cur
.isOptional
= cf
->get_is_optional();
1543 cur
.isDefault
= cf
->has_default();
1544 cur
.optimizedMemAlloc
= cur
.of_type
&& (type
->get_optimize_attribute() == "memalloc");
1545 if (cur
.isDefault
) {
1546 Value
*defval
= cf
->get_defval();
1548 Code::init_cdef(&cdef
);
1549 type
->generate_code_object(&cdef
, defval
);
1550 cdef
.init
= defval
->generate_code_init
1551 (cdef
.init
, defval
->get_lhs_name().c_str());
1552 Code::merge_cdef(target
, &cdef
);
1553 Code::free_cdef(&cdef
);
1554 cur
.defvalname
= defval
->get_genname_own().c_str();
1557 if (type
->xerattrib
) {
1558 cur
.xerAttribute
= type
->xerattrib
->attribute_
;
1560 if (has_aa(type
->xerattrib
)) {
1561 cur
.xerAnyNum
= type
->xerattrib
->anyAttributes_
.nElements_
;
1562 cur
.xerAnyKind
= ANY_ATTRIB_BIT
|
1563 (type
->xerattrib
->anyAttributes_
.type_
== NamespaceRestriction::FROM
?
1564 ANY_FROM_BIT
: ANY_EXCEPT_BIT
);
1565 if (cur
.xerAnyNum
> 0)
1566 cur
.xerAnyUris
= (char**)Malloc(cur
.xerAnyNum
* sizeof(char*));
1567 for (size_t uu
=0; uu
<cur
.xerAnyNum
; ++uu
)
1568 cur
.xerAnyUris
[uu
] = type
->xerattrib
->anyAttributes_
.uris_
[uu
];
1570 else if(has_ae(type
->xerattrib
)) {
1571 cur
.xerAnyNum
= type
->xerattrib
->anyElement_
.nElements_
;
1572 cur
.xerAnyKind
= ANY_ELEM_BIT
|
1573 (type
->xerattrib
->anyElement_
.type_
== NamespaceRestriction::FROM
?
1574 ANY_FROM_BIT
: ANY_EXCEPT_BIT
);
1575 if (cur
.xerAnyNum
> 0)
1576 cur
.xerAnyUris
= (char**)Malloc(cur
.xerAnyNum
* sizeof(char*));
1577 for (size_t uu
=0; uu
<cur
.xerAnyNum
; ++uu
)
1578 cur
.xerAnyUris
[uu
] = type
->xerattrib
->anyElement_
.uris_
[uu
];
1581 if (type
->jsonattrib
) {
1582 cur
.jsonOmitAsNull
= type
->jsonattrib
->omit_as_null
;
1583 cur
.jsonAlias
= type
->jsonattrib
->alias
;
1584 cur
.jsonDefaultValue
= type
->jsonattrib
->default_value
;
1585 cur
.jsonMetainfoUnbound
= type
->jsonattrib
->metainfo_unbound
;
1589 if (last_field_type
)
1590 for (size_t i
= sdef
.nElements
; i
< sdef
.totalElements
; i
++) {
1591 struct_field
&cur
= sdef
.elements
[i
];
1592 CompField
*cf
= last_field_type
->get_comp_byIndex(i
- sdef
.nElements
);
1593 const Identifier
& id
= cf
->get_name();
1594 Type
*type
= cf
->get_type();
1595 cur
.type
= pool
.add(type
->get_genname_value(my_scope
));
1596 cur
.typegen
= pool
.add(type
->get_genname_own());
1597 cur
.of_type
= type
->get_type_refd_last()->is_seof();
1599 pool
.add(type
->get_genname_typedescriptor(my_scope
));
1600 cur
.name
= id
.get_name().c_str();
1601 cur
.dispname
= id
.get_ttcnname().c_str();
1602 cur
.isOptional
= cf
->get_is_optional();
1607 copy_rawAST_to_struct(rawattrib
,&(sdef
.raw
));
1610 for(int c
=0;c
<rawattrib
->taglist
.nElements
;c
++) {
1611 if(rawattrib
->taglist
.tag
[c
].nElements
)
1612 sdef
.raw
.taglist
.list
[c
].fields
=
1613 (rawAST_coding_field_list
*)
1614 Malloc(rawattrib
->taglist
.tag
[c
].nElements
1615 *sizeof(rawAST_coding_field_list
));
1616 else sdef
.raw
.taglist
.list
[c
].fields
=NULL
;
1617 sdef
.raw
.taglist
.list
[c
].nElements
=
1618 rawattrib
->taglist
.tag
[c
].nElements
;
1619 sdef
.raw
.taglist
.list
[c
].fieldName
=
1620 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1621 Identifier
*idf
=rawattrib
->taglist
.tag
[c
].fieldName
;
1622 sdef
.raw
.taglist
.list
[c
].fieldnum
=get_comp_index_byName(*idf
);
1623 for(int a
=0;a
<rawattrib
->taglist
.tag
[c
].nElements
;a
++){
1624 rawAST_coding_field_list
* key
=
1625 sdef
.raw
.taglist
.list
[c
].fields
+a
;
1627 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->nElements
+1;
1628 key
->value
=rawattrib
->taglist
.tag
[c
].keyList
[a
].value
;
1630 key
->fields
=(rawAST_coding_fields
*)
1631 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1633 CompField
*cf
=get_comp_byIndex(sdef
.raw
.taglist
.list
[c
].fieldnum
);
1634 Type
*t
=cf
->get_type()->get_type_refd_last();
1636 key
->fields
[0].nthfield
= sdef
.raw
.taglist
.list
[c
].fieldnum
;
1637 key
->fields
[0].nthfieldname
=
1638 rawattrib
->taglist
.tag
[c
].fieldName
->get_name().c_str();
1639 if (cf
->get_is_optional())
1640 key
->fields
[0].fieldtype
= OPTIONAL_FIELD
;
1641 else key
->fields
[0].fieldtype
= MANDATORY_FIELD
;
1642 key
->fields
[0].type
= pool
.add(t
->get_genname_value(my_scope
));
1643 key
->fields
[0].typedescr
=
1644 pool
.add(t
->get_genname_typedescriptor(my_scope
));
1647 for (int b
= 1; b
< key
->nElements
; b
++) {
1649 rawattrib
->taglist
.tag
[c
].keyList
[a
].keyField
->names
[b
-1];
1650 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1651 cf2
= t
->get_comp_byIndex(comp_index
);
1652 key
->fields
[b
].nthfield
= comp_index
;
1653 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1654 if (t
->typetype
== T_CHOICE_T
)
1655 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1656 else if (cf2
->get_is_optional())
1657 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1658 else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1659 Type
*field_type
= cf2
->get_type();
1660 key
->fields
[b
].type
=
1661 pool
.add(field_type
->get_genname_value(my_scope
));
1662 key
->fields
[b
].typedescr
=
1663 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1664 if (field_type
->typetype
== T_SEQ_T
&& field_type
->rawattrib
1665 && (field_type
->rawattrib
->pointerto
1666 || field_type
->rawattrib
->lengthto_num
))
1667 key
->start_pos
= -1;
1669 if(t
->typetype
!= T_CHOICE_T
&& t
->typetype
!= T_SET_T
){
1671 for(size_t i
= 0; i
< comp_index
&& key
->start_pos
>=0; i
++)
1673 t2
= t
->get_comp_byIndex(i
)->get_type();
1674 if(t2
->get_raw_length() >= 0){
1676 key
->start_pos
+= t2
->rawattrib
->padding
;
1677 key
->start_pos
+= t2
->get_raw_length();
1678 }else key
->start_pos
= -1;
1681 t
= field_type
->get_type_refd_last();
1685 // building presence list
1686 for(int a
=0;a
<rawattrib
->presence
.nElements
;a
++) {
1687 rawAST_coding_field_list
* presences
=sdef
.raw
.presence
.fields
+a
;
1688 presences
->nElements
=
1689 rawattrib
->presence
.keyList
[a
].keyField
->nElements
;
1690 presences
->value
=rawattrib
->presence
.keyList
[a
].value
;
1691 presences
->fields
=(rawAST_coding_fields
*)
1692 Malloc(presences
->nElements
*sizeof(rawAST_coding_fields
));
1694 for (int b
= 0; b
< presences
->nElements
; b
++) {
1695 Identifier
*idf
= rawattrib
->presence
.keyList
[a
].keyField
->names
[b
];
1696 size_t comp_index
= t
->get_comp_index_byName(*idf
);
1697 CompField
*cf
= t
->get_comp_byIndex(comp_index
);
1698 presences
->fields
[b
].nthfield
= comp_index
;
1699 presences
->fields
[b
].nthfieldname
= idf
->get_name().c_str();
1700 if (t
->typetype
== T_CHOICE_T
)
1701 presences
->fields
[b
].fieldtype
= UNION_FIELD
;
1702 else if (cf
->get_is_optional())
1703 presences
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1704 else presences
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1705 Type
*field_type
= cf
->get_type();
1706 presences
->fields
[b
].type
=
1707 pool
.add(field_type
->get_genname_value(my_scope
));
1708 presences
->fields
[b
].typedescr
=
1709 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1710 t
= field_type
->get_type_refd_last();
1713 for(int c
=0;c
<rawattrib
->ext_bit_goup_num
;c
++){
1714 Identifier
*idf
=rawattrib
->ext_bit_groups
[c
].from
;
1715 Identifier
*idf2
=rawattrib
->ext_bit_groups
[c
].to
;
1716 sdef
.raw
.ext_bit_groups
[c
].ext_bit
=rawattrib
->ext_bit_groups
[c
].ext_bit
;
1717 sdef
.raw
.ext_bit_groups
[c
].from
=(int)get_comp_index_byName(*idf
);
1718 sdef
.raw
.ext_bit_groups
[c
].to
=(int)get_comp_index_byName(*idf2
);
1720 for(size_t i
=0; i
<sdef
.totalElements
; i
++) {
1721 CompField
*cf
= get_comp_byIndex(i
);
1722 Type
*t_field
= cf
->get_type();
1723 Type
*t_field_last
= t_field
->get_type_refd_last();
1724 RawAST
*rawpar
= t_field
->rawattrib
;
1726 copy_rawAST_to_struct(rawpar
,&(sdef
.elements
[i
].raw
));
1727 for(int j
=0; j
<rawpar
->lengthto_num
;j
++){
1728 Identifier
*idf
=rawpar
->lengthto
[j
];
1729 sdef
.elements
[i
].raw
.lengthto
[j
]=get_comp_index_byName(*idf
);
1731 if (rawpar
->lengthto_num
&& rawpar
->lengthindex
) {
1732 Identifier
*idf
= rawpar
->lengthindex
->names
[0];
1733 size_t comp_index
= t_field_last
->get_comp_index_byName(*idf
);
1734 sdef
.elements
[i
].raw
.lengthindex
->nthfield
= comp_index
;
1735 sdef
.elements
[i
].raw
.lengthindex
->nthfieldname
=
1736 idf
->get_name().c_str();
1737 CompField
*cf2
= t_field_last
->get_comp_byIndex(comp_index
);
1738 Type
*t_field2
= cf2
->get_type();
1739 if (t_field2
->typetype
== T_CHOICE_T
)
1740 sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= UNION_FIELD
;
1741 else if (cf2
->get_is_optional())
1742 sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= OPTIONAL_FIELD
;
1743 else sdef
.elements
[i
].raw
.lengthindex
->fieldtype
= MANDATORY_FIELD
;
1744 sdef
.elements
[i
].raw
.lengthindex
->type
=
1745 pool
.add(t_field2
->get_genname_value(my_scope
));
1746 sdef
.elements
[i
].raw
.lengthindex
->typedescr
=
1747 pool
.add(t_field2
->get_genname_typedescriptor(my_scope
));
1749 if (rawpar
->lengthto_num
&& !rawpar
->lengthindex
&&
1750 t_field_last
->is_secho()) {
1751 int comp_num
=(int)t_field_last
->get_nof_comps();
1752 sdef
.elements
[i
].raw
.union_member_num
=comp_num
;
1753 sdef
.elements
[i
].raw
.member_name
=
1754 (const char **)Malloc((comp_num
+1)*sizeof(const char*));
1755 sdef
.elements
[i
].raw
.member_name
[0] =
1756 pool
.add(t_field_last
->get_genname_value(my_scope
));
1757 for(int m
=1;m
<comp_num
+1;m
++){
1758 CompField
*compf
=t_field_last
->get_comp_byIndex(m
-1);
1759 sdef
.elements
[i
].raw
.member_name
[m
]=
1760 compf
->get_name().get_name().c_str();
1763 if(rawpar
->pointerto
){
1764 Identifier
*idf
=rawpar
->pointerto
;
1765 sdef
.elements
[i
].raw
.pointerto
=get_comp_index_byName(*idf
);
1766 if(rawpar
->ptrbase
){
1767 Identifier
*idf2
=rawpar
->ptrbase
;
1768 sdef
.elements
[i
].raw
.pointerbase
=get_comp_index_byName(*idf2
);
1769 } else sdef
.elements
[i
].raw
.pointerbase
=i
;
1771 // building presence list
1772 for(int a
=0;a
<rawpar
->presence
.nElements
;a
++) {
1773 rawAST_coding_field_list
* presences
=
1774 sdef
.elements
[i
].raw
.presence
.fields
+a
;
1775 presences
->nElements
=
1776 rawpar
->presence
.keyList
[a
].keyField
->nElements
;
1777 presences
->value
=rawpar
->presence
.keyList
[a
].value
;
1778 presences
->fields
=(rawAST_coding_fields
*)
1779 Malloc(presences
->nElements
*sizeof(rawAST_coding_fields
));
1781 for (int b
= 0; b
< presences
->nElements
; b
++) {
1782 Identifier
*idf
= rawpar
->presence
.keyList
[a
].keyField
->names
[b
];
1783 size_t comp_index
= t
->get_comp_index_byName(*idf
);
1784 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1785 presences
->fields
[b
].nthfield
= comp_index
;
1786 presences
->fields
[b
].nthfieldname
= idf
->get_name().c_str();
1787 if (t
->typetype
== T_CHOICE_T
)
1788 presences
->fields
[b
].fieldtype
= UNION_FIELD
;
1789 else if (cf2
->get_is_optional())
1790 presences
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1791 else presences
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1792 Type
*field_type
= cf2
->get_type();
1793 presences
->fields
[b
].type
=
1794 pool
.add(field_type
->get_genname_value(my_scope
));
1795 presences
->fields
[b
].typedescr
=
1796 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1797 t
= field_type
->get_type_refd_last();
1800 // building crosstaglist
1801 for(int c
=0;c
<rawpar
->crosstaglist
.nElements
;c
++){
1802 if(rawpar
->crosstaglist
.tag
[c
].nElements
)
1803 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
=
1804 (rawAST_coding_field_list
*)
1805 Malloc(rawpar
->crosstaglist
.tag
[c
].nElements
1806 *sizeof(rawAST_coding_field_list
));
1807 else sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
=NULL
;
1808 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].nElements
=
1809 rawpar
->crosstaglist
.tag
[c
].nElements
;
1810 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldName
=
1811 rawpar
->crosstaglist
.tag
[c
].fieldName
->get_name().c_str();
1812 Identifier
*idf
=rawpar
->crosstaglist
.tag
[c
].fieldName
;
1813 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldnum
=
1814 t_field_last
->get_comp_index_byName(*idf
);
1815 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fieldnum
=
1816 t_field_last
->get_comp_index_byName(*idf
);
1817 for(int a
=0;a
<rawpar
->crosstaglist
.tag
[c
].nElements
;a
++) {
1818 rawAST_coding_field_list
* key
=
1819 sdef
.elements
[i
].raw
.crosstaglist
.list
[c
].fields
+a
;
1821 rawpar
->crosstaglist
.tag
[c
].keyList
[a
].keyField
->nElements
;
1822 key
->value
=rawpar
->crosstaglist
.tag
[c
].keyList
[a
].value
;
1823 key
->fields
=(rawAST_coding_fields
*)
1824 Malloc(key
->nElements
*sizeof(rawAST_coding_fields
));
1826 for (int b
= 0; b
< key
->nElements
; b
++) {
1828 rawpar
->crosstaglist
.tag
[c
].keyList
[a
].keyField
->names
[b
];
1829 size_t comp_index
= t
->get_comp_index_byName(*idf2
);
1830 CompField
*cf2
= t
->get_comp_byIndex(comp_index
);
1831 key
->fields
[b
].nthfield
= comp_index
;
1832 key
->fields
[b
].nthfieldname
= idf2
->get_name().c_str();
1833 if (t
->typetype
== T_CHOICE_T
)
1834 key
->fields
[b
].fieldtype
= UNION_FIELD
;
1835 else if (cf2
->get_is_optional())
1836 key
->fields
[b
].fieldtype
= OPTIONAL_FIELD
;
1837 else key
->fields
[b
].fieldtype
= MANDATORY_FIELD
;
1838 Type
*field_type
= cf2
->get_type();
1839 key
->fields
[b
].type
=
1840 pool
.add(field_type
->get_genname_value(my_scope
));
1841 key
->fields
[b
].typedescr
=
1842 pool
.add(field_type
->get_genname_typedescriptor(my_scope
));
1843 t
= field_type
->get_type_refd_last();
1847 sdef
.elements
[i
].raw
.length
= t_field
->get_raw_length();
1848 sdef
.elements
[i
].hasRaw
=true;
1851 sdef
.elements
[i
].hasRaw
=false;
1856 for(size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1857 sdef
.elements
[i
].hasRaw
=false;
1862 defRecordClass(&sdef
, target
);
1863 defRecordTemplate(&sdef
, target
);
1865 for(size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1866 // free the array but not the strings
1867 if (sdef
.elements
[i
].xerAnyNum
> 0) Free(sdef
.elements
[i
].xerAnyUris
);
1871 free_raw_attrib_struct(&sdef
.raw
);
1872 for (size_t i
= 0; i
< sdef
.totalElements
; i
++) {
1873 if (sdef
.elements
[i
].hasRaw
) {
1874 free_raw_attrib_struct(&sdef
.elements
[i
].raw
);
1878 Free(sdef
.elements
);
1881 bool Type::is_untagged() const { return xerattrib
&& xerattrib
->untagged_
; }
1883 void Type::generate_code_SeOf(output_struct
*target
)
1885 const Type
*oftypelast
= u
.seof
.ofType
->get_type_refd_last();
1886 const string
& oftypename
= u
.seof
.ofType
->get_genname_value(my_scope
);
1887 boolean optimized_memalloc
= !use_runtime_2
&& get_optimize_attribute() == "memalloc";
1889 if (is_pregenerated()) {
1890 switch(oftypelast
->typetype
) {
1893 case T_TELETEXSTRING
:
1894 case T_VIDEOTEXSTRING
:
1895 case T_GRAPHICSTRING
:
1896 case T_GENERALSTRING
:
1897 case T_UNIVERSALSTRING
:
1899 case T_OBJECTDESCRIPTOR
:
1900 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
1901 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s %s;\n"
1902 "typedef PreGenRecordOf::PREGEN__%s__OF__UNIVERSAL__CHARSTRING%s_template %s_template;\n",
1903 (typetype
== T_SEQOF
) ? "RECORD" : "SET",
1904 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str(),
1905 (typetype
== T_SEQOF
) ? "RECORD" : "SET",
1906 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str());
1909 // generate these in the class declarations part, they need to be
1910 // outside of the include guard in case of circular imports
1911 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
1912 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s %s;\n"
1913 "typedef PreGenRecordOf::PREGEN__%s__OF__%s%s_template %s_template;\n",
1914 (typetype
== T_SEQOF
) ? "RECORD" : "SET", oftypename
.c_str(),
1915 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str(),
1916 (typetype
== T_SEQOF
) ? "RECORD" : "SET", oftypename
.c_str(),
1917 optimized_memalloc
? "__OPTIMIZED" : "", get_genname_own().c_str());
1923 struct_of_def sofdef
;
1924 memset(&sofdef
, 0, sizeof(sofdef
));
1925 sofdef
.name
= get_genname_own().c_str();
1926 sofdef
.dispname
= get_fullname().c_str();
1927 sofdef
.kind
= typetype
== T_SEQOF
? RECORD_OF
: SET_OF
;
1928 sofdef
.isASN1
= is_asn1();
1929 sofdef
.hasText
= textattrib
!=NULL
;
1930 sofdef
.hasXer
= has_encoding(CT_XER
);
1931 sofdef
.hasJson
= has_encoding(CT_JSON
);
1933 //sofdef.xerList = xerattrib->list_;
1934 sofdef
.xerAttribute
= xerattrib
->attribute_
;
1936 // If a record of UTF8String, we need to prepare for ANY-ATTRIBUTES and
1938 sofdef
.xerAnyAttrElem
= oftypelast
->typetype
== T_USTR
1939 || oftypelast
->typetype
== T_UTF8STRING
;
1940 sofdef
.type
= oftypename
.c_str();
1941 sofdef
.has_opentypes
= get_has_opentypes();
1942 const string
& oftypedescrname
=
1943 u
.seof
.ofType
->get_genname_typedescriptor(my_scope
);
1944 sofdef
.oftypedescrname
= oftypedescrname
.c_str();
1946 if (xerattrib
&& xerattrib
->untagged_
1947 && ((u
.seof
.ofType
->xerattrib
&& has_ae(u
.seof
.ofType
->xerattrib
))
1948 || (xerattrib
&& has_ae(xerattrib
)))) {
1949 // An untagged record-of which has an embedded type with ANY-ELEMENT,
1950 // or itself has ANY-ELEMENT
1951 if (parent_type
&& parent_type
->typetype
== T_SEQ_T
) {
1952 /* The record-of needs to know the optional siblings following it,
1953 * to be able to stop consuming XML elements that belong
1954 * to the following fields. This is achieved by generating
1955 * a can_start() for the record-of which returns false for XML elements
1956 * that belong to those following fields. */
1957 size_t n_parent_comps
= parent_type
->get_nof_comps();
1958 boolean found_self
= false;
1959 /* Go through the fields of the parent; skip everything until we find
1960 * the field that is this record-of; then collect fields until
1961 * the first non-disappearing field. */
1962 for (size_t pc
= 0; pc
< n_parent_comps
; ++pc
) {
1963 CompField
*pcf
= parent_type
->get_comp_byIndex(pc
); //"ParentCompField"
1964 Type
*pcft
= pcf
->get_type();
1966 const Identifier
& cfid
= pcf
->get_name();
1967 sofdef
.followers
= (struct_field
*)Realloc(sofdef
.followers
,
1968 (++sofdef
.nFollowers
) * sizeof(struct_field
));
1969 sofdef
.followers
[sofdef
.nFollowers
-1].name
= pool
.add(cfid
.get_name());
1970 sofdef
.followers
[sofdef
.nFollowers
-1].type
=
1971 pool
.add(pcft
->get_genname_value(my_scope
));
1972 sofdef
.followers
[sofdef
.nFollowers
-1].typegen
=
1973 pool
.add(pcft
->get_genname_own());
1975 Type
*pcft_last
= pcft
->get_type_refd_last();
1976 if (pcf
->get_is_optional()
1977 || (pcft
->is_untagged() && pcft_last
->has_empty_xml()))
1978 {} // can disappear, continue
1981 else if (pcft
== this) found_self
= true;
1983 } // if parent is record
1986 switch (oftypelast
->typetype
) { // X.680/2002, Table 5 under 25.5
1987 // T_CHOICE_A and T_CHOICE_T do not set xmlValueList because choice types
1988 // already omit their own tag.
1990 case T_ENUM_A
: case T_ENUM_T
:
1992 sofdef
.xmlValueList
= TRUE
;
1996 sofdef
.xmlValueList
= FALSE
;
2001 copy_rawAST_to_struct(rawattrib
,&(sofdef
.raw
));
2003 } else sofdef
.hasRaw
=false;
2005 if (optimized_memalloc
) {
2006 defRecordOfClassMemAllocOptimized(&sofdef
, target
);
2008 defRecordOfClass(&sofdef
, target
);
2010 defRecordOfTemplate(&sofdef
, target
);
2012 if (sofdef
.nFollowers
) {
2013 Free(sofdef
.followers
);
2017 void Type::generate_code_Array(output_struct
*target
)
2019 if (!u
.array
.in_typedef
) return;
2020 const char *own_name
= get_genname_own().c_str();
2021 if (has_encoding(CT_JSON
)) {
2022 target
->header
.class_decls
= mputprintf(target
->header
.class_decls
,
2023 "class %s;\n", own_name
);
2024 target
->header
.class_defs
= mputprintf(target
->header
.class_defs
,
2025 "class %s : public %s {\n"
2026 "const TTCN_Typedescriptor_t* get_elem_descr() const;\n"
2029 u
.array
.dimension
->get_value_type(u
.array
.element_type
, my_scope
).c_str());
2030 target
->source
.class_defs
= mputprintf(target
->source
.class_defs
,
2031 "const TTCN_Typedescriptor_t* %s::get_elem_descr() const { return &%s_descr_; }\n\n",
2032 own_name
, u
.array
.element_type
->get_genname_typedescriptor(my_scope
).c_str());
2034 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
2036 "// written by %s in " __FILE__
" at %d\n"
2040 __FUNCTION__
, __LINE__
,
2042 u
.array
.dimension
->get_value_type(u
.array
.element_type
, my_scope
).c_str(),
2045 target
->header
.typedefs
= mputprintf(target
->header
.typedefs
,
2046 "typedef %s %s_template;\n",
2047 u
.array
.dimension
->get_template_type(u
.array
.element_type
, my_scope
).c_str(),
2051 void Type::generate_code_Fat(output_struct
*target
)
2054 memset(&fdef
, 0, sizeof(fdef
));
2055 fdef
.name
= get_genname_own().c_str();
2056 fdef
.dispname
= get_fullname().c_str();
2059 if(u
.fatref
.return_type
)
2060 if(u
.fatref
.returns_template
)
2061 fdef
.return_type
= mcopystr(u
.fatref
.return_type
->
2062 get_genname_template(my_scope
).c_str());
2063 else fdef
.return_type
= mcopystr(u
.fatref
.return_type
->
2064 get_genname_value(my_scope
).c_str());
2065 else fdef
.return_type
= NULL
;
2066 fdef
.type
= FUNCTION
;
2069 fdef
.return_type
= NULL
;
2070 fdef
.type
= ALTSTEP
;
2073 fdef
.return_type
= NULL
;
2074 fdef
.type
= TESTCASE
;
2077 FATAL_ERROR("Type::generate_code_Fat()");
2079 fdef
.runs_on_self
= u
.fatref
.runs_on
.self
? TRUE
: FALSE
;
2080 fdef
.is_startable
= u
.fatref
.is_startable
;
2081 fdef
.formal_par_list
= u
.fatref
.fp_list
->generate_code(memptystr());
2082 u
.fatref
.fp_list
->generate_code_defval(target
);
2083 fdef
.actual_par_list
= u
.fatref
.fp_list
2084 ->generate_code_actual_parlist(memptystr(),"");
2085 if (typetype
== T_TESTCASE
) {
2086 if (u
.fatref
.fp_list
->get_nof_fps() > 0) {
2087 fdef
.formal_par_list
= mputstr(fdef
.formal_par_list
, ", ");
2088 fdef
.actual_par_list
= mputstr(fdef
.actual_par_list
, ", ");
2090 fdef
.formal_par_list
= mputstr(fdef
.formal_par_list
,
2091 "boolean has_timer, double timer_value");
2092 fdef
.actual_par_list
= mputstr(fdef
.actual_par_list
,
2093 "has_timer, timer_value");
2095 fdef
.nElements
= u
.fatref
.fp_list
->get_nof_fps();
2096 fdef
.parameters
= (const char**)
2097 Malloc(fdef
.nElements
* sizeof(*fdef
.parameters
));
2098 for(size_t i
= 0;i
< fdef
.nElements
; i
++) {
2099 fdef
.parameters
[i
] = u
.fatref
.fp_list
->get_fp_byIndex(i
)
2100 ->get_id().get_name().c_str();
2103 defFunctionrefClass(&fdef
, target
);
2104 defFunctionrefTemplate(&fdef
, target
);
2105 Free(fdef
.return_type
);
2106 Free(fdef
.formal_par_list
);
2107 Free(fdef
.actual_par_list
);
2108 Free(fdef
.parameters
);
2111 void Type::generate_code_Signature(output_struct
*target
)
2115 memset(&sdef
, 0, sizeof(sdef
));
2116 sdef
.name
= get_genname_own().c_str();
2117 sdef
.dispname
= get_fullname().c_str();
2118 if (u
.signature
.return_type
) sdef
.return_type
=
2119 pool
.add(u
.signature
.return_type
->get_genname_value(my_scope
));
2120 else sdef
.return_type
= NULL
;
2121 if (u
.signature
.parameters
) {
2122 sdef
.parameters
.nElements
= u
.signature
.parameters
->get_nof_params();
2123 sdef
.parameters
.elements
= (signature_par
*)
2124 Malloc(sdef
.parameters
.nElements
* sizeof(*sdef
.parameters
.elements
));
2125 for (size_t i
= 0; i
< sdef
.parameters
.nElements
; i
++) {
2126 SignatureParam
*param
= u
.signature
.parameters
->get_param_byIndex(i
);
2127 switch (param
->get_direction()) {
2128 case SignatureParam::PARAM_IN
:
2129 sdef
.parameters
.elements
[i
].direction
= PAR_IN
;
2131 case SignatureParam::PARAM_OUT
:
2132 sdef
.parameters
.elements
[i
].direction
= PAR_OUT
;
2134 case SignatureParam::PARAM_INOUT
:
2135 sdef
.parameters
.elements
[i
].direction
= PAR_INOUT
;
2138 FATAL_ERROR("Type::generate_code_Signature()");
2140 sdef
.parameters
.elements
[i
].type
=
2141 pool
.add(param
->get_type()->get_genname_value(my_scope
));
2142 sdef
.parameters
.elements
[i
].name
= param
->get_id().get_name().c_str();
2143 sdef
.parameters
.elements
[i
].dispname
=
2144 param
->get_id().get_ttcnname().c_str();
2147 sdef
.parameters
.nElements
= 0;
2148 sdef
.parameters
.elements
= NULL
;
2150 sdef
.is_noblock
= u
.signature
.no_block
;
2151 if (u
.signature
.exceptions
) {
2152 sdef
.exceptions
.nElements
= u
.signature
.exceptions
->get_nof_types();
2153 sdef
.exceptions
.elements
= (signature_exception
*)
2154 Malloc(sdef
.exceptions
.nElements
* sizeof(*sdef
.exceptions
.elements
));
2155 for (size_t i
= 0; i
< sdef
.exceptions
.nElements
; i
++) {
2156 Type
*type
= u
.signature
.exceptions
->get_type_byIndex(i
);
2157 sdef
.exceptions
.elements
[i
].name
=
2158 pool
.add(type
->get_genname_value(my_scope
));
2159 sdef
.exceptions
.elements
[i
].dispname
= pool
.add(type
->get_typename());
2160 sdef
.exceptions
.elements
[i
].altname
= pool
.add(type
->get_genname_altname());
2163 sdef
.exceptions
.nElements
= 0;
2164 sdef
.exceptions
.elements
= NULL
;
2166 defSignatureClasses(&sdef
, target
);
2167 Free(sdef
.parameters
.elements
);
2168 Free(sdef
.exceptions
.elements
);
2171 bool Type::needs_alias()
2173 /** The decision is actually based on the fullname of the type. If it
2174 * contains two or more dot (.) characters false is returned.
2175 * The following attributes cannot be used for the decision:
2176 * - parent_type, my_scope: types within ASN.1 object classes, objects
2177 * look the same as top-level aliased types, but they do not need alias. */
2178 const string
& full_name
= get_fullname();
2179 size_t fullname_len
= full_name
.size();
2180 size_t first_dot
= full_name
.find('.', 0);
2181 if (first_dot
>= fullname_len
) return true; // no dots
2182 else if (full_name
.find('.', first_dot
+ 1) < fullname_len
) return false;
2187 void Type::generate_code_done(output_struct
*target
)
2189 const string
& t_genname
= get_genname_value(my_scope
);
2190 const char *genname_str
= t_genname
.c_str();
2191 const string
& dispname
= get_typename();
2192 const char *dispname_str
= dispname
.c_str();
2193 target
->header
.function_prototypes
= mputprintf
2194 (target
->header
.function_prototypes
,
2195 "extern alt_status done(const COMPONENT& component_reference, "
2196 "const %s_template& value_template, %s *value_ptr);\n",
2197 genname_str
, genname_str
);
2198 target
->source
.function_bodies
= mputprintf
2199 (target
->source
.function_bodies
,
2200 "alt_status done(const COMPONENT& component_reference, "
2201 "const %s_template& value_template, %s *value_ptr)\n"
2203 "if (!component_reference.is_bound()) "
2204 "TTCN_error(\"Performing a done operation on an unbound component "
2206 "Text_Buf *text_buf;\n"
2207 "alt_status ret_val = TTCN_Runtime::component_done("
2208 "(component)component_reference, \"%s\", text_buf);\n"
2209 "if (ret_val == ALT_YES) {\n"
2210 "%s return_value;\n"
2211 "return_value.decode_text(*text_buf);\n"
2212 "if (value_template.match(return_value)) {\n"
2213 "if (value_ptr != NULL) *value_ptr = return_value;\n"
2214 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
2215 "TTCN_Logger::log_event_str(\"PTC with component reference \");\n"
2216 "component_reference.log();\n"
2217 "TTCN_Logger::log_event_str(\" is done. Return value: %s : \");\n"
2218 "return_value.log();\n"
2219 "TTCN_Logger::end_event();\n"
2222 "if (TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_DONE)) {\n"
2223 "TTCN_Logger::begin_event(TTCN_Logger::MATCHING_DONE);\n"
2224 "TTCN_Logger::log_event_str(\"Done operation with type %s on"
2225 " component reference \");\n"
2226 "component_reference.log();\n"
2227 "TTCN_Logger::log_event_str(\" failed: Return value does not match "
2228 "the template: \");\n"
2229 "value_template.log_match(return_value%s);\n"
2230 "TTCN_Logger::end_event();\n"
2234 "} else return ret_val;\n"
2236 genname_str
, genname_str
, dispname_str
, genname_str
, dispname_str
,
2237 dispname_str
, omit_in_value_list
? ", TRUE" : "");
2240 bool Type::ispresent_anyvalue_embedded_field(Type
* t
,
2241 Ttcn::FieldOrArrayRefs
*subrefs
, size_t begin_index
)
2243 if (!subrefs
) return true;
2244 size_t nof_refs
= subrefs
->get_nof_refs();
2245 for (size_t i
= begin_index
; i
< nof_refs
; i
++) {
2246 t
= t
->get_type_refd_last();
2247 Ttcn::FieldOrArrayRef
*ref
= subrefs
->get_ref(i
);
2248 switch (ref
->get_type()) {
2249 case Ttcn::FieldOrArrayRef::FIELD_REF
: {
2250 CompField
* cf
= t
->get_comp_byName(*ref
->get_id());
2251 switch (t
->typetype
) {
2261 if (cf
->get_is_optional()) return false;
2264 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2268 case Ttcn::FieldOrArrayRef::ARRAY_REF
:
2269 switch (t
->typetype
) {
2272 return false; // (the existence of a record of element is optional)
2274 t
= t
->u
.array
.element_type
;
2277 return true; // string types
2281 FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
2287 void Type::generate_code_ispresentbound(expression_struct
*expr
,
2288 Ttcn::FieldOrArrayRefs
*subrefs
, Common::Module
* module
,
2289 const string
& global_id
, const string
& external_id
, const bool is_template
,
2292 if (!subrefs
) return;
2296 bool next_o
; // next is optional value
2297 size_t nof_refs
= subrefs
->get_nof_refs();
2298 subrefs
->clear_string_element_ref();
2299 char *tmp_generalid_str
= mcopystr(external_id
.c_str());
2300 expstring_t closing_brackets
= memptystr(); //The closing parts collected
2301 for (size_t i
= 0; i
< nof_refs
; i
++) {
2302 t
= t
->get_type_refd_last();
2303 // stop immediately if current type t is erroneous
2304 // (e.g. because of circular reference)
2305 if (t
->typetype
== T_ERROR
) return;
2308 bool anyval_ret_val
= true;
2310 anyval_ret_val
= ispresent_anyvalue_embedded_field(t
, subrefs
, i
);
2312 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2313 expr
->expr
= mputprintf(expr
->expr
,
2314 "switch (%s.get_selection()) {\n"
2315 "case UNINITIALIZED_TEMPLATE:\n"
2321 "case SPECIFIC_VALUE: {\n",
2322 tmp_generalid_str
, global_id
.c_str(), global_id
.c_str(),
2323 anyval_ret_val
? "true" : "false");
2325 expstring_t closing_brackets_switch
= mprintf(
2333 global_id
.c_str(), closing_brackets
);
2334 Free(closing_brackets
);
2335 closing_brackets
= closing_brackets_switch
;
2338 Ttcn::FieldOrArrayRef
*ref
= subrefs
->get_ref(i
);
2339 switch (ref
->get_type()) {
2340 case Ttcn::FieldOrArrayRef::FIELD_REF
: {
2341 const Identifier
& id
= *ref
->get_id();
2342 CompField
* cf
= t
->get_comp_byName(id
);
2343 next_t
= cf
->get_type();
2344 next_o
= !is_template
&& cf
->get_is_optional();
2346 switch (t
->typetype
) {
2350 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2351 expr
->expr
= mputprintf(expr
->expr
,
2352 "%s = %s.ischosen(%s::ALT_%s);\n", global_id
.c_str(),
2354 t
->get_genname_value(module
).c_str(),
2355 id
.get_name().c_str());
2356 expr
->expr
= mputstr(expr
->expr
, "}\n");
2357 // intentionally missing break
2365 FATAL_ERROR("Type::generate_code_isbound()");
2369 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2370 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2371 Free(closing_brackets
);
2372 closing_brackets
= closing_brackets2
;
2374 const string
& tmp_id
= module
->get_temporary_id();
2375 const char *tmp_id_str
= tmp_id
.c_str();
2376 expr
->expr
= mputprintf(expr
->expr
,
2377 "const OPTIONAL<%s%s>& %s = %s.%s();\n",
2378 next_t
->get_genname_value(module
).c_str(),
2379 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2380 id
.get_name().c_str());
2382 if (i
==(nof_refs
-1)) {
2383 // we are at the end of the reference chain
2384 expr
->expr
= mputprintf(expr
->expr
,
2385 "switch (%s.get_selection()) {\n"
2386 "case OPTIONAL_UNBOUND:\n"
2389 "case OPTIONAL_OMIT:\n"
2393 tmp_id_str
, global_id
.c_str(),global_id
.c_str(),
2394 isbound
? "true" : "false");
2395 Free(tmp_generalid_str
);
2396 tmp_generalid_str
= mcopystr(tmp_id_str
);
2398 expr
->expr
= mputstr(expr
->expr
, "{\n");
2399 const string
& tmp_id2
= module
->get_temporary_id();
2400 const char *tmp_id2_str
= tmp_id2
.c_str();
2401 expr
->expr
= mputprintf(expr
->expr
,
2402 "const %s%s& %s = (const %s%s&) %s;\n",
2403 next_t
->get_genname_value(module
).c_str(),
2404 is_template
?"_template":"", tmp_id2_str
,
2405 next_t
->get_genname_value(module
).c_str(),
2406 is_template
?"_template":"", tmp_id_str
);
2408 expr
->expr
= mputprintf(expr
->expr
,
2409 "%s = %s.%s(%s);\n", global_id
.c_str(),
2410 tmp_id2_str
, isbound
? "is_bound" : "is_present",
2411 (!isbound
&& is_template
&& omit_in_value_list
) ? "TRUE" : "");
2412 Free(tmp_generalid_str
);
2413 tmp_generalid_str
= mcopystr(tmp_id2_str
);
2415 expr
->expr
= mputprintf(expr
->expr
,
2419 expr
->expr
= mputprintf(expr
->expr
,
2420 "switch (%s.get_selection()) {\n"
2421 "case OPTIONAL_UNBOUND:\n"
2422 "case OPTIONAL_OMIT:\n"
2428 tmp_id_str
, global_id
.c_str());
2429 Free(tmp_generalid_str
);
2430 tmp_generalid_str
= mcopystr(tmp_id_str
);
2432 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2433 closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2434 Free(closing_brackets
);
2435 closing_brackets
= closing_brackets2
;
2437 const string
& tmp_id2
= module
->get_temporary_id();
2438 const char *tmp_id2_str
= tmp_id2
.c_str();
2439 expr
->expr
= mputprintf(expr
->expr
,
2440 "const %s%s& %s = (const %s%s&) %s;\n",
2441 next_t
->get_genname_value(module
).c_str(),
2442 is_template
?"_template":"", tmp_id2_str
,
2443 next_t
->get_genname_value(module
).c_str(),
2444 is_template
?"_template":"", tmp_id_str
);
2446 expr
->expr
= mputprintf(expr
->expr
,
2447 "%s = %s.is_bound();\n", global_id
.c_str(),
2449 Free(tmp_generalid_str
);
2450 tmp_generalid_str
= mcopystr(tmp_id2_str
);
2453 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2454 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2455 Free(closing_brackets
);
2456 closing_brackets
= closing_brackets2
;
2458 const string
& tmp_id
= module
->get_temporary_id();
2459 const char *tmp_id_str
= tmp_id
.c_str();
2460 expr
->expr
= mputprintf(expr
->expr
,
2461 "const %s%s& %s = %s.%s();\n",
2462 next_t
->get_genname_value(module
).c_str(),
2463 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2464 id
.get_name().c_str());
2466 expr
->expr
= mputprintf(expr
->expr
,
2467 "%s = %s.%s(%s);\n", global_id
.c_str(),
2468 tmp_id_str
, isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2469 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2470 Free(tmp_generalid_str
);
2471 tmp_generalid_str
= mcopystr(tmp_id_str
);
2476 case Ttcn::FieldOrArrayRef::ARRAY_REF
: {
2477 Type
*embedded_type
= 0;
2478 bool is_string
= true;
2479 bool is_string_element
= false;
2480 switch (t
->typetype
) {
2483 embedded_type
= t
->u
.seof
.ofType
;
2487 embedded_type
= t
->u
.array
.element_type
;
2497 case T_NUMERICSTRING
:
2498 case T_PRINTABLESTRING
:
2499 case T_TELETEXSTRING
:
2500 case T_VIDEOTEXSTRING
:
2502 case T_GRAPHICSTRING
:
2503 case T_VISIBLESTRING
:
2504 case T_GENERALSTRING
:
2505 case T_UNIVERSALSTRING
:
2508 case T_GENERALIZEDTIME
:
2509 case T_OBJECTDESCRIPTOR
:
2510 if (subrefs
->refers_to_string_element()) {
2511 FATAL_ERROR("Type::generate_code_isbound()");
2513 subrefs
->set_string_element_ref();
2514 // string elements have the same type as the string itself
2516 is_string_element
= true;
2520 FATAL_ERROR("Type::generate_code_isbound()");
2523 next_t
= embedded_type
;
2525 // check the index value
2526 Value
*index_value
= ref
->get_val();
2527 Value
*v_last
= index_value
->get_value_refd_last();
2529 const string
& tmp_index_id
= module
->get_temporary_id();
2530 const char *tmp_index_id_str
= tmp_index_id
.c_str();
2531 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2533 expstring_t closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2534 Free(closing_brackets
);
2535 closing_brackets
= closing_brackets2
;
2537 expr
->expr
= mputprintf(expr
->expr
, "const int %s = ", tmp_index_id_str
);
2538 v_last
->generate_code_expr_mandatory(expr
);
2539 expr
->expr
= mputstr(expr
->expr
, ";\n");
2540 expr
->expr
= mputprintf(expr
->expr
, "%s = (%s >= 0) && (%s.%s > %s);\n",
2541 global_id
.c_str(), tmp_index_id_str
, tmp_generalid_str
,
2542 is_string
? "lengthof()": ( is_template
? "n_elem()" : "size_of()" ),
2544 expr
->expr
= mputprintf(expr
->expr
, "if(%s) {\n",global_id
.c_str());
2546 closing_brackets2
= mprintf("}\n%s", closing_brackets
);
2547 Free(closing_brackets
);
2548 closing_brackets
= closing_brackets2
;
2550 const string
& tmp_id
= module
->get_temporary_id();
2551 const char *tmp_id_str
= tmp_id
.c_str();
2553 if (is_string_element
) {
2554 expr
->expr
= mputprintf(expr
->expr
,
2555 "%s = %s[%s].%s(%s);\n", global_id
.c_str(),
2556 tmp_generalid_str
, tmp_index_id_str
,
2557 isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2558 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2561 expr
->expr
= mputprintf(expr
->expr
,
2562 "const %s& %s = %s[%s];\n",
2563 next_t
->get_genname_template(module
).c_str(),
2564 tmp_id_str
, tmp_generalid_str
,
2567 expr
->expr
= mputprintf(expr
->expr
,
2568 "const %s%s& %s = %s[%s];\n",
2569 next_t
->get_genname_value(module
).c_str(),
2570 is_template
?"_template":"", tmp_id_str
, tmp_generalid_str
,
2574 expr
->expr
= mputprintf(expr
->expr
,
2575 "%s = %s.%s(%s);\n", global_id
.c_str(), tmp_id_str
,
2576 isbound
||(i
!=(nof_refs
-1)) ? "is_bound" : "is_present",
2577 (!(isbound
||(i
!=(nof_refs
-1))) && is_template
&& omit_in_value_list
) ? "TRUE" : "");
2580 Free(tmp_generalid_str
);
2581 tmp_generalid_str
= mcopystr(tmp_id_str
);
2583 // change t to the embedded type
2587 FATAL_ERROR("Type::generate_code_isbound(): invalid reference type");
2591 Free(tmp_generalid_str
);
2592 expr
->expr
= mputstr(expr
->expr
, closing_brackets
);
2593 Free(closing_brackets
);
2596 string
Type::get_optimize_attribute()
2600 vector
<SingleWithAttrib
> const &real_attribs
2601 = w_attrib_path
->get_real_attrib();
2602 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2603 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2604 if (temp_single
->get_attribKeyword()
2605 == SingleWithAttrib::AT_EXTENSION
2606 && (!temp_single
->get_attribQualifiers()
2607 || (temp_single
->get_attribQualifiers()
2608 ->get_nof_qualifiers() == 0)))
2610 const string
& spec
= temp_single
->get_attribSpec().get_spec();
2611 // TODO: use a real parser to allow whitespaces, etc.
2612 if (spec
.find("optimize:")==0 && spec
.size()>9)
2614 string spec_optimize_for_what
= spec
.substr(9);
2615 return spec_optimize_for_what
;
2623 string
Type::get_sourcefile_attribute()
2627 vector
<SingleWithAttrib
> const &real_attribs
2628 = w_attrib_path
->get_real_attrib();
2630 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2631 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2632 if (temp_single
->get_attribKeyword()
2633 == SingleWithAttrib::AT_EXTENSION
2634 && (!temp_single
->get_attribQualifiers()
2635 || (temp_single
->get_attribQualifiers()
2636 ->get_nof_qualifiers() == 0)))
2638 const string
& spec
= temp_single
->get_attribSpec().get_spec();
2639 if (spec
.find("sourcefile:")==0 && spec
.size()>11)
2641 string spec_filename
= spec
.substr(11);
2642 // TODO: check if string can be a valid filename
2643 return spec_filename
;
2651 bool Type::has_done_attribute()
2655 vector
<SingleWithAttrib
> const &real_attribs
2656 = w_attrib_path
->get_real_attrib();
2658 for (size_t i
= 0; i
< real_attribs
.size(); i
++) {
2659 SingleWithAttrib
* temp_single
= real_attribs
[i
];
2660 if (temp_single
->get_attribKeyword()
2661 == SingleWithAttrib::AT_EXTENSION
2662 && (!temp_single
->get_attribQualifiers()
2663 || (temp_single
->get_attribQualifiers()
2664 ->get_nof_qualifiers() == 0))
2665 && temp_single
->get_attribSpec().get_spec() == "done")
2674 void Type::generate_code_object(const_def
*cdef
, Scope
*p_scope
,
2675 const string
& name
, const char *prefix
, bool is_template
)
2678 if (is_template
) type_name
= get_genname_template(p_scope
);
2679 else type_name
= get_genname_value(p_scope
);
2680 const char *name_str
= name
.c_str();
2681 const char *type_name_str
= type_name
.c_str();
2683 cdef
->decl
= mputprintf(cdef
->decl
, "extern const %s& %s;\n",
2684 type_name_str
, name_str
);
2685 cdef
->def
= mputprintf(cdef
->def
, "static %s %s%s;\n"
2686 "const %s& %s = %s%s;\n", type_name_str
, prefix
, name_str
,
2687 type_name_str
, name_str
, prefix
, name_str
);
2689 cdef
->decl
= mputprintf(cdef
->decl
, "extern %s %s;\n",
2690 type_name_str
, name_str
);
2691 cdef
->def
= mputprintf(cdef
->def
, "%s %s;\n",
2692 type_name_str
, name_str
);
2696 void Type::generate_code_object(const_def
*cdef
, GovernedSimple
*p_setting
)
2698 bool is_template
= false;
2699 switch (p_setting
->get_st()) {
2706 FATAL_ERROR("Type::generate_code_object()");
2708 if (p_setting
->get_err_descr()) {
2709 cdef
->def
= p_setting
->get_err_descr()->generate_code_str(cdef
->def
,
2710 p_setting
->get_genname_prefix() + p_setting
->get_genname_own());
2712 generate_code_object(cdef
, p_setting
->get_my_scope(),
2713 p_setting
->get_genname_own(), p_setting
->get_genname_prefix(),
2717 void Type::generate_json_schema(JSON_Tokenizer
& json
, bool embedded
, bool as_value
)
2719 // add a new property for the type if it has its own definition
2721 json
.put_next_token(JSON_TOKEN_NAME
, get_dispname().c_str());
2724 // create an object containing the type's schema
2725 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2727 // if this is a field of a record/set/union with an alias, the field's
2728 // original name must be stored ("originalName" property), it also needs to be
2729 // stored if this is a field of a union with the "as value" coding instruction
2730 if (ownertype
== OT_COMP_FIELD
) {
2731 CompField
* cf
= static_cast<CompField
*>(owner
);
2732 if (as_value
|| (cf
->get_type()->jsonattrib
!= NULL
2733 && cf
->get_type()->jsonattrib
->alias
!= NULL
)) {
2734 json
.put_next_token(JSON_TOKEN_NAME
, "originalName");
2735 char* field_str
= mprintf("\"%s\"", cf
->get_name().get_ttcnname().c_str());
2736 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
2740 // if the parent is a union with the "as value" coding instruction AND the field
2741 // has an alias, then the alias needs to be stored as well ("unusedAlias" property)
2742 if (as_value
&& cf
->get_type()->jsonattrib
!= NULL
2743 && cf
->get_type()->jsonattrib
->alias
!= NULL
) {
2744 json
.put_next_token(JSON_TOKEN_NAME
, "unusedAlias");
2745 char* alias_str
= mprintf("\"%s\"", cf
->get_type()->jsonattrib
->alias
);
2746 json
.put_next_token(JSON_TOKEN_STRING
, alias_str
);
2751 // get the type at the end of the reference chain
2752 Type
* last
= get_type_refd_last();
2754 // check if this is a reference to another type that has its own definition
2755 Type
* refd_type
= NULL
;
2758 while (iter
->is_ref()) {
2759 iter
= iter
->get_type_refd();
2760 if (iter
->ownertype
== OT_TYPE_DEF
|| /* TTCN-3 type definition */
2761 iter
->ownertype
== OT_TYPE_ASS
) { /* ASN.1 type assignment */
2768 // check if there are any type restrictions
2769 boolean has_restrictions
= sub_type
!= NULL
&& sub_type
->has_json_schema();
2771 // if it's a referenced type, then its schema already exists, only add a pointer to it
2772 // exception: instances of ASN.1 parameterized types, always embed their schemas
2773 if (refd_type
!= NULL
&& !get_type_refd()->pard_type_instance
) {
2774 if (has_restrictions
) {
2775 // an 'allOf' structure is needed if this is a subtype,
2776 // insert the pointer in the first part
2777 json
.put_next_token(JSON_TOKEN_NAME
, "allOf");
2778 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2779 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2781 json
.put_next_token(JSON_TOKEN_NAME
, "$ref");
2782 char* ref_str
= mprintf("\"#/definitions/%s/%s\"",
2783 refd_type
->my_scope
->get_scope_mod()->get_modid().get_ttcnname().c_str(),
2784 refd_type
->get_dispname().c_str());
2785 json
.put_next_token(JSON_TOKEN_STRING
, ref_str
);
2787 if (has_restrictions
) {
2788 // close the first part of the 'allOf' and insert the type restrictions
2789 // in the second part
2790 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2791 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2793 // pass the tokenizer to the subtype to insert the type restrictions' schema
2794 sub_type
->generate_json_schema(json
);
2796 // close the second part and the 'allOf' structure itself
2797 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2798 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2801 // generate the schema for the referenced type
2802 switch (last
->typetype
) {
2804 // use the JSON boolean type
2805 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2806 json
.put_next_token(JSON_TOKEN_STRING
, "\"boolean\"");
2810 // use the JSON integer type
2811 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2812 json
.put_next_token(JSON_TOKEN_STRING
, "\"integer\"");
2815 if (has_restrictions
) {
2816 // adding restrictions after the type's schema wouldn't work here
2817 // if the restrictions affect the special values
2818 // use a special function that generates the schema segment for both
2819 // the float type and its restrictions
2820 sub_type
->generate_json_schema_float(json
);
2821 has_restrictions
= false; // so they aren't generated twice
2824 // any of: JSON number or the special values as strings (in an enum)
2825 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
2826 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2827 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2828 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2829 json
.put_next_token(JSON_TOKEN_STRING
, "\"number\"");
2830 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2831 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2832 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2833 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2834 json
.put_next_token(JSON_TOKEN_STRING
, "\"not_a_number\"");
2835 json
.put_next_token(JSON_TOKEN_STRING
, "\"infinity\"");
2836 json
.put_next_token(JSON_TOKEN_STRING
, "\"-infinity\"");
2837 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2838 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2839 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2847 // use the JSON string type and add a pattern to only allow bits or hex digits
2848 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2849 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2850 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2851 json
.put_next_token(JSON_TOKEN_STRING
,
2852 (last
->typetype
== T_OSTR
|| last
->typetype
== T_ANY
) ? "\"octetstring\"" :
2853 ((last
->typetype
== T_HSTR
) ? "\"hexstring\"" : "\"bitstring\""));
2854 json
.put_next_token(JSON_TOKEN_NAME
, "pattern");
2855 json
.put_next_token(JSON_TOKEN_STRING
,
2856 (last
->typetype
== T_OSTR
|| last
->typetype
== T_ANY
) ? "\"^([0-9A-Fa-f][0-9A-Fa-f])*$\"" :
2857 ((last
->typetype
== T_HSTR
) ? "\"^[0-9A-Fa-f]*$\"" : "\"^[01]*$\""));
2860 case T_NUMERICSTRING
:
2861 case T_PRINTABLESTRING
:
2863 case T_VISIBLESTRING
:
2864 // use the JSON string type and add a "subType" property to distinguish it from
2865 // universal charstring types
2866 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2867 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2868 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2869 json
.put_next_token(JSON_TOKEN_STRING
, "\"charstring\"");
2872 case T_GENERALSTRING
:
2873 case T_UNIVERSALSTRING
:
2876 case T_GRAPHICSTRING
:
2877 case T_TELETEXSTRING
:
2878 case T_VIDEOTEXSTRING
:
2879 // use the JSON string type and add a "subType" property to distinguish it from
2881 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2882 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2883 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2884 json
.put_next_token(JSON_TOKEN_STRING
, "\"universal charstring\"");
2888 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2889 json
.put_next_token(JSON_TOKEN_STRING
, "\"string\"");
2890 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
2891 json
.put_next_token(JSON_TOKEN_STRING
, "\"objid\"");
2892 json
.put_next_token(JSON_TOKEN_NAME
, "pattern");
2893 json
.put_next_token(JSON_TOKEN_STRING
, "\"^[0-2][.][1-3]?[0-9]([.][0-9]|([1-9][0-9]+))*$\"");
2896 if (has_restrictions
) {
2897 // the restrictions would only add another JSON enum (after the one
2898 /// generated below), instead just insert the one with the restrictions
2899 sub_type
->generate_json_schema(json
);
2900 has_restrictions
= false; // so they aren't generated twice
2903 // enumerate the possible values
2904 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2905 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2906 json
.put_next_token(JSON_TOKEN_STRING
, "\"none\"");
2907 json
.put_next_token(JSON_TOKEN_STRING
, "\"pass\"");
2908 json
.put_next_token(JSON_TOKEN_STRING
, "\"inconc\"");
2909 json
.put_next_token(JSON_TOKEN_STRING
, "\"fail\"");
2910 json
.put_next_token(JSON_TOKEN_STRING
, "\"error\"");
2911 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2916 // enumerate the possible values
2917 json
.put_next_token(JSON_TOKEN_NAME
, "enum");
2918 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2919 for (size_t i
= 0; i
< last
->u
.enums
.eis
->get_nof_eis(); ++i
) {
2920 char* enum_str
= mprintf("\"%s\"", last
->get_ei_byIndex(i
)->get_name().get_ttcnname().c_str());
2921 json
.put_next_token(JSON_TOKEN_STRING
, enum_str
);
2924 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2925 // list the numeric values for the enumerated items
2926 json
.put_next_token(JSON_TOKEN_NAME
, "numericValues");
2927 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
2928 for (size_t i
= 0; i
< last
->u
.enums
.eis
->get_nof_eis(); ++i
) {
2929 char* num_val_str
= mprintf("%lli", last
->get_ei_byIndex(i
)->get_value()->get_val_Int()->get_val());
2930 json
.put_next_token(JSON_TOKEN_NUMBER
, num_val_str
);
2933 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
2936 // use the JSON null value for the ASN.1 NULL type
2937 json
.put_next_token(JSON_TOKEN_NAME
, "type");
2938 json
.put_next_token(JSON_TOKEN_STRING
, "\"null\"");
2943 last
->generate_json_schema_array(json
);
2949 last
->generate_json_schema_record(json
);
2955 last
->generate_json_schema_union(json
);
2958 FATAL_ERROR("Type::generate_json_schema");
2961 if (has_restrictions
) {
2962 // pass the tokenizer to the subtype to insert the type restrictions' schema
2963 sub_type
->generate_json_schema(json
);
2967 // insert default value (if any)
2968 if (jsonattrib
!= NULL
&& jsonattrib
->default_value
!= NULL
) {
2969 json
.put_next_token(JSON_TOKEN_NAME
, "default");
2970 switch (last
->typetype
) {
2972 json
.put_next_token((jsonattrib
->default_value
[0] == 't') ?
2973 JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
);
2977 if (jsonattrib
->default_value
[0] != 'n' && jsonattrib
->default_value
[0] != 'i'
2978 && jsonattrib
->default_value
[1] != 'i') {
2979 json
.put_next_token(JSON_TOKEN_NUMBER
, jsonattrib
->default_value
);
2982 // no break, insert the special float values as strings
2990 char* default_str
= mprintf("\"%s\"", jsonattrib
->default_value
);
2991 json
.put_next_token(JSON_TOKEN_STRING
, default_str
);
2995 FATAL_ERROR("Type::generate_json_schema");
2999 // insert schema extensions (if any)
3000 if (jsonattrib
!= NULL
) {
3001 for (size_t i
= 0; i
< jsonattrib
->schema_extensions
.size(); ++i
) {
3002 json
.put_next_token(JSON_TOKEN_NAME
, jsonattrib
->schema_extensions
[i
]->key
);
3003 char* value_str
= mprintf("\"%s\"", jsonattrib
->schema_extensions
[i
]->value
);
3004 json
.put_next_token(JSON_TOKEN_STRING
, value_str
);
3009 // end of type's schema
3010 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3013 void Type::generate_json_schema_array(JSON_Tokenizer
& json
)
3015 // use the JSON array type
3016 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3017 json
.put_next_token(JSON_TOKEN_STRING
, "\"array\"");
3019 if (typetype
!= T_ARRAY
) {
3020 // use the "subType" property to distinguish 'record of' from 'set of'
3021 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
3022 json
.put_next_token(JSON_TOKEN_STRING
, (typetype
== T_SEQOF
) ?
3023 "\"record of\"" : "\"set of\"");
3025 // set the number of elements for arrays
3026 char* size_str
= mprintf("%lu", get_nof_comps());
3027 json
.put_next_token(JSON_TOKEN_NAME
, "minItems");
3028 json
.put_next_token(JSON_TOKEN_NUMBER
, size_str
);
3029 json
.put_next_token(JSON_TOKEN_NAME
, "maxItems");
3030 json
.put_next_token(JSON_TOKEN_NUMBER
, size_str
);
3034 // set the element type
3035 json
.put_next_token(JSON_TOKEN_NAME
, "items");
3037 // pass the tokenizer to the elements' type object to insert its schema
3038 get_ofType()->generate_json_schema(json
, true, false);
3041 void Type::generate_json_schema_record(JSON_Tokenizer
& json
)
3043 // use the JSON object type
3044 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3045 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
3047 // use the "subType" property to distinguish records from sets
3048 json
.put_next_token(JSON_TOKEN_NAME
, "subType");
3049 json
.put_next_token(JSON_TOKEN_STRING
, (typetype
== T_SEQ_T
|| typetype
== T_SEQ_A
) ?
3050 "\"record\"" : "\"set\"");
3053 json
.put_next_token(JSON_TOKEN_NAME
, "properties");
3054 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3055 size_t field_count
= get_nof_comps();
3056 bool has_non_optional
= false;
3057 for (size_t i
= 0; i
< field_count
; ++i
) {
3058 Type
* field
= get_comp_byIndex(i
)->get_type();
3060 // use the field's alias if it has one
3061 json
.put_next_token(JSON_TOKEN_NAME
,
3062 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3063 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3065 // optional fields can also get the JSON null value
3066 if (get_comp_byIndex(i
)->get_is_optional()) {
3067 // special case: ASN NULL type, since it uses the JSON literal "null" as a value
3068 if (T_NULL
!= field
->get_type_refd_last()->typetype
) {
3069 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3070 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
3071 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3072 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3073 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3074 json
.put_next_token(JSON_TOKEN_STRING
, "\"null\"");
3075 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3077 } else if (!has_non_optional
) {
3078 has_non_optional
= true;
3081 // pass the tokenizer to the field's type to insert its schema
3082 field
->generate_json_schema(json
, true, false);
3084 // for optional fields: specify the presence of the "omit as null" coding instruction
3085 // and close structures
3086 if (get_comp_byIndex(i
)->get_is_optional() &&
3087 T_NULL
!= field
->get_type_refd_last()->typetype
) {
3088 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3089 json
.put_next_token(JSON_TOKEN_NAME
, "omitAsNull");
3090 json
.put_next_token((field
->jsonattrib
!= NULL
&& field
->jsonattrib
->omit_as_null
) ?
3091 JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
);
3092 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3096 // end of properties
3097 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3099 // do not accept additional fields
3100 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3101 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
3103 // set the field order
3104 if (field_count
> 1) {
3105 json
.put_next_token(JSON_TOKEN_NAME
, "fieldOrder");
3106 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3107 for (size_t i
= 0; i
< field_count
; ++i
) {
3108 Type
* field
= get_comp_byIndex(i
)->get_type();
3109 // use the field's alias if it has one
3110 char* field_str
= mprintf("\"%s\"",
3111 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3112 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3113 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3116 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3119 // set the required (non-optional) fields
3120 if (has_non_optional
) {
3121 json
.put_next_token(JSON_TOKEN_NAME
, "required");
3122 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3123 for (size_t i
= 0; i
< field_count
; ++i
) {
3124 if (!get_comp_byIndex(i
)->get_is_optional()) {
3125 Type
* field
= get_comp_byIndex(i
)->get_type();
3126 // use the field's alias if it has one
3127 char* field_str
= mprintf("\"%s\"",
3128 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3129 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3130 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3134 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3138 void Type::generate_json_schema_union(JSON_Tokenizer
& json
)
3140 // use an "anyOf" structure containing the union's alternatives
3141 json
.put_next_token(JSON_TOKEN_NAME
, "anyOf");
3142 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3144 for (size_t i
= 0; i
< get_nof_comps(); ++i
) {
3145 Type
* field
= get_comp_byIndex(i
)->get_type();
3147 if (jsonattrib
!= NULL
&& jsonattrib
->as_value
) {
3148 // only add the alternative's schema
3149 field
->generate_json_schema(json
, true, true);
3151 // use a JSON object with one key-value pair for each alternative
3152 // the schema is the same as a record's with one field
3153 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3155 json
.put_next_token(JSON_TOKEN_NAME
, "type");
3156 json
.put_next_token(JSON_TOKEN_STRING
, "\"object\"");
3158 json
.put_next_token(JSON_TOKEN_NAME
, "properties");
3159 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3161 // use the alternative's alias if it has one
3162 json
.put_next_token(JSON_TOKEN_NAME
,
3163 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3164 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3166 // let the alternative's type insert its schema
3167 field
->generate_json_schema(json
, true, false);
3169 // continue the schema for the record with one field
3170 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3172 json
.put_next_token(JSON_TOKEN_NAME
, "additionalProperties");
3173 json
.put_next_token(JSON_TOKEN_LITERAL_FALSE
);
3175 // the one field is non-optional
3176 json
.put_next_token(JSON_TOKEN_NAME
, "required");
3177 json
.put_next_token(JSON_TOKEN_ARRAY_START
);
3179 // use the alternative's alias here as well
3180 char* field_str
= mprintf("\"%s\"",
3181 (field
->jsonattrib
!= NULL
&& field
->jsonattrib
->alias
!= NULL
) ?
3182 field
->jsonattrib
->alias
: get_comp_byIndex(i
)->get_name().get_ttcnname().c_str());
3183 json
.put_next_token(JSON_TOKEN_STRING
, field_str
);
3186 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3188 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
3192 // close the "anyOf" array
3193 json
.put_next_token(JSON_TOKEN_ARRAY_END
);
3196 void Type::generate_json_schema_ref(JSON_Tokenizer
& json
)
3198 // start the object containing the reference
3199 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
3201 // insert the reference
3202 json
.put_next_token(JSON_TOKEN_NAME
, "$ref");
3203 char* ref_str
= mprintf("\"#/definitions/%s/%s\"",
3204 my_scope
->get_scope_mod()->get_modid().get_ttcnname().c_str(),
3205 get_dispname().c_str());
3206 json
.put_next_token(JSON_TOKEN_STRING
, ref_str
);
3209 // the object will be closed later, as it may contain other properties
3213 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3215 } // namespace Common