diff --git a/compiler2/Type.cc b/compiler2/Type.cc index bd5d1fc495aea7ea5c1afda2f06b460724905be0..7e2d8bdf1c8ed10573ee96a0bc19ec84abc3d1b8 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -2849,8 +2849,12 @@ namespace Common { if (NULL != jsonattrib->alias) { Type* parent = get_parent_type(); - if (NULL == parent || (T_SEQ_T != parent->typetype && - T_SET_T != parent->typetype && T_CHOICE_T != parent->typetype)) { + if (!legacy_codec_handling && + (NULL == parent || (T_SEQ_T != parent->typetype && + T_SET_T != parent->typetype && T_CHOICE_T != parent->typetype))) { + // only report this error when using the new codec handling, otherwise + // ignore the attribute (since it can also be set by the XML 'name as ...' + // attribute) error("Invalid attribute, 'name as ...' requires field of a " "record, set or union."); } diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index bb0227ceab31ec6071d4faf8a5568a7c9cb9f873..777e7e12cbcb093ce061e76a32e7e975fb9a1bcf 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -965,10 +965,11 @@ void Type::chk_this_variant(const Ttcn::SingleWithAttrib* swa, bool global) } } else { - const string& enc_str = swa->get_attribSpec().get_encoding(); - MessageEncodingType_t coding = get_enc_type(enc_str); + const vector<string>* coding_strings = swa->get_attribSpec().get_encodings(); + // gather the built-in codecs referred to by the variant's encoding strings + vector<MessageEncodingType_t> codings; bool erroneous = false; - if (enc_str.empty()) { + if (coding_strings == NULL) { if (t->coding_table.size() > 1) { if (!global) { swa->error("The encoding reference is mandatory for variant attributes " @@ -977,129 +978,148 @@ void Type::chk_this_variant(const Ttcn::SingleWithAttrib* swa, bool global) erroneous = true; } else if (t->coding_table[0]->built_in) { - coding = t->coding_table[0]->built_in_coding; + codings.add(new MessageEncodingType_t(t->coding_table[0]->built_in_coding)); } - else if (strcmp(t->coding_table[0]->custom_coding.name, "PER") == 0) { - coding = CT_PER; + else { // PER or custom encoding + MessageEncodingType_t coding = + strcmp(t->coding_table[0]->custom_coding.name, "PER") == 0 ? + CT_PER : CT_CUSTOM; + swa->warning("Variant attributes related to %s encoding are ignored", + get_encoding_name(coding)); } - // else leave it as CT_CUSTOM } else { - if (!has_encoding(coding, &enc_str)) { - erroneous = true; - if (!global) { - if (coding != CT_CUSTOM) { - swa->error("Type `%s' does not support %s encoding", - get_typename().c_str(), get_encoding_name(coding)); - } - else { - swa->error("Type `%s' does not support custom encoding `%s'", - get_typename().c_str(), enc_str.c_str()); + for (size_t i = 0; i < coding_strings->size(); ++i) { + const string& enc_str = *(*coding_strings)[i]; + MessageEncodingType_t coding = get_enc_type(enc_str); + if (!has_encoding(coding, &enc_str)) { + erroneous = true; + if (!global) { + if (coding != CT_CUSTOM) { + swa->error("Type `%s' does not support %s encoding", + get_typename().c_str(), get_encoding_name(coding)); + } + else { + swa->error("Type `%s' does not support custom encoding `%s'", + get_typename().c_str(), enc_str.c_str()); + } } } + else if (coding != CT_PER && coding != CT_CUSTOM) { + codings.add(new MessageEncodingType_t(coding)); + } + else { // PER or custom encoding + swa->warning("Variant attributes related to %s encoding are ignored", + get_encoding_name(coding)); + } } } - if (!erroneous && coding != CT_PER && coding != CT_CUSTOM) { - bool new_ber = false; // a BerAST object was allocated here - bool new_raw = false; // a RawAST object was allocated here - bool new_text = false; // a TextAST object was allocated here - bool new_xer = false; // a XerAttribute object was allocated here - bool new_json = false; // a JsonAST object was allocated here - bool ber_found = false; // a BER attribute was found by the parser - bool raw_found = false; // a RAW attribute was found by the parser - bool text_found = false; // a TEXT attribute was found by the parser - bool xer_found = false; // a XER attribute was found by the parser - bool json_found = false; // a JSON attribute was found by the parser - if (berattrib == NULL) { - berattrib = new BerAST; - new_ber = true; - } - if (rawattrib == NULL) { - Type* t_refd = this; - while (t_refd->rawattrib == NULL && t_refd->is_ref()) { - t_refd = t_refd->get_type_refd(); + if (!erroneous && codings.size() != 0) { + for (size_t i = 0; i < codings.size(); ++i) { + MessageEncodingType_t coding = *codings[i]; + bool new_ber = false; // a BerAST object was allocated here + bool new_raw = false; // a RawAST object was allocated here + bool new_text = false; // a TextAST object was allocated here + bool new_xer = false; // a XerAttribute object was allocated here + bool new_json = false; // a JsonAST object was allocated here + bool ber_found = false; // a BER attribute was found by the parser + bool raw_found = false; // a RAW attribute was found by the parser + bool text_found = false; // a TEXT attribute was found by the parser + bool xer_found = false; // a XER attribute was found by the parser + bool json_found = false; // a JSON attribute was found by the parser + if (berattrib == NULL) { + berattrib = new BerAST; + new_ber = true; } - rawattrib = new RawAST(t_refd->rawattrib, get_default_raw_fieldlength()); - new_raw = true; - } - if (textattrib == NULL) { - Type* t_refd = this; - while (t_refd->textattrib == NULL && t_refd->is_ref()) { - t_refd = t_refd->get_type_refd(); + if (rawattrib == NULL) { + Type* t_refd = this; + while (t_refd->rawattrib == NULL && t_refd->is_ref()) { + t_refd = t_refd->get_type_refd(); + } + rawattrib = new RawAST(t_refd->rawattrib, get_default_raw_fieldlength()); + new_raw = true; } - textattrib = new TextAST(t_refd->textattrib); - new_text = true; - } - if (xerattrib == NULL) { - xerattrib = new XerAttributes; - new_xer = true; - } - if (jsonattrib == NULL) { - Type* t_refd = this; - while (t_refd->jsonattrib == NULL && t_refd->is_ref()) { - t_refd = t_refd->get_type_refd(); + if (textattrib == NULL) { + Type* t_refd = this; + while (t_refd->textattrib == NULL && t_refd->is_ref()) { + t_refd = t_refd->get_type_refd(); + } + textattrib = new TextAST(t_refd->textattrib); + new_text = true; } - jsonattrib = new JsonAST(t_refd->jsonattrib); - new_json = true; - } - int ret = parse_rawAST(rawattrib, textattrib, xerattrib, berattrib, jsonattrib, - swa->get_attribSpec(), get_length_multiplier(), my_scope->get_scope_mod(), - raw_found, text_found, xer_found, ber_found, json_found, coding); - bool mismatch = false; - if (ber_found || raw_found || text_found || xer_found || json_found) { - switch (coding) { - case CT_BER: - mismatch = !ber_found; - break; - case CT_RAW: - mismatch = !raw_found; - break; - case CT_TEXT: - mismatch = !text_found; - break; - case CT_XER: - mismatch = !xer_found; - break; - case CT_JSON: - mismatch = !json_found; - break; - default: - FATAL_ERROR("Type::chk_this_variant"); - break; + if (xerattrib == NULL) { + xerattrib = new XerAttributes; + new_xer = true; } - } - if (mismatch && ret == 0) { - if (!global || !enc_str.empty()) { - // don't display this if there were parsing errors in the variant - // attribute, or if it was empty - swa->error("Variant attribute is not related to %s encoding", - get_encoding_name(coding)); + if (jsonattrib == NULL) { + Type* t_refd = this; + while (t_refd->jsonattrib == NULL && t_refd->is_ref()) { + t_refd = t_refd->get_type_refd(); + } + jsonattrib = new JsonAST(t_refd->jsonattrib); + new_json = true; + } + int ret = parse_rawAST(rawattrib, textattrib, xerattrib, berattrib, jsonattrib, + swa->get_attribSpec(), get_length_multiplier(), my_scope->get_scope_mod(), + raw_found, text_found, xer_found, ber_found, json_found, coding); + bool mismatch = false; + if (ber_found || raw_found || text_found || xer_found || json_found) { + switch (coding) { + case CT_BER: + mismatch = !ber_found; + break; + case CT_RAW: + mismatch = !raw_found; + break; + case CT_TEXT: + mismatch = !text_found; + break; + case CT_XER: + mismatch = !xer_found; + break; + case CT_JSON: + mismatch = !json_found; + break; + default: + FATAL_ERROR("Type::chk_this_variant"); + break; + } + } + if (mismatch && ret == 0) { + if (!global || coding_strings != NULL) { + // don't display this if there were parsing errors in the variant + // attribute, or if it didn't have encoding strings + swa->error("Variant attribute is not related to %s encoding", + get_encoding_name(coding)); + } + } + if (new_ber && !ber_found) { + delete berattrib; + berattrib = NULL; + } + if (new_raw && !raw_found) { + delete rawattrib; + rawattrib = NULL; + } + if (new_text && !text_found) { + delete textattrib; + textattrib = NULL; + } + if (new_xer && !xer_found) { + delete xerattrib; + xerattrib = NULL; + } + if (new_json && !json_found) { + delete jsonattrib; + jsonattrib = NULL; } - } - if (new_ber && !ber_found) { - delete berattrib; - berattrib = NULL; - } - if (new_raw && !raw_found) { - delete rawattrib; - rawattrib = NULL; - } - if (new_text && !text_found) { - delete textattrib; - textattrib = NULL; - } - if (new_xer && !xer_found) { - delete xerattrib; - xerattrib = NULL; - } - if (new_json && !json_found) { - delete jsonattrib; - jsonattrib = NULL; } } - else if (!erroneous && !global) { // PER or custom encoding - swa->warning("Variant attributes related to %s encoding are ignored", - get_encoding_name(coding)); + if (codings.size() != 0) { + for (size_t i = 0; i < codings.size(); ++i) { + delete codings[i]; + } + codings.clear(); } } // if t != NULL if (global) { diff --git a/compiler2/ttcn3/Attributes.cc b/compiler2/ttcn3/Attributes.cc index 7629ed47a2f80f3d360e3bec3dcd3d2100c30aaf..1ff202ceb5ea73679e5301c98a2f32758a101d5c 100644 --- a/compiler2/ttcn3/Attributes.cc +++ b/compiler2/ttcn3/Attributes.cc @@ -883,6 +883,17 @@ namespace Ttcn { } // ==== AttributeSpec ==== + + AttributeSpec::~AttributeSpec() + { + if (encodings != NULL) { + for (size_t i = 0; i < encodings->size(); ++i) { + delete (*encodings)[i]; + } + encodings->clear(); + delete encodings; + } + } AttributeSpec* AttributeSpec::clone() const { @@ -897,8 +908,15 @@ namespace Ttcn { void AttributeSpec::dump(unsigned level) const { DEBUG(level,"spec: %s", spec.c_str()); - if (!encoding.empty()) { - DEBUG(level, "encoding: %s", encoding.c_str()); + if (encodings != NULL) { + string res; + for (size_t i = 0; i < encodings->size(); ++i) { + if (i != 0) { + res += ", "; + } + res += *(*encodings)[i]; + } + DEBUG(level, "encoding(s): %s", res.c_str()); } } @@ -1203,7 +1221,7 @@ namespace Ttcn { "attributes. Modifier ignored."); } } - if (!temp_attrib->get_attribSpec().get_encoding().empty() && + if (temp_attrib->get_attribSpec().get_encodings() != NULL && (legacy_codec_handling || temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_VARIANT)) { temp_attrib->error("Invalid attribute format. Dot notation is only " diff --git a/compiler2/ttcn3/Attributes.hh b/compiler2/ttcn3/Attributes.hh index 375383d1513385a4890ef83185e08c6341337284..700eb59f1ffc871265983f9cc95f318876e5628f 100644 --- a/compiler2/ttcn3/Attributes.hh +++ b/compiler2/ttcn3/Attributes.hh @@ -221,7 +221,7 @@ namespace Ttcn { void chk(); ErroneousDescriptor* get_err_descr() const { return err_descr_tree; } }; - + /** * Stores the attribute specification and its location */ @@ -230,20 +230,20 @@ namespace Ttcn { AttributeSpec& operator=(const AttributeSpec& p); private: string spec; ///< The attribute specification (free text) - string encoding; ///< Encoding specification for variant attributes (free text) - // TODO: check that the variant indeed belongs to the specified encoding + vector<string>* encodings; ///< Encoding specifications for variant attributes (free text) /// Copy constructor, for clone() only AttributeSpec(const AttributeSpec& p) - : Node(p), Location(p), spec(p.spec), encoding(p.encoding) { } + : Node(p), Location(p), spec(p.spec), encodings(p.encodings) { } public: AttributeSpec(const string& p_spec) - : Node(), Location(), spec(p_spec), encoding() { } - AttributeSpec(const string& p_spec, const string& p_encoding) - : Node(), Location(), spec(p_spec), encoding(p_encoding) { } + : Node(), Location(), spec(p_spec), encodings(NULL) { } + AttributeSpec(const string& p_spec, vector<string>* p_encodings) + : Node(), Location(), spec(p_spec), encodings(p_encodings) { } + ~AttributeSpec(); virtual AttributeSpec* clone() const; virtual void set_fullname(const string& p_fullname); const string& get_spec() const { return spec; } - const string& get_encoding() const { return encoding; } + const vector<string>* get_encodings() const { return encodings; } virtual void dump(unsigned level) const; }; diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index b91c77073f98faae76bd77af737854fc68482bd4..f396e1040ecaaecef9ef981f7dad69ef7e0ce5cc 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -217,6 +217,7 @@ static const string anyname("anytype"); param_eval_t eval; TypeMappingTargets *typemappingtargets; attribute_modifier_t attrib_mod; + vector<string>* string_vector; struct { bool is_raw; @@ -1130,6 +1131,7 @@ AllOrTypeListWithTo TypeListWithFrom TypeListWithTo %type <single_value_redirect_list> SingleValueSpecList %type <typemappingtargets> WithList %type <reference_list> PortTypeList +%type <string_vector> AttribSpecEncodings /********************************************************************* * Destructors @@ -1490,6 +1492,7 @@ Quadruple AllowedValues optSubTypeSpec seqValueOrRange +AttribSpecEncodings %destructor { for(size_t i=0; i<$$.nElements; i++) delete $$.elements[i]; @@ -8331,11 +8334,34 @@ AttribSpec: // 542 } | FreeText '.' FreeText { - $$ = new AttributeSpec(string($3), string($1)); + vector<string>* v = new vector<string>; + v->add(new string($1)); + $$ = new AttributeSpec(string($3), v); $$->set_location(infile, @$); Free($1); Free($3); } +| '{' AttribSpecEncodings '}' '.' FreeText + { + $$ = new AttributeSpec(string($5), $2); + $$->set_location(infile, @$); + Free($5); + } +; + +AttribSpecEncodings: + FreeText + { + $$ = new vector<string>; + $$->add(new string($1)); + Free($1); + } +| AttribSpecEncodings ',' FreeText + { + $$ = $1; + $$->add(new string($3)); + Free($3); + } ; /* A.1.6.7 Behaviour statements */ diff --git a/compiler2/ttcn3/rawAST.y b/compiler2/ttcn3/rawAST.y index 791b38b787ae4ff46a22fcf463a3b3ed24b466ca..94baf56fc181c788a64c42410e32dbf34d21c4d1 100644 --- a/compiler2/ttcn3/rawAST.y +++ b/compiler2/ttcn3/rawAST.y @@ -1364,7 +1364,7 @@ XERattribute: // this handles the "name as '...' " attributes for both the XER and // JSON codecs // (overwrites any previously set name) - if (selected_codec == Common::Type::CT_XER) { + if (selected_codec == Common::Type::CT_XER || legacy_codec_handling) { switch (xerstruct->name_.kw_) { case NamespaceSpecification::NO_MANGLING: case NamespaceSpecification::CAPITALIZED: @@ -1377,7 +1377,7 @@ XERattribute: } xerstruct->name_.nn_ = $1; } - else { + if (selected_codec != Common::Type::CT_XER) { // treat XML special values and real strings separately XerAttributes::NameChange special; special.nn_ = $1; @@ -1397,9 +1397,17 @@ XERattribute: } break; default: // it's a real string - if (selected_codec == Common::Type::CT_JSON) { + if (selected_codec == Common::Type::CT_JSON || + legacy_codec_handling) { Free(jsonstruct->alias); - jsonstruct->alias = $1; + if (legacy_codec_handling) { + // in this case the string is saved in both the XML and JSON + // structs, so we can't use the same string + jsonstruct->alias = mcopystr($1); + } + else { + jsonstruct->alias = $1; + } json_f = true; } else { diff --git a/regression_test/multipleEncodings/Testcases.ttcn b/regression_test/multipleEncodings/Testcases.ttcn index 260a7dc05f8c3fc7eabb8e2afc554052fc1d9288..599527540f363cdd25de43ecff94f3514700725d 100644 --- a/regression_test/multipleEncodings/Testcases.ttcn +++ b/regression_test/multipleEncodings/Testcases.ttcn @@ -476,6 +476,38 @@ testcase tc_ttcn_codec_switch() runs on CT { setverdict(pass); } +// Testing the 'name as ...' attribute applied to multiple codecs using only one variant attribute +testcase tc_ttcn_multi_attrib() runs on CT { + var S x := { num := 12, str := "abc" }; + + // JSON encoding & decoding + var universal charstring exp := "{\"int\":12,\"str\":\"abc\"}"; + var universal charstring enc1 := encvalue_unichar(x, "UTF-8", "", "JSON"); + if (exp != enc1) { + setverdict(fail, "JSON encoding failed. Expected: ", exp, ", got: ", enc1); + } + + var S dec1; + var integer res := decvalue_unichar(enc1, dec1, "UTF-8", "", "JSON"); + if (x != dec1) { + setverdict(fail, "JSON decoding failed. Expected: ", x, ", got: ", dec1); + } + + // XML encoding & decoding + exp := "<S>\n\t<int>12</int>\n\t<str>abc</str>\n</S>\n\n"; + var universal charstring enc2 := encvalue_unichar(x, "UTF-8", "", "XML"); + if (exp != enc2) { + setverdict(fail, "XML encoding test failed. Expected: ", exp, ", got: ", enc2); + } + + var S dec2; + res := decvalue_unichar(enc2, dec2, "UTF-8", "", "XML"); + if (x != dec2) { + setverdict(fail, "XML decoding test failed. Expected: ", x, ", got: ", dec2); + } + setverdict(pass); +} + control { execute(tc_ttcn_encvalue()); execute(tc_ttcn_encvalue_negtest()); @@ -495,6 +527,7 @@ control { execute(tc_asn_setencode_per()); execute(tc_asn_setencode_negtest()); execute(tc_ttcn_codec_switch()); + execute(tc_ttcn_multi_attrib()); } } diff --git a/regression_test/multipleEncodings/TtcnTypes.ttcn b/regression_test/multipleEncodings/TtcnTypes.ttcn index cfee27c6ccc1c1e0b397c3c07dcbab10d24011fd..aa2b8cc34d526cc66c53293503a3f2257609e139 100644 --- a/regression_test/multipleEncodings/TtcnTypes.ttcn +++ b/regression_test/multipleEncodings/TtcnTypes.ttcn @@ -56,6 +56,16 @@ with { encode "JSON"; } +type set S { + integer num, + charstring str +} +with { + encode "JSON"; + encode "XML"; + variant (num) {"JSON", "XML"}."name as 'int'"; +} + type record Msg { bitstring data }