diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 1f9f95a549d4dd385b6741ce6ef0dbc0ebdb4ecc..7ec627cf7e879831e34e0e8086eb52da90d500f1 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -61,7 +61,7 @@ extern Ttcn::ExtensionAttributes * parse_extattributes( namespace Common { - map<Type*, void> Type::CodingCheckTracker::types; + map<Type*, void> Type::RecursionTracker::types; using Ttcn::MultiWithAttrib; using Ttcn::SingleWithAttrib; @@ -615,6 +615,7 @@ namespace Common { default_encoding.type = CODING_UNSET; default_decoding.type = CODING_UNSET; checked_incorrect_field = false; + encode_attrib_mod_conflict = false; } void Type::clean_up() @@ -1216,6 +1217,11 @@ namespace Common { Type::truth Type::is_charenc() { + // this helps avoid infinite recursions in self-referencing types + if (RecursionTracker::is_happening(this)) { + return Maybe; + } + RecursionTracker tracker(this); switch(typetype) { case T_CHOICE_A: case T_CHOICE_T: @@ -3265,12 +3271,17 @@ namespace Common { } } - void Type::add_coding(const string& name, bool silent) + void Type::add_coding(const string& name, Ttcn::attribute_modifier_t modifier, bool silent) { if (legacy_codec_handling) { FATAL_ERROR("Type::add_coding"); } for (size_t i = 0; i < coding_table.size(); ++i) { + if (!encode_attrib_mod_conflict && modifier != coding_table[i]->modifier) { + encode_attrib_mod_conflict = true; + error("All 'encode' attributes of a type must have the same modifier " + "('override', '@local' or none)"); + } const char* coding_name = coding_table[i]->built_in ? get_encoding_name(coding_table[i]->built_in_coding) : coding_table[i]->custom_coding.name; @@ -3283,6 +3294,7 @@ namespace Common { if (get_type_refd_last()->can_have_coding(built_in_coding)) { coding_t* new_coding = new coding_t; new_coding->built_in = TRUE; + new_coding->modifier = modifier; new_coding->built_in_coding = built_in_coding; coding_table.add(new_coding); get_type_refd_last()->set_gen_coder_functions(built_in_coding); @@ -3297,6 +3309,7 @@ namespace Common { else { coding_t* new_coding = new coding_t; new_coding->built_in = FALSE; + new_coding->modifier = modifier; new_coding->custom_coding.name = mcopystr(name.c_str()); new_coding->custom_coding.encoders = new map<Type*, coder_function_t>; new_coding->custom_coding.decoders = new map<Type*, coder_function_t>; @@ -3380,35 +3393,72 @@ namespace Common { return NULL; // not found } - Type* Type::get_type_w_coding_table() + Type* Type::get_type_w_coding_table(bool ignore_local /* = false */) { - // only return the type if it has a non-empty coding table - if (coding_table.size() != 0) { + // 1st priority: if local attributes are not ignored, and if the type + // has its own 'encode' attributes (its coding table is not empty), then + // return the type + if (!ignore_local && coding_table.size() != 0) { return this; } - // first, check referenced types + + // 2nd priority: if this is a field or element type, and one of its parents + // has an 'encode' attribute with the 'override' modifier, then return the + // parent type + Type* t_parent = NULL; + if (parent_type != NULL && (ownertype == OT_COMP_FIELD || + ownertype == OT_RECORD_OF || ownertype == OT_ARRAY)) { + // note: if one of the parent types has an overriding 'encode' attribute, + // then this returns the furthest parent with an overriding 'encode'; + // if none of the 'encode' attributes are overriding, then the nearest + // parent with at least one 'encode' attribute is returned + t_parent = parent_type->get_type_w_coding_table(true); + } + if (t_parent != NULL) { + for (size_t i = 0; i < t_parent->coding_table.size(); ++i) { + if (t_parent->coding_table[i]->modifier == Ttcn::MOD_OVERRIDE) { + return t_parent; + } + } + } + + // 3rd priority: if local attributes are ignored, and if the type has its + // own (non-local) 'encode' attributes, then return the type + if (ignore_local && coding_table.size() != 0) { + bool local = false; + for (size_t i = 0; i < coding_table.size(); ++i) { + if (coding_table[i]->modifier == Ttcn::MOD_LOCAL) { + local = true; + break; + } + } + if (!local) { + return this; + } + } + + // 4th priority, if a referenced type has an 'encode' attribute, then return + // the referenced type if (is_ref()) { - Type* t = get_type_refd()->get_type_w_coding_table(); + // note: this always returns the nearest referenced type with at least one + // 'encode' attribute + Type* t = get_type_refd()->get_type_w_coding_table(false); if (t != NULL) { return t; } } - // second, check the parent type if this is a field or element type - if (parent_type != NULL && (ownertype == OT_COMP_FIELD || - ownertype == OT_RECORD_OF || ownertype == OT_ARRAY)) { - return parent_type->get_type_w_coding_table(); - } - // if none of the above have a non-empty coding table, then return null - return NULL; + + // otherwise return the parent type pointer (whether it's null or not) + return t_parent; } bool Type::can_have_coding(MessageEncodingType_t coding) { // this helps avoid infinite recursions in self-referencing types - if (CodingCheckTracker::is_happening(this)) { + if (RecursionTracker::is_happening(this)) { return true; } - CodingCheckTracker tracker(this); + RecursionTracker tracker(this); // check whether the codec has been disabled by a compiler option or by // the license diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 5cc3364f0761a1fa2dbe11679332e82ba61eabbb..b58bd84233ccb964cccb1500d373ac51bdeda6c3 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -76,6 +76,13 @@ namespace Ttcn { class PortTypeBody; class Def_Type; class Ref_pard; + + /** Stores the modifier of an attribute */ + enum attribute_modifier_t { + MOD_NONE, ///< no modifier + MOD_OVERRIDE, ///< 'override' modifier + MOD_LOCAL ///< '@local' modifier + }; } // namespace Ttcn // not defined here @@ -303,6 +310,7 @@ namespace Common { * codec handling. */ struct coding_t { boolean built_in; ///< built-in or user defined codec + Ttcn::attribute_modifier_t modifier; ///< the 'encode' attribute's modifier union { MessageEncodingType_t built_in_coding; ///< built-in codec struct { @@ -478,14 +486,18 @@ namespace Common { * method. */ vector<MessageEncodingType_t> coders_to_generate; - /** Helper class that tracks the execution of a type's 'can_have_coding' - * function to prevent infinite recursions. */ - class CodingCheckTracker { + /** Indicates whether an 'encode' attribute modifier conflict error has + * already been displayed for the type. */ + bool encode_attrib_mod_conflict; + + /** Helper class that tracks the execution of recursive functions in the + * Type class in order to prevent infinite recursions. */ + class RecursionTracker { static map<Type*, void> types; Type* key; public: - CodingCheckTracker(Type* t): key(t) { types.add(t, NULL); } - ~CodingCheckTracker() { types.erase(key); } + RecursionTracker(Type* t): key(t) { types.add(t, NULL); } + ~RecursionTracker() { types.erase(key); } static bool is_happening(Type* t) { return types.has_key(t); } }; @@ -512,6 +524,13 @@ namespace Common { static void destroy_pooltypes(); /** Returns the TTCN-3 equivalent of \a p_tt. */ static typetype_t get_typetype_ttcn3(typetype_t p_tt); + + /** Fills the list parameter with the types that have an empty coding table. + * The types considered are the type itself and its field and element types. + * Recursive. + * @param only_own_table if true, then only the type's own coding table is + * checked, otherwise inherited coding tables are also checked */ + void get_types_w_no_coding_table(vector<Type>& type_list, bool only_own_table); public: /** @name Constructors @@ -652,7 +671,7 @@ namespace Common { * if the type can have that encoding. * @param name name of the encoding as it appears in the 'encode' attribute; * this may be the name of a built-in or a user-defined encoding */ - void add_coding(const string& name, bool silent); + void add_coding(const string& name, Ttcn::attribute_modifier_t modifier, bool silent); /** Sets the encoder or decoder function for the user-defined encoding with * the specified name (when using new codec handling). */ @@ -666,8 +685,10 @@ namespace Common { /** Returns the type that contains this type's coding table (since types * with no 'encode' attributes of their own inherit the 'encode' attributes * of a referenced type or a parent type). + * @param ignore_local indicates whether to ignore attributes with the + * '@local' modifier * Only used with new codec handling. */ - Type* get_type_w_coding_table(); + Type* get_type_w_coding_table(bool ignore_local = false); const vector<coding_t>& get_coding_table() const { return coding_table; } diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 0b760a2a5cc0d2c04709dbe6a864534e8b6a0c77..fdb15d224c5c7d14aa887643f2a599f3f00fbeaa 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -338,7 +338,7 @@ void Type::parse_attributes() // see if there's an encode with override for(size_t i = real_attribs.size(); i > 0 && !override_ref; i--) { - if(real_attribs[i-1]->has_override() + if(real_attribs[i-1]->get_modifier() == Ttcn::MOD_OVERRIDE && real_attribs[i-1]->get_attribKeyword() != SingleWithAttrib::AT_ENCODE) override_ref = true; @@ -491,7 +491,7 @@ void Type::parse_attributes() // Copy the attribute without qualifiers const SingleWithAttrib* swaref = self_attribs->get_element(i); swa = new SingleWithAttrib(swaref->get_attribKeyword(), - swaref->has_override(), 0, swaref->get_attribSpec().clone()); + swaref->get_modifier(), 0, swaref->get_attribSpec().clone()); new_self_attribs->add_element(swa); } } @@ -558,7 +558,7 @@ void Type::parse_attributes() // A copy of temp_single, with new qualifiers SingleWithAttrib* temp_single2 = new SingleWithAttrib(temp_single->get_attribKeyword(), - temp_single->has_override(), + temp_single->get_modifier(), calculated_qualifiers, temp_single->get_attribSpec().clone()); temp_single2->set_location(*temp_single); @@ -670,6 +670,37 @@ void change_name(string &name, XerAttributes::NameChange change) { } // switch for NAME } +void Type::get_types_w_no_coding_table(vector<Type>& type_list, bool only_own_table) +{ + // this helps avoid infinite recursions in self-referencing types + if (RecursionTracker::is_happening(this)) { + return; + } + RecursionTracker tracker(this); + if ((only_own_table && coding_table.size() == 0) || + (!only_own_table && get_type_w_coding_table() == NULL)) { + type_list.add(this); + } + switch (get_typetype_ttcn3()) { + case T_SEQ_T: + case T_SET_T: + case T_CHOICE_T: + case T_ANYTYPE: + case T_OPENTYPE: + for (size_t j = 0; j < get_nof_comps(); ++j) { + get_comp_byIndex(j)->get_type()->get_types_w_no_coding_table(type_list, only_own_table); + } + break; + case T_SEQOF: + case T_SETOF: + case T_ARRAY: + get_ofType()->get_types_w_no_coding_table(type_list, only_own_table); + break; + default: + break; + } +} + void Type::chk_encodings() { if (legacy_codec_handling) { @@ -703,6 +734,7 @@ void Type::chk_encodings() for (size_t i = 0; i < mwa->get_nof_elements(); ++i) { const SingleWithAttrib* swa = mwa->get_element(i); if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE) { + Ttcn::attribute_modifier_t mod = swa->get_modifier(); Ttcn::Qualifiers* quals = swa->get_attribQualifiers(); if (quals != NULL && quals->get_nof_qualifiers() != 0) { for (size_t j = 0; j < quals->get_nof_qualifiers(); ++j) { @@ -715,26 +747,75 @@ void Type::chk_encodings() "refers to a type from a different type definition"); } else { - t->add_coding(swa->get_attribSpec().get_spec(), false); + t->add_coding(swa->get_attribSpec().get_spec(), mod, false); } } } } else { - add_coding(swa->get_attribSpec().get_spec(), false); + add_coding(swa->get_attribSpec().get_spec(), mod, false); } } } } - if (get_type_w_coding_table() == NULL) { - // if there are no 'encode' attributes in this type, the referenced - // types, or the parent type, then try the nearest group or the module - const vector<SingleWithAttrib>& real = ap->get_real_attrib(); + WithAttribPath* global_ap = NULL; + Ttcn::Def_Type* def = static_cast<Ttcn::Def_Type*>(owner); + Ttcn::Group* nearest_group = def->get_parent_group(); + + if (nearest_group != NULL) { // there is a group + global_ap = nearest_group->get_attrib_path(); + } + else { // no group, use the module + Common::Module* mymod = my_scope->get_scope_mod(); + // OT_TYPE_DEF is always from a TTCN-3 module + Ttcn::Module* my_ttcn_module = static_cast<Ttcn::Module *>(mymod); + global_ap = my_ttcn_module->get_attrib_path(); + } + if (global_ap != NULL) { + bool has_global_override = false; + bool modifier_conflict = false; + Ttcn::attribute_modifier_t first_mod = Ttcn::MOD_NONE; + const vector<SingleWithAttrib>& real = global_ap->get_real_attrib(); for (size_t i = 0; i < real.size(); ++i) { const SingleWithAttrib* swa = real[i]; if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE) { - add_coding(swa->get_attribSpec().get_spec(), true); + Ttcn::attribute_modifier_t mod = swa->get_modifier(); + if (i == 0) { + first_mod = mod; + } + else if (!modifier_conflict && mod != first_mod) { + modifier_conflict = true; + swa->error("All 'encode' attributes of a group or module must " + "have the same modifier ('override', '@local' or none)"); + } + if (mod == Ttcn::MOD_OVERRIDE) { + has_global_override = true; + } + if (has_global_override && modifier_conflict) { + break; + } + } + } + // make a list of the type and its field and element types that inherit + // the global 'encode' attributes + // overriding global attributes are inherited by types with no coding + // table (no 'encode' attributes) of their own + // non-overriding global attributes are inherited by types that have + // no coding table of their own and cannot use the coding table of any + // other type (get_type_w_coding_table() == NULL) + vector<Type> type_list; + get_types_w_no_coding_table(type_list, has_global_override); + if (type_list.size() != 0) { + for (size_t i = 0; i < real.size(); ++i) { + const SingleWithAttrib* swa = real[i]; + if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE) { + for (size_t j = 0; j < type_list.size(); ++j) { + type_list[j]->add_coding(swa->get_attribSpec().get_spec(), + Ttcn::MOD_NONE, true); + } + } } + type_list.clear(); } } } @@ -746,12 +827,12 @@ void Type::chk_encodings() case OT_COMP_FIELD: case OT_SELTYPE: // ASN.1 types automatically have BER, PER, XER and JSON encoding - add_coding(string("BER:2002"), true); - add_coding(string(get_encoding_name(CT_PER)), true); - add_coding(string(get_encoding_name(CT_JSON)), true); + add_coding(string("BER:2002"), Ttcn::MOD_NONE, true); + add_coding(string(get_encoding_name(CT_PER)), Ttcn::MOD_NONE, true); + add_coding(string(get_encoding_name(CT_JSON)), Ttcn::MOD_NONE, true); if (asn1_xer) { // XER encoding for ASN.1 types can be disabled with a command line option - add_coding(string(get_encoding_name(CT_XER)), true); + add_coding(string(get_encoding_name(CT_XER)), Ttcn::MOD_NONE, true); } break; default: diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 6ff1c4401d6c9f066906b6d059e9363f39981f82..e85cda8ad804e88408fbd1dcd2429e3839cb648e 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -6848,26 +6848,28 @@ namespace Ttcn { // First collect the fields of a record, set, union type which // does not support the encoding, then write it in the error message. char* message = NULL; - Type *t = input_type; - if (t->is_ref()) t = t->get_type_refd(); - switch(t->get_typetype()) { - case Type::T_SEQ_T: - case Type::T_SET_T: - case Type::T_CHOICE_T: { - for (size_t i = 0; i < t->get_nof_comps(); i++) { - if (!t->get_comp_byIndex(i)->get_type()->has_encoding(encoding_type, encoding_options)) { - if (i == 0) { - message = mputprintf(message, " The following fields do not support %s encoding: ", - Type::get_encoding_name(encoding_type)); - } else { - message = mputstr(message, ", "); + if (legacy_codec_handling) { + Type *t = input_type; + if (t->is_ref()) t = t->get_type_refd(); + switch(t->get_typetype()) { + case Type::T_SEQ_T: + case Type::T_SET_T: + case Type::T_CHOICE_T: { + for (size_t i = 0; i < t->get_nof_comps(); i++) { + if (!t->get_comp_byIndex(i)->get_type()->has_encoding(encoding_type, encoding_options)) { + if (i == 0) { + message = mputprintf(message, " The following fields do not support %s encoding: ", + Type::get_encoding_name(encoding_type)); + } else { + message = mputstr(message, ", "); + } + message = mputstr(message, t->get_comp_id_byIndex(i).get_ttcnname().c_str()); } - message = mputstr(message, t->get_comp_id_byIndex(i).get_ttcnname().c_str()); } - } - break; } - default: - break; + break; } + default: + break; + } } input_type->error("Input type `%s' does not support %s encoding.%s", input_type->get_typename().c_str(), diff --git a/compiler2/ttcn3/Attributes.cc b/compiler2/ttcn3/Attributes.cc index 4614bbdfd88f16f33d64286e792098e227c603f6..61f8159748ef3565667d941ce3291ae69fe60743 100644 --- a/compiler2/ttcn3/Attributes.cc +++ b/compiler2/ttcn3/Attributes.cc @@ -905,17 +905,17 @@ namespace Ttcn { SingleWithAttrib::SingleWithAttrib(const SingleWithAttrib& p) : Node(p), Location(p), attribKeyword(p.attribKeyword), - hasOverride(p.hasOverride) + modifier(p.modifier) { attribQualifiers = p.attribQualifiers ? p.attribQualifiers->clone() : 0; attribSpec = p.attribSpec->clone(); } SingleWithAttrib::SingleWithAttrib( - attribtype_t p_attribKeyword, bool p_hasOverride, + attribtype_t p_attribKeyword, attribute_modifier_t p_modifier, Qualifiers *p_attribQualifiers, AttributeSpec* p_attribSpec) : Node(), Location(), attribKeyword(p_attribKeyword), - hasOverride(p_hasOverride), attribQualifiers(p_attribQualifiers), + modifier(p_modifier), attribQualifiers(p_attribQualifiers), attribSpec(p_attribSpec) { if(!p_attribSpec) @@ -971,7 +971,8 @@ namespace Ttcn { FATAL_ERROR("SingleWithAttrib::dump()"); } - DEBUG(level + 1, hasOverride ? "has override" : "hasn't got override"); + DEBUG(level + 1, "modifier: %s", modifier == MOD_NONE ? "none" : + (modifier == MOD_OVERRIDE ? "override" : "@local")); if(attribSpec) attribSpec->dump(level + 1); @@ -1045,7 +1046,8 @@ namespace Ttcn { WithAttribPath::WithAttribPath(const WithAttribPath& p) : Node(p), had_global_variants(false), attributes_checked(false), - cached(false), s_o_encode(false), parent(p.parent) + global_attrib_checked(false), cached(false), s_o_encode(false), + parent(p.parent) { m_w_attrib = p.m_w_attrib ? p.m_w_attrib->clone() : 0; } @@ -1131,7 +1133,7 @@ namespace Ttcn { */ void WithAttribPath::chk_global_attrib(bool erroneous_allowed) { - if(!m_w_attrib) + if(!m_w_attrib || global_attrib_checked) return; if (!erroneous_allowed) { @@ -1177,7 +1179,7 @@ namespace Ttcn { break; case SingleWithAttrib::AT_ERRONEOUS: { - if (temp_attrib->has_override()) { + if (temp_attrib->get_modifier() == MOD_OVERRIDE) { temp_attrib->error("Override cannot be used with erroneous"); } } @@ -1190,6 +1192,22 @@ namespace Ttcn { for(size_t i = 0; i < m_w_attrib->get_nof_elements();) { const SingleWithAttrib* const temp_attrib = m_w_attrib->get_element(i); + if (temp_attrib->get_modifier() == MOD_LOCAL) { + if (legacy_codec_handling) { + temp_attrib->error("The '@local' modifier cannot be used with legacy " + "codec handling"); + } + else if (temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_ENCODE) { + temp_attrib->warning("The '@local' modifier only affects 'encode' " + "attributes. Modifier ignored."); + } + } + if (!temp_attrib->get_attribSpec().get_encoding().empty() && + (legacy_codec_handling || + temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_VARIANT)) { + temp_attrib->error("Invalid attribute format. Dot notation is only " + "allowed for variant attributes when using the new codec handling."); + } switch(temp_attrib->get_attribKeyword()) { case SingleWithAttrib::AT_VARIANT: @@ -1200,7 +1218,7 @@ namespace Ttcn { " variant of the with statement will have effect"); m_w_attrib->delete_element(i); }else{ - if(temp_attrib->has_override()) + if(temp_attrib->get_modifier() == MOD_OVERRIDE) has_override_variant = true; i++; } @@ -1214,7 +1232,7 @@ namespace Ttcn { " display of the with statement will have effect"); m_w_attrib->delete_element(i); }else{ - if(temp_attrib->has_override()) + if(temp_attrib->get_modifier() == MOD_OVERRIDE) has_override_display = true; i++; } @@ -1228,7 +1246,7 @@ namespace Ttcn { " extension of the with statement will have effect"); m_w_attrib->delete_element(i); }else{ - if(temp_attrib->has_override()) + if(temp_attrib->get_modifier() == MOD_OVERRIDE) has_override_extension = true; i++; } @@ -1248,7 +1266,7 @@ namespace Ttcn { " optional of the with statement will have effect"); m_w_attrib->delete_element(i); }else{ - if(temp_attrib->has_override()) + if(temp_attrib->get_modifier() == MOD_OVERRIDE) has_override_optional = true; i++; } @@ -1259,6 +1277,7 @@ namespace Ttcn { break; } // switch } // next i + global_attrib_checked = true; } void WithAttribPath::set_with_attr(MultiWithAttrib* p_m_w_attr) @@ -1266,6 +1285,7 @@ namespace Ttcn { if(m_w_attrib) FATAL_ERROR("WithAttribPath::set_with_attr()"); m_w_attrib = p_m_w_attr; attributes_checked = false; + global_attrib_checked = false; } /** @@ -1370,7 +1390,7 @@ namespace Ttcn { { case SingleWithAttrib::AT_ENCODE: par_has_encode = true; - par_has_override_encode |= act_single->has_override(); + par_has_override_encode |= act_single->get_modifier() == MOD_OVERRIDE; if(self_encode_index != -1) { // We also have an encode. See if they differ. @@ -1381,16 +1401,16 @@ namespace Ttcn { break; case SingleWithAttrib::AT_VARIANT: - par_has_override_variant |= act_single->has_override(); + par_has_override_variant |= act_single->get_modifier() == MOD_OVERRIDE; break; case SingleWithAttrib::AT_DISPLAY: - par_has_override_display |= act_single->has_override(); + par_has_override_display |= act_single->get_modifier() == MOD_OVERRIDE; break; case SingleWithAttrib::AT_EXTENSION: - par_has_override_extension |= act_single->has_override(); + par_has_override_extension |= act_single->get_modifier() == MOD_OVERRIDE; break; case SingleWithAttrib::AT_OPTIONAL: - par_has_override_optional |= act_single->has_override(); + par_has_override_optional |= act_single->get_modifier() == MOD_OVERRIDE; break; case SingleWithAttrib::AT_ERRONEOUS: case SingleWithAttrib::AT_INVALID: diff --git a/compiler2/ttcn3/Attributes.hh b/compiler2/ttcn3/Attributes.hh index eb2a6a991ed716b232b74632d5d945348cc7b8fb..375383d1513385a4890ef83185e08c6341337284 100644 --- a/compiler2/ttcn3/Attributes.hh +++ b/compiler2/ttcn3/Attributes.hh @@ -267,21 +267,21 @@ namespace Ttcn { }; private: attribtype_t attribKeyword; - /// True if the \c override keyword was used - bool hasOverride; + /// Attribute modifier ('override', '@local' or none) + attribute_modifier_t modifier; /// The stuff in parenthesis before the attribute text. Owned. Qualifiers *attribQualifiers; /// The attribute text (FreeText). Owned. AttributeSpec* attribSpec; public: - SingleWithAttrib(attribtype_t p_attribKeyword, bool p_hasOverride, + SingleWithAttrib(attribtype_t p_attribKeyword, attribute_modifier_t p_modifier, Qualifiers *p_attribQualifiers, AttributeSpec *p_attribSpec); ~SingleWithAttrib(); virtual SingleWithAttrib* clone() const; virtual void set_fullname(const string& p_fullname); attribtype_t get_attribKeyword() const{ return attribKeyword; } - bool has_override() const { return hasOverride; } + attribute_modifier_t get_modifier() const { return modifier; } AttributeSpec const& get_attribSpec() const { return *attribSpec; } Qualifiers *get_attribQualifiers() const { return attribQualifiers; } virtual void dump(unsigned level) const; @@ -333,6 +333,7 @@ namespace Ttcn { private: bool had_global_variants; bool attributes_checked; + bool global_attrib_checked; bool cached; bool s_o_encode; WithAttribPath* parent; @@ -343,8 +344,8 @@ namespace Ttcn { bool& stepped_over_encode); public: WithAttribPath() : Node(), had_global_variants(false), - attributes_checked(false), cached(false), s_o_encode(false), - parent(0), m_w_attrib(0) { } + attributes_checked(false), global_attrib_checked(false), cached(false), + s_o_encode(false), parent(0), m_w_attrib(0) { } ~WithAttribPath(); virtual WithAttribPath* clone() const; virtual void set_fullname(const string& p_fullname); diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l index 852036dddfb5b3adcd71353b96b01bde42278c61..6035603516d76799e2664d11e6405e8f0680ef31 100644 --- a/compiler2/ttcn3/compiler.l +++ b/compiler2/ttcn3/compiler.l @@ -526,6 +526,7 @@ xor4b RETURN(Xor4bKeyword); "@deterministic" RETURN(DeterministicKeyword); "@fuzzy" RETURN(FuzzyKeyword); "@index" RETURN(IndexKeyword); +"@local" RETURN(LocalKeyword); /* special TITAN specific keywords */ diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 58b2c56322ae0e9e9cc9a04ae113ac4c4eea35da..0d828c19d6a0b7e9c6ceddbb5e1098c6a9c7b67a 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -216,6 +216,7 @@ static const string anyname("anytype"); SingleValueRedirect* single_value_redirect; param_eval_t eval; TypeMappingTargets *typemappingtargets; + attribute_modifier_t attrib_mod; struct { bool is_raw; @@ -791,6 +792,7 @@ static const string anyname("anytype"); %token DeterministicKeyword %token FuzzyKeyword %token IndexKeyword +%token LocalKeyword /* TITAN specific keywords */ %token TitanSpecificTryKeyword @@ -922,7 +924,7 @@ static const string anyname("anytype"); * Semantic types of nonterminals *********************************************************************/ -%type <bool_val> optAliveKeyword optOptionalKeyword optOverrideKeyword +%type <bool_val> optAliveKeyword optOptionalKeyword optErrValueRaw optAllKeyword optDeterministicModifier %type <str> FreeText optLanguageSpec PatternChunk PatternChunkList %type <uchar_val> Group Plane Row Cell @@ -935,6 +937,7 @@ static const string anyname("anytype"); %type <typetype> PredefinedType %type <portoperationmode> PortOperationMode %type <operationtype> PredefinedOpKeyword1 PredefinedOpKeyword2 PredefinedOpKeyword3 +%type <attrib_mod> optAttributeModifier %type <activateop> ActivateOp %type <attribtype> AttribKeyword @@ -8165,7 +8168,7 @@ MultiWithAttrib: // 529 ; SingleWithAttrib: // 530 - AttribKeyword optOverrideKeyword optAttribQualifier AttribSpec + AttribKeyword optAttributeModifier optAttribQualifier AttribSpec { $$ = new SingleWithAttrib($1,$2,$3,$4); $$->set_location(infile, @$); @@ -8202,9 +8205,10 @@ AttribKeyword: // 531 } ; -optOverrideKeyword: // [536] - /* empty */ { $$ = false; } -| OverrideKeyword { $$ = true; } +optAttributeModifier: // [536] + /* empty */ { $$ = MOD_NONE; } +| OverrideKeyword { $$ = MOD_OVERRIDE; } +| LocalKeyword { $$ = MOD_LOCAL; } ; optAttribQualifier: // [537] @@ -8315,15 +8319,8 @@ AttribSpec: // 542 } | FreeText '.' FreeText { - if (legacy_codec_handling) { - Location loc(infile, @$); - loc.error("Invalid attribute format. Dot notation is only allowed for " - "variant attributes when using legacy codec handling."); - } - else { - $$ = new AttributeSpec(string($3), string($1)); - $$->set_location(infile, @$); - } + $$ = new AttributeSpec(string($3), string($1)); + $$->set_location(infile, @$); Free($1); Free($3); } diff --git a/function_test/Semantic_Analyser/Makefile.semantic b/function_test/Semantic_Analyser/Makefile.semantic index 9d22c6583214b6f9afda94a9b586f186561bfb78..5f3a543ebb7fdfe6b8d1ab328e36d4b14c694bed 100644 --- a/function_test/Semantic_Analyser/Makefile.semantic +++ b/function_test/Semantic_Analyser/Makefile.semantic @@ -12,6 +12,8 @@ # Szabo, Bence Janos # ############################################################################## +include ../../Makefile.personal + SADIRS := ver param template any_from pattern_ref float recof_index \ port_translation mtc_and_system_clause port_map_connect deterministic ifdef RT2 diff --git a/function_test/Semantic_Analyser/common.mk b/function_test/Semantic_Analyser/common.mk index 558c5f1d86a7494bc0e62919397afecabef1a3a8..d7aa71e0236d9a57604e4a7910fc43c755378a21 100644 --- a/function_test/Semantic_Analyser/common.mk +++ b/function_test/Semantic_Analyser/common.mk @@ -21,11 +21,6 @@ ifdef RT2 COMPILER_FLAGS += -R endif -# Use the legacy handling of 'encode' and 'variant' in tests. -ifdef LEGACY_CODEC_HANDLING -COMPILER_FLAGS += -e -endif - # TTCN-3 modules of this project: TTCN3_MODULES := $(sort $(wildcard *A.ttcn *S[WE].ttcn *OK.ttcn)) @@ -66,6 +61,11 @@ ifeq ($(DEBUG), yes) CPPFLAGS += -DMEMORY_DEBUG endif +# Use the legacy handling of 'encode' and 'variant' attributes in tests. +ifdef LEGACY_CODEC_HANDLING +COMPILER_FLAGS += -e +endif + # # Rules for building the executable... # diff --git a/function_test/Semantic_Analyser/encode/encode_modifier_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_modifier_SE.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..7fcc0edcb5491bdd7c6575730082ab8ece170e66 --- /dev/null +++ b/function_test/Semantic_Analyser/encode/encode_modifier_SE.ttcn @@ -0,0 +1,178 @@ +/****************************************************************************** + * Copyright (c) 2000-2017 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +module encode_modifier { //^In TTCN-3 module// + +type enumerated Enum { x1, x2 } +with { + encode "RAW"; +} + +type record of integer RoI; + +group Grp1 { + +group Grp2 { + +type record Rec { + Enum en, + RoI list +} +with { + encode "XML"; +} + +} /* Grp2 */ +with { + encode "TEXT"; +} + +} /* Grp1 */ +with { + encode override "JSON"; +} + +type union Uni { + Enum en, + Rec.list list +} +with { + encode override "TEXT"; +} + +group Grp3 { + +type set of octetstring SoOS +with { + encode @local "RAW"; +} + +type set Set { + SoOS octs, + RoI ints +} +with { + encode @local "JSON"; +} + +} /* Grp3 */ +with { + encode "XML"; +} + +external function f_enc_rec1(in Rec x) return octetstring + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; +external function f_enc_rec2(in Rec x) return charstring //^In external function definition// //does not support TEXT encoding// + with { extension "prototype(convert) encode(TEXT)" }; +external function f_enc_rec3(in Rec x) return octetstring //^In external function definition// //does not support JSON encoding// + with { extension "prototype(convert) encode(JSON)" }; + +external function f_enc_rec_en1(in Rec.en x) return octetstring //^In external function definition// //does not support RAW encoding// + with { extension "prototype(convert) encode(RAW)" }; +external function f_enc_rec_en2(in Rec.en x) return octetstring //^In external function definition// //does not support XER encoding// + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; +external function f_enc_rec_en3(in Rec.en x) return charstring //^In external function definition// //does not support TEXT encoding// + with { extension "prototype(convert) encode(TEXT)" }; +external function f_enc_rec_en4(in Rec.en x) return octetstring + with { extension "prototype(convert) encode(JSON)" }; + +external function f_enc_rec_list1(in Rec.list x) return octetstring //^In external function definition// //does not support XER encoding// + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; +external function f_enc_rec_list2(in Rec.list x) return charstring //^In external function definition// //does not support TEXT encoding// + with { extension "prototype(convert) encode(TEXT)" }; +external function f_enc_rec_list3(in Rec.list x) return octetstring + with { extension "prototype(convert) encode(JSON)" }; + +external function f_enc_uni_en1(in Uni.en x) return octetstring //^In external function definition// //does not support RAW encoding// + with { extension "prototype(convert) encode(RAW)" }; +external function f_enc_uni_en2(in Uni.en x) return charstring + with { extension "prototype(convert) encode(TEXT)" }; + +external function f_enc_uni_list1(in Uni.list x) return octetstring //^In external function definition// //does not support XER encoding// + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; +external function f_enc_uni_list2(in Uni.list x) return octetstring //^In external function definition// //does not support JSON encoding// + with { extension "prototype(convert) encode(JSON)" }; +external function f_enc_uni_list3(in Uni.list x) return charstring + with { extension "prototype(convert) encode(TEXT)" }; + +external function f_enc_set1(in Set x) return octetstring + with { extension "prototype(convert) encode(JSON)" }; +external function f_enc_set2(in Set x) return octetstring //^In external function definition// //does not support XER encoding// + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; + +external function f_enc_set_octs1(in Set.octs x) return octetstring + with { extension "prototype(convert) encode(RAW)" }; +external function f_enc_set_octs2(in Set.octs x) return octetstring //^In external function definition// //does not support JSON encoding// + with { extension "prototype(convert) encode(JSON)" }; +external function f_enc_set_octs3(in Set.octs x) return octetstring //^In external function definition// //does not support XER encoding// + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; + +external function f_enc_set_ints1(in Set.ints x) return octetstring //^In external function definition// //does not support JSON encoding// + with { extension "prototype(convert) encode(JSON)" }; +external function f_enc_set_ints2(in Set.ints x) return octetstring + with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; + + +type record MixedModifiersInType { //^In type definition// //All 'encode' attributes of a type must have the same modifier// + integer f1, //All 'encode' attributes of a type must have the same modifier// + charstring f2 //All 'encode' attributes of a type must have the same modifier// +} +with { + encode "RAW"; + encode @local "JSON"; + encode override (f1) "RAW"; + encode (f1) "JSON"; + encode @local (f2) "RAW"; + encode override (f2) "JSON"; +} + +group MixedModifiersInGroup1 { + type record of integer DummyList; //^In type definition// +} +with { + encode @local "TEXT"; //All 'encode' attributes of a group or module must have the same modifier// + encode "XML"; +} + +group MixedModifiersInGroup2 { + type record DummyRecord { integer f }; //^In type definition// +} +with { + encode "TEXT"; //All 'encode' attributes of a group or module must have the same modifier// + encode override "XML"; +} + +group MixedModifiersInGroup3 { + type union DummyUnion { integer f }; //^In type definition// +} +with { + encode override "TEXT"; //All 'encode' attributes of a group or module must have the same modifier// + encode @local "XML"; +} + +type set DummySet { //^In type definition// + integer f optional +} +with { + encode "XML"; + variant @local "name as uncapitalized"; //The '@local' modifier only affects 'encode' attributes. Modifier ignored.// + display @local "xx"."red"; //The '@local' modifier only affects 'encode' attributes. Modifier ignored.// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// +} + +const DummySet c_dummy := { f := - } with { optional @local "yy"."implicit omit" } //^In constant definition// //The '@local' modifier only affects 'encode' attributes. Modifier ignored.// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// + +type set of DummySet DummySetList with { //^In type definition// + extension @local "qw"."optimize:memalloc"; //The '@local' modifier only affects 'encode' attributes. Modifier ignored.// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// + encode "JSON"."RAW"; //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// +} + +} diff --git a/function_test/Semantic_Analyser/encode_legacy/encode_ttcn_SE.ttcn b/function_test/Semantic_Analyser/encode_legacy/encode_ttcn_SE.ttcn index 19416d334db091ef331ebde32019858b639c22e0..607038addf66d6ae963f4544cd2d1d5534510de6 100644 --- a/function_test/Semantic_Analyser/encode_legacy/encode_ttcn_SE.ttcn +++ b/function_test/Semantic_Analyser/encode_legacy/encode_ttcn_SE.ttcn @@ -150,6 +150,21 @@ type record C2 { external function f_enc_C2(in C2 x) return octetstring //^In external function definition \`f_enc_C2\'\:// //^error\: Input type \`\@encode_ttcn_SE\.C2\' does not support XER encoding\.// with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }; +type set DummySet { //^In type definition// + integer f optional +} +with { + encode @local "XML"; //The '@local' modifier cannot be used with legacy codec handling// + variant @local "XML"."name as uncapitalized"; //The '@local' modifier cannot be used with legacy codec handling// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// + display @local "xx"."red"; //The '@local' modifier cannot be used with legacy codec handling// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// +} + +const DummySet c_dummy := { f := - } with { optional @local "yy"."implicit omit" } //^In constant definition// //The '@local' modifier cannot be used with legacy codec handling// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// + +type set of DummySet DummySetList with { //^In type definition// + extension @local "qw"."optimize:memalloc"; //The '@local' modifier cannot be used with legacy codec handling// //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// + encode "JSON"."RAW"; //Invalid attribute format. Dot notation is only allowed for variant attributes when using the new codec handling.// +} } with { encode "whatever" diff --git a/function_test/Semantic_Analyser/xer/ifq_SE.ttcn b/function_test/Semantic_Analyser/xer/ifq_SE.ttcn index 2e7db4d6ae7eec47b37be492652b40300ed1fe1a..3687cf7f7a9c93a1f083c5283c7176d30d4da3cb 100644 --- a/function_test/Semantic_Analyser/xer/ifq_SE.ttcn +++ b/function_test/Semantic_Analyser/xer/ifq_SE.ttcn @@ -14,7 +14,7 @@ module ifq_SE { //^In TTCN-3 module `ifq_SE':// type record foo {} //^In type definition// with { - variant ([-]) "attribute" //^error: Invalid field qualifier \[-\]// + variant ([-]) "attribute" //^error: Type `\@ifq_SE\.foo' cannot be indexed// } /* integer _0; is a syntax error