diff --git a/compiler2/CompField.cc b/compiler2/CompField.cc index e017e850e5765efab570c7f3559742c93b6d100c..47dca525b17b90bce7c50e3c76c227e862d58031 100644 --- a/compiler2/CompField.cc +++ b/compiler2/CompField.cc @@ -23,9 +23,10 @@ namespace Common { // ================================= CompField::CompField(Identifier *p_name, Type *p_type, bool p_is_optional, - Value *p_defval) + Value *p_defval, bool p_default_modifier) : Node(), Location(), name(p_name), type(p_type), - is_optional(p_is_optional), defval(p_defval), rawattrib(0) + is_optional(p_is_optional), defval(p_defval), + default_modifier(p_default_modifier), rawattrib(0) { if(!p_name || !p_type) FATAL_ERROR("NULL parameter: Common::CompField::CompField()"); @@ -33,7 +34,8 @@ CompField::CompField(Identifier *p_name, Type *p_type, bool p_is_optional, } CompField::CompField(const CompField& p) - : Node(p), Location(p), is_optional(p.is_optional), rawattrib(0) + : Node(p), Location(p), is_optional(p.is_optional), + default_modifier(p.default_modifier), rawattrib(0) { name=p.name->clone(); type=p.type->clone(); @@ -84,6 +86,9 @@ void CompField::dump(unsigned level) const DEBUG(level + 1, "with default value"); defval->dump(level + 2); } + if (default_modifier) { + DEBUG(level + 1, "@default"); + } } // ================================= @@ -145,6 +150,14 @@ CompField* CompFieldMap::get_comp_byName(const Identifier& p_name) return m[p_name.get_name()]; } +CompField* CompFieldMap::get_default() +{ + if (!checked) { + chk_uniq(); + } + return default_alt; +} + const char *CompFieldMap::get_typetype_name() const { if (!my_type) FATAL_ERROR("CompFieldMap::get_typetype_name()"); @@ -178,6 +191,36 @@ void CompFieldMap::chk_uniq() comp->error("Duplicate %s field name `%s'", typetype_name, dispname); m[name]->note("Field `%s' is already defined here", dispname); } else m.add(name, comp); + if (comp->has_default_modifier()) { + if (default_alt == NULL) { + default_alt = comp; + } + else { + comp->error("Multiple union fields defined with the `@default' modifier"); + default_alt->note("The `@default' modifier was already used here"); + } + } + } + if (default_alt != NULL) { + CompField* current_default = default_alt; + while (current_default) { + Type* current_type = current_default->get_type()->get_type_refd_last(); + if (!current_type->is_secho()) { + break; + } + for (size_t i = 0; i < nof_comps; ++i) { + CompField* comp = v[i]; + const Identifier& id = comp->get_name(); + if (current_type->has_comp_withName(id)) { + CompField* clashing_comp = current_type->get_comp_byName(id); + const char* dispname = id.get_dispname().c_str(); + comp->error("Duplicate union field name `%s'", dispname); + clashing_comp->note("Field `%s' of the default alternative is here", dispname); + } + } + current_default = current_type->get_typetype() == Type::T_CHOICE_T ? + current_type->get_default_alternative() : NULL; + } } checked = true; } diff --git a/compiler2/CompField.hh b/compiler2/CompField.hh index e4c96d34ba96f27c0bb20a828bfe80ff52229ee1..9588d6e4c7c905072b9420997f3f8082fd80adf0 100644 --- a/compiler2/CompField.hh +++ b/compiler2/CompField.hh @@ -32,6 +32,8 @@ private: bool is_optional; /** Default value or 0 if no default value. Owned. */ Value *defval; + /** @default modifier */ + bool default_modifier; /** Raw attributes or 0. Owned */ RawAST *rawattrib; /** Copy constructor not implemented */ @@ -40,7 +42,7 @@ private: CompField& operator=(const CompField& p); public: CompField(Identifier *p_name, Type *p_type, bool p_is_optional=false, - Value *p_defval=0); + Value *p_defval=0, bool p_default_modifier = false); virtual ~CompField(); virtual CompField *clone() const; virtual void set_fullname(const string& p_fullname); @@ -52,6 +54,7 @@ public: bool get_is_optional() const { return is_optional; } bool has_default() const { return defval != 0; } Value *get_defval() const { return defval; } + bool has_default_modifier() const { return default_modifier; } virtual void dump(unsigned level) const; }; @@ -68,6 +71,9 @@ private: /** Contains pointers to the individual CompField s. * The CompFieldMap owns the CompFields and will free them. */ vector<CompField> v; + /** Pointer to the union alternative with the '@default' modifier. + * Null if there is none, or if the structure is not a union. */ + CompField* default_alt; /** Points to the owner type, which shall be a TTCN-3 record, set or * union or an ASN.1 open type. * The CompFieldMap does not own the type. */ @@ -80,7 +86,7 @@ private: /** Assignment disabled */ CompFieldMap& operator=(const CompFieldMap& p); public: - CompFieldMap() : Node(), m(), v(), my_type(0), checked(false) {} + CompFieldMap() : Node(), m(), v(), default_alt(NULL), my_type(0), checked(false) {} virtual ~CompFieldMap(); virtual CompFieldMap *clone() const; virtual void set_fullname(const string& p_fullname); @@ -91,6 +97,7 @@ public: CompField* get_comp_byIndex(size_t n) const { return v[n]; } bool has_comp_withName(const Identifier& p_name); CompField* get_comp_byName(const Identifier& p_name); + CompField* get_default(); private: const char *get_typetype_name() const; /** Check the uniqueness of field identifiers. diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 3711acf52b62312d9770a950909cf779f0944951..be2d4838cdab37406d1e53c8f7e00ae13cc1828e 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -1771,6 +1771,13 @@ namespace Common { } else { if (!t->has_comp_withName(id)) { + CompField* def_alt = t->get_default_alternative(); + if (def_alt != NULL) { + Error_Context cntxt(ref, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); + subrefs->use_default_alternative(i, def_alt->get_name()); + return get_field_type(subrefs, expected_index, refch, interrupt_if_optional, last_method); + } if (!silent) { ref->error("Reference to non-existent field `%s' in type `%s'", id.get_dispname().c_str(), t->get_typename().c_str()); @@ -1923,6 +1930,15 @@ namespace Common { embedded_type = t; break; } + case T_CHOICE_T: { + CompField* def_alt = t->get_default_alternative(); + if (def_alt != NULL) { + Error_Context cntxt(ref, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); + subrefs->use_default_alternative(i, def_alt->get_name()); + return get_field_type(subrefs, expected_index, refch, interrupt_if_optional, last_method); + } + /* otherwise fall through */ } default: if (!silent) { ref->error("Type `%s' cannot be indexed", @@ -6018,6 +6034,18 @@ namespace Common { } return *(*t->u.secho.field_by_name)[p_name.get_name()]; } + + CompField* Type::get_default_alternative() + { + if (!checked) { + chk(); + } + Type* t = get_type_refd_last(); + if (t->typetype != T_CHOICE_T) { + return NULL; + } + return t->u.secho.cfm->get_default(); + } size_t Type::get_eis_index_byName(const Identifier& p_name) { diff --git a/compiler2/Type.hh b/compiler2/Type.hh index f3423ab861f2455ae7d3358058cb90dc966de83d..825677c6de54f6693cd618527829a3553f5eff05 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -977,7 +977,9 @@ namespace Common { void chk_this_value_Any(Value *value); bool chk_this_value_Choice(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool omit_allowed, namedbool sub_chk, + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool str_elem = NOT_STR_ELEM); bool chk_this_value_Se(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, namedbool implicit_omit = NOT_IMPLICIT_OMIT); @@ -1030,8 +1032,9 @@ namespace Common { void chk_this_template_length_restriction(Template *t); bool chk_this_template_concat_operand(Template* t, namedbool implicit_omit, Common::Assignment *lhs); - bool chk_this_template(Template *t, namedbool incomplete_allowed, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *); + bool chk_this_template(Template *t, namedbool incomplete_allowed, + namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, + namedbool implicit_omit, Common::Assignment *lhs); bool chk_this_template_Str(Template *t, namedbool implicit_omit, Common::Assignment *lhs); /** Checks whether \a v is a correct range boundary for this type. @@ -1049,6 +1052,7 @@ namespace Common { void chk_this_template_Int_Real(Template *t); void chk_this_template_Enum(Template *t); bool chk_this_template_Choice(Template *t, namedbool incomplete_allowed, + namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, namedbool implicit_omit, Common::Assignment *lhs); bool chk_this_template_Seq(Template *t, namedbool incomplete_allowed, namedbool implicit_omit, Common::Assignment *lhs); @@ -1109,6 +1113,8 @@ namespace Common { * T_CHOICE_T, T_SEQ_T, T_SET_T, T_OPENTYPE, * T_SEQ_A, T_SET_A, T_CHOICE_A, T_ANYTYPE */ size_t get_comp_index_byName(const Identifier& p_name); + + CompField* get_default_alternative(); /** Get the index of the enum item with the given name * diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 41843b00d84e2c228b263322676fd25aa872492a..95247f4098419b18326d759bb080a5caed9d8b7a 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -3962,6 +3962,13 @@ void Type::chk_this_value_ref(Value *value) case T_OCFT: get_type_refd()->chk_this_value_ref(value); return; + case T_CHOICE_T: { + CompField* def_alt = get_default_alternative(); + if (def_alt != NULL) { + def_alt->get_type()->chk_this_value_ref(value); + return; + } + break; } default: break; } // switch @@ -4003,6 +4010,15 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ if (value->is_unfoldable(0, expected_value)) { typetype_t tt = value->get_expr_returntype(expected_value); if (!is_compatible_tt(tt, value->is_asn1(), value->get_expr_governor_last())) { + CompField* def_alt = get_default_alternative(); + if (def_alt != NULL) { + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, is_str_elem); + value->use_default_alternative(this); + return self_ref; + } value->error("Incompatible value: `%s' value was expected", get_typename().c_str()); value->set_valuetype(Value::V_ERROR); @@ -4085,8 +4101,8 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ case T_CHOICE_T: case T_OPENTYPE: case T_ANYTYPE: - self_ref = chk_this_value_Choice(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + self_ref = chk_this_value_Choice(value, lhs, expected_value, omit_allowed, + sub_chk, incomplete_allowed, implicit_omit, is_str_elem); break; case T_SEQ_T: case T_SET_T: @@ -4340,6 +4356,26 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v if (info.is_subtype_error()) { value->error("%s", info.get_subtype_error().c_str()); } else if (!info.is_erroneous()) { + CompField* def_alt_ref = governor->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); + if (def_alt_ref != NULL && ttcn_ref != NULL) { + // first try using default alternatives on the right-hand-side + Error_Context cntxt(value, "Using default alternative `%s' in reference to " + "value of union type `%s'", def_alt_ref->get_name().get_dispname().c_str(), + governor->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt_ref->get_name()); + return chk_this_refd_value(value, lhs, expected_value, refch, str_elem); + } + CompField* def_alt = get_default_alternative(); + if (def_alt != NULL) { + // afterwards try using default alternatives on the left-hand-side + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_refd_value(value, lhs, + expected_value, refch, str_elem); + value->use_default_alternative(this); + return self_ref; + } value->error("Type mismatch: a %s of type `%s' was expected " "instead of `%s'", expected_value == EXPECTED_TEMPLATE ? "value or template" : "value", @@ -4932,12 +4968,22 @@ static string actual_fields(Type& t) // alas, not even get_nof_comps() is const bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, - expected_value_t expected_value, namedbool incomplete_allowed, namedbool implicit_omit) + expected_value_t expected_value, namedbool omit_allowed, namedbool sub_chk, + namedbool incomplete_allowed, namedbool implicit_omit, namedbool str_elem) { bool self_ref = false; + CompField* def_alt = get_default_alternative(); switch(value->get_valuetype()) { case Value::V_SEQ: if (value->is_asn1()) { + if (def_alt != NULL) { + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + value->use_default_alternative(this); + return self_ref; + } value->error("CHOICE value was expected for type `%s'", get_fullname().c_str()); value->set_valuetype(Value::V_ERROR); @@ -4945,6 +4991,15 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, } else { // the valuetype can be ERROR if the value has no fields at all if (value->get_valuetype() == Value::V_ERROR) return false; + if (def_alt != NULL && (value->get_nof_comps() != 1 || + !has_comp_withName(value->get_se_comp_byIndex(0)->get_name()))) { + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + value->use_default_alternative(this); + return self_ref; + } // The value notation for TTCN record/union types // cannot be distinguished during parsing. Now we know it's a union. value->set_valuetype(Value::V_CHOICE); @@ -4957,20 +5012,30 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, } const Identifier& alt_name = value->get_alt_name(); if(!has_comp_withName(alt_name)) { - if (value->is_asn1()) { - value->error("Reference to non-existent alternative `%s' in CHOICE" - " value for type `%s'", - alt_name.get_dispname().c_str(), - get_fullname().c_str()); - } else { - value->error("Reference to non-existent field `%s' in union " - "value for type `%s'", - alt_name.get_dispname().c_str(), - get_fullname().c_str()); + if (def_alt != NULL) { + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + value->use_default_alternative(this); + return self_ref; + } + else { + if (value->is_asn1()) { + value->error("Reference to non-existent alternative `%s' in CHOICE" + " value for type `%s'", + alt_name.get_dispname().c_str(), + get_fullname().c_str()); + } else { + value->error("Reference to non-existent field `%s' in union " + "value for type `%s'", + alt_name.get_dispname().c_str(), + get_fullname().c_str()); + } + value->set_valuetype(Value::V_ERROR); + value->note("%s", actual_fields(*this).c_str()); + return self_ref; } - value->set_valuetype(Value::V_ERROR); - value->note("%s", actual_fields(*this).c_str()); - return self_ref; } Type *alt_type = get_comp_byName(alt_name)->get_type(); Value *alt_value = value->get_alt_value(); @@ -4986,10 +5051,19 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, } break;} default: - value->error("%s value was expected for type `%s'", - value->is_asn1() ? "CHOICE" : "union", - get_fullname().c_str()); - value->set_valuetype(Value::V_ERROR); + if (def_alt != NULL) { + Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + value->use_default_alternative(this); + return self_ref; + } + else { + value->error("%s value was expected for type `%s'", + value->is_asn1() ? "CHOICE" : "union", get_fullname().c_str()); + value->set_valuetype(Value::V_ERROR); + } break; } return self_ref; @@ -6537,7 +6611,8 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, } break; default: - self_ref = chk_this_template(t, incomplete_allowed, sub_chk, implicit_omit, lhs); + self_ref = chk_this_template(t, incomplete_allowed, allow_omit, allow_any_or_omit, + sub_chk, implicit_omit, lhs); break; } if (t->get_length_restriction()) chk_this_template_length_restriction(t); @@ -6687,8 +6762,9 @@ bool Type::chk_this_template_concat_operand(Template* t, namedbool implicit_omit return self_ref; } -bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, namedbool, - namedbool implicit_omit, Common::Assignment *lhs) +bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, + namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, + namedbool implicit_omit, Common::Assignment *lhs) { bool self_ref = false; Type *t_last = get_type_refd_last(); @@ -6742,7 +6818,8 @@ bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, namedboo case T_CHOICE_T: case T_OPENTYPE: case T_ANYTYPE: - self_ref = t_last->chk_this_template_Choice(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_Choice(t, incomplete_allowed, allow_omit, + allow_any_or_omit, sub_chk, implicit_omit, lhs); break; case T_SEQ_A: case T_SEQ_T: @@ -7030,12 +7107,23 @@ void Type::chk_this_template_Enum(Template *t) } bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, + namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, namedbool implicit_omit, Common::Assignment *lhs) { bool self_ref = false; + CompField* def_alt = get_default_alternative(); switch (t->get_templatetype()) { case Ttcn::Template::NAMED_TEMPLATE_LIST: { size_t nof_nts = t->get_nof_comps(); + if (def_alt != NULL && (nof_nts != 1 || + !has_comp_withName(t->get_namedtemp_byIndex(0)->get_name()))) { + Error_Context cntxt(t, "Using default alternative `%s' in template of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_template_generic(t, incomplete_allowed, allow_omit, + allow_any_or_omit, sub_chk, implicit_omit, lhs); + t->use_default_alternative(this); + return self_ref; + } if (nof_nts != 1) t->error("A template for union type must contain " "exactly one selected field"); // We check all named templates, even though it is an error @@ -7072,6 +7160,14 @@ bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, } break;} default: + if (def_alt != NULL) { + Error_Context cntxt(t, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); + self_ref = def_alt->get_type()->chk_this_template_generic(t, incomplete_allowed, allow_omit, + allow_any_or_omit, sub_chk, implicit_omit, lhs); + t->use_default_alternative(this); + return self_ref; + } t->error("%s cannot be used for union type `%s'", t->get_templatetype_str(), get_typename().c_str()); break; diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 0846c3ba24b3f370b3d653165d76b0d7885cf410..6dd9179434028ce9bf6ffa13a48c21a2dc1e50d1 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -80,7 +80,7 @@ namespace Common { // ================================= Value::Value(const Value& p) - : GovernedSimple(p), valuetype(p.valuetype), my_governor(0) + : GovernedSimple(p), valuetype(p.valuetype), my_governor(p.my_governor) , in_brackets(p.in_brackets) { switch(valuetype) { @@ -3681,7 +3681,8 @@ namespace Common { } } - Type::typetype_t Value::get_expr_returntype(Type::expected_value_t exp_val) + Type::typetype_t Value::get_expr_returntype(Type::expected_value_t exp_val, + bool use_def_alt /* = false */) { switch (valuetype) { case V_CHARSYMS: @@ -3710,8 +3711,23 @@ namespace Common { case V_REFD: case V_INVOKE: { Type *t = get_expr_governor(exp_val); - if (t) return t->get_type_refd_last()->get_typetype_ttcn3(); - else return Type::T_ERROR; } + if (t != NULL) { + t = t->get_type_refd_last(); + } + Type::typetype_t tt = t != NULL ? t->get_typetype_ttcn3() : Type::T_ERROR; + if (use_def_alt) { + while (tt == Type::T_CHOICE_T) { + CompField* def_alt = t->get_default_alternative(); + if (def_alt != NULL) { + t = def_alt->get_type()->get_type_refd_last(); + tt = t->get_typetype_ttcn3(); + } + else { + break; // exit the 'while' loop if there's no default alternative + } + } + } + return tt; } case V_FUNCTION: return Type::T_FUNCTION; case V_ALTSTEP: @@ -3801,7 +3817,7 @@ namespace Common { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); - tmp_tt=u.expr.v1->get_expr_returntype(exp_val); + tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_INT: @@ -3821,7 +3837,7 @@ namespace Common { Error_Context cntxt(this, "In the left operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); - tmp_tt=u.expr.v1->get_expr_returntype(exp_val); + tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_INT: @@ -3834,7 +3850,7 @@ namespace Common { Error_Context cntxt(this, "In the right operand of operation `%s'", get_opname()); u.expr.v2->set_lowerid_to_ref(); - tmp_tt2=u.expr.v2->get_expr_returntype(exp_val); + tmp_tt2=u.expr.v2->get_expr_returntype(exp_val, true); } Type::typetype_t ret_val=Type::T_ERROR; bool maybeconcat=false; @@ -3882,7 +3898,7 @@ namespace Common { u.expr.v_optype==OPTYPE_NOT4B?"":"left ", get_opname()); u.expr.v1->set_lowerid_to_ref(); - tmp_tt=u.expr.v1->get_expr_returntype(exp_val); + tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_BSTR: @@ -3966,7 +3982,7 @@ namespace Common { Error_Context cntxt(this, "In the first operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); - tmp_tt=u.expr.v1->get_expr_returntype(exp_val); + tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_CSTR: @@ -4583,29 +4599,6 @@ namespace Common { } // switch } - void Value::chk_expr_operandtype_enum(const char *opname, Value *v, - Type::expected_value_t exp_val) - { - v->set_lowerid_to_ref(); // can only be reference to enum - Type *t = v->get_expr_governor(exp_val); - if (v->valuetype==V_ERROR) return; - if (!t) { - v->error("Please use reference to an enumerated value as the operand of " - "operation `%s'", get_opname()); - set_valuetype(V_ERROR); - return; - } - t = t->get_type_refd_last(); - if (t->get_typetype()!=Type::T_ENUM_A && t->get_typetype()!=Type::T_ENUM_T) { - v->error("The operand of operation `%s' should be enumerated value", opname); - set_valuetype(V_ERROR); - } - if (v->get_value_refd_last()->valuetype==V_OMIT) { - v->error("The operand of operation `%s' cannot be omit", opname); - set_valuetype(V_ERROR); - } - } - void Value::chk_expr_operandtype_bool(Type::typetype_t tt, const char *opnum, const char *opname, @@ -4956,6 +4949,26 @@ namespace Common { if (!info1.is_erroneous() && !info2.is_erroneous()) { // the subtypes don't need to be compatible here if (!info1.is_subtype_error() && !info2.is_subtype_error()) { + if (v1->is_ref()) { + CompField* def_alt = t1->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v1->get_reference()); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(v1, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t1->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + return chk_expr_operandtypes_compat(exp_val, v1, v2, opnum1, opnum2); + } + } + if (v2->is_ref()) { + CompField* def_alt = t2->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v2->get_reference()); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(v2, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t2->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + return chk_expr_operandtypes_compat(exp_val, v1, v2, opnum1, opnum2); + } + } error("The operands of operation `%s' should be of compatible " "types", get_opname()); set_valuetype(V_ERROR); @@ -5272,6 +5285,16 @@ namespace Common { ->get_field_type(ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); if(!ret_val) goto error; Type* t_type=ret_val->get_type_refd_last(); + if (t_type->get_typetype() == Type::T_CHOICE_T) { + CompField* def_alt = t_type->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(val, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + return chk_expr_operand_compref(val, opnum, opname, any_from); + } + } if(t_type->get_typetype() != (any_from ? Type::T_ARRAY : Type::T_COMPONENT)) { ref->error("%s operand of operation `%s': Type mismatch:" " component%s reference was expected instead of `%s'", @@ -6446,14 +6469,31 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Type::T_CHOICE_T: case Type::T_ANYTYPE: case Type::T_OPENTYPE: - if (!t_governor->has_comp_withName(*u.expr.i2)) { - error(t_governor->get_typetype()==Type::T_ANYTYPE ? - "%s does not have a field named `%s'" : - "Union type `%s' does not have a field named `%s'", - t_governor->get_typename().c_str(), - u.expr.i2->get_dispname().c_str()); - error_flag = true; - } + if (!t_governor->has_comp_withName(*u.expr.i2)) { + CompField* def_alt = t_governor->get_default_alternative(); + Ttcn::Reference* ref = u.expr.v_optype == OPTYPE_ISCHOSEN_V ? + dynamic_cast<Ttcn::Reference*>(u.expr.v1->get_reference()) : + u.expr.t1->get_reference(); + if (def_alt != NULL && ref != NULL) { + Error_Context cntxt2(ref, "Using default alternative `%s' in value or template of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t_governor->get_typename().c_str()); + ref->use_default_alternative(def_alt->get_name()); + if (u.expr.v_optype == OPTYPE_ISCHOSEN_V) { + u.expr.v1->set_my_governor(def_alt->get_type()); + } + else { + u.expr.t1->set_my_governor(def_alt->get_type()); + } + chk_expr_operands_ischosen(refch, exp_val); + return; + } + error(t_governor->get_typetype()==Type::T_ANYTYPE ? + "%s does not have a field named `%s'" : + "Union type `%s' does not have a field named `%s'", + t_governor->get_typename().c_str(), + u.expr.i2->get_dispname().c_str()); + error_flag = true; + } break; default: loc->error("The operand of operation `%s' should be a union value " @@ -6581,6 +6621,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } v_enc_info->set_lowerid_to_ref(); Type::typetype_t tt = v_enc_info->get_expr_returntype(exp_val); + if (tt == Type::T_CHOICE_T && v_enc_info->is_ref() && + chk_expr_operand_default_alternative(v_enc_info, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_ENCODE ? "Second" : "Third", opname, v_enc_info); chk_expr_eval_value(v_enc_info, t_chk, refch, exp_val); @@ -6597,6 +6642,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } v_dyn_enc->set_lowerid_to_ref(); Type::typetype_t tt = v_dyn_enc->get_expr_returntype(exp_val); + if (tt == Type::T_CHOICE_T && v_dyn_enc->is_ref() && + chk_expr_operand_default_alternative(v_dyn_enc, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_ENCODE ? "Third" : "Fourth", opname, v_dyn_enc); chk_expr_eval_value(v_dyn_enc, t_chk, refch, exp_val); @@ -6667,6 +6717,16 @@ void Value::chk_expr_operand_execute_refd(Value *v1, if (!t_type) { goto error; } + if (t_type->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T) { + CompField* def_alt = t_type->get_default_alternative(); + if (def_alt != NULL) { + Error_Context cntxt2(ref, "Using default alternative `%s' in reference to value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); + ref->use_default_alternative(def_alt->get_name()); + chk_expr_operands_decode(refch, exp_val); + return; + } + } switch(u.expr.v_optype) { case OPTYPE_DECODE: if (t_type->get_type_refd_last()->get_typetype() != Type::T_BSTR){ @@ -6750,6 +6810,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } v_enc_info->set_lowerid_to_ref(); Type::typetype_t tt = v_enc_info->get_expr_returntype(exp_val); + if (tt == Type::T_CHOICE_T && v_enc_info->is_ref() && + chk_expr_operand_default_alternative(v_enc_info, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_DECODE ? "Third" : "Fourth", opname, v_enc_info); chk_expr_eval_value(v_enc_info, t_chk, refch, exp_val); @@ -6766,6 +6831,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } v_dyn_enc->set_lowerid_to_ref(); Type::typetype_t tt = v_dyn_enc->get_expr_returntype(exp_val); + if (tt == Type::T_CHOICE_T && v_dyn_enc->is_ref() && + chk_expr_operand_default_alternative(v_dyn_enc, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_DECODE ? "Fourth" : "Fifth", opname, v_dyn_enc); chk_expr_eval_value(v_dyn_enc, t_chk, refch, exp_val); @@ -6835,7 +6905,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } Int Value::chk_eval_expr_sizeof(ReferenceChain *refch, - Type::expected_value_t exp_val) + Type::expected_value_t exp_val, + Type* def_alt_type) { if(valuetype==V_ERROR) return -1; if(u.expr.state==EXPR_CHECKING_ERR) return -1; @@ -6899,7 +6970,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Assignment* t_ass = 0; Reference* ref = 0; Ttcn::FieldOrArrayRefs* t_subrefs = 0; - t_type = chk_expr_operands_ti(u.expr.ti1, exp_val); + t_type = def_alt_type != NULL ? def_alt_type : + chk_expr_operands_ti(u.expr.ti1, exp_val); if (t_type) { chk_expr_eval_ti(u.expr.ti1, t_type, refch, exp_val); t_type = t_type->get_type_refd_last(); @@ -6917,6 +6989,10 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Template::INDEXED_TEMPLATE_LIST: return -1; case Template::TEMPLATE_REFD: + ref = t_templ->get_reference(); + t_ass = ref->get_refd_assignment(); + t_subrefs = ref->get_subrefs(); + break; case Template::TEMPLATE_LIST: case Template::NAMED_TEMPLATE_LIST: // computed later @@ -6996,10 +7072,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: - if (exp_val!=Type::EXPECTED_TEMPLATE) + if (exp_val!=Type::EXPECTED_TEMPLATE) { u.expr.ti1->error("Reference to a value was expected instead of %s", t_ass->get_description().c_str()); - goto error; + goto error; + } break; case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: @@ -7079,6 +7156,18 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Type::T_OID: case Type::T_ROID: break; + case Type::T_CHOICE_T: + if (ref != NULL) { + CompField* def_alt = t_type->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt2(ref, "Using default alternative `%s' in value or template of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + return chk_eval_expr_sizeof(refch, exp_val, def_alt->get_type()); + } + } + // otherwise fall through default: u.expr.ti1->error("Reference to value or template of type record, record of," " set, set of, objid or array was expected"); @@ -7358,6 +7447,58 @@ void Value::chk_expr_operand_execute_refd(Value *v1, set_valuetype(V_ERROR); } } + + bool Value::chk_expr_operand_default_alternative(Value* v, ReferenceChain *refch, + Type::expected_value_t exp_val) + { + if (!v->is_ref()) { + FATAL_ERROR("Value::chk_default_alternative_ref"); + } + Type* t = v->get_expr_governor(exp_val); + CompField* def_alt = t->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v->get_reference()); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(v, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + if (u.expr.state != EXPR_CHECKING_ERR) { + chk_expr_operands(refch, exp_val); + } + return true; + } + return false; + } + + bool Value::chk_expr_operand_default_alternative(TemplateInstance* ti, Type* ti_gov, + ReferenceChain *refch, Type::expected_value_t exp_val) + { + CompField* def_alt = ti_gov->get_default_alternative(); + if (def_alt == NULL) { + return false; + } + Ttcn::Reference* ttcn_ref = NULL; + Template* temp = ti->get_Template(); + switch (temp->get_templatetype()) { + case Ttcn::Template::TEMPLATE_REFD: + ttcn_ref = temp->get_reference(); + break; + case Ttcn::Template::SPECIFIC_VALUE: + ttcn_ref = dynamic_cast<Ttcn::Reference*>(temp->get_specific_value()->get_reference()); + break; + default: + break; + } + if (ttcn_ref != NULL) { + Error_Context cntxt(ti, "Using default alternative `%s' in value or template of union type `%s'", + def_alt->get_name().get_dispname().c_str(), ti_gov->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + if (u.expr.state != EXPR_CHECKING_ERR) { + chk_expr_operands(refch, exp_val); + } + return true; + } + return false; + } void Value::chk_expr_operands(ReferenceChain *refch, Type::expected_value_t exp_val) @@ -7431,6 +7572,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7441,6 +7587,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bool(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7451,6 +7602,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_binstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7463,6 +7619,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7473,6 +7634,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Skip `chk_expr_val_bitstr_intsize(v1, the, opname);'. @@ -7484,6 +7650,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_len1(v1, the, opname); @@ -7495,6 +7666,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7505,6 +7681,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_int(v1, the, opname); @@ -7516,6 +7697,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_float(v1, the, opname); @@ -7527,6 +7713,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_bindigits(v1, the, opname); @@ -7538,6 +7729,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_hexdigits(v1, the, opname); @@ -7549,6 +7745,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_len_even(v1, the, opname); @@ -7559,7 +7760,29 @@ void Value::chk_expr_operand_execute_refd(Value *v1, v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); - chk_expr_operandtype_enum(opname, v1, exp_val); + v1->set_lowerid_to_ref(); // can only be reference to enum + Type *t = v1->get_expr_governor(exp_val); + if (v1->valuetype==V_ERROR) return; + if (!t) { + v1->error("Please use reference to an enumerated value as the operand of " + "operation `%s'", get_opname()); + set_valuetype(V_ERROR); + return; + } + t = t->get_type_refd_last(); + if (t->get_typetype() == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } + if (t->get_typetype()!=Type::T_ENUM_A && t->get_typetype()!=Type::T_ENUM_T) { + v1->error("The operand of operation `%s' should be enumerated value", opname); + set_valuetype(V_ERROR); + } + if (v1->get_value_refd_last()->valuetype==V_OMIT) { + v1->error("The operand of operation `%s' cannot be omit", opname); + set_valuetype(V_ERROR); + } chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; @@ -7573,6 +7796,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); if (u.expr.v_optype==OPTYPE_FLOAT2INT) @@ -7585,6 +7813,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_operand_valid_float(v1, the, opname); @@ -7599,6 +7832,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_hstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7609,6 +7847,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_hstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Skip `chk_expr_val_hexstr_intsize(v1, the, opname);'. @@ -7620,6 +7863,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos7bit(v1, the, opname); @@ -7631,6 +7879,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos31bit(v1, first, opname); @@ -7643,6 +7896,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7657,6 +7915,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7667,6 +7930,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Simply skip `chk_expr_val_hexstr_intsize(v1, the, opname);' for @@ -7679,6 +7947,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_7bitoctets(v1, the, opname); @@ -7690,6 +7963,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7700,6 +7978,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7710,6 +7993,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7719,6 +8007,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bool(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -7729,6 +8022,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7739,6 +8037,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_len1(v1, the, opname); @@ -7750,6 +8053,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_ustr_7bitchars(v1, the, opname); @@ -7762,6 +8070,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt1, second, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7773,6 +8086,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7783,6 +8101,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7792,6 +8115,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -7802,6 +8130,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7811,6 +8144,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_cstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -7828,6 +8166,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(u.expr.v2, "In the second operand of operation `%s'", opname); u.expr.v2->set_lowerid_to_ref(); tt2=u.expr.v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && u.expr.v2->is_ref() && + chk_expr_operand_default_alternative(u.expr.v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt2, second, opname, u.expr.v2); chk_expr_eval_value(u.expr.v2, t_chk, refch, exp_val); if (!u.expr.v2->is_unfoldable()) { @@ -7853,6 +8196,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); if (!u.expr.v2->is_unfoldable()) { @@ -7875,6 +8223,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the thrid operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); + if (tt3 == Type::T_CHOICE_T && v3->is_ref() && + chk_expr_operand_default_alternative(v3, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_charstr(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); if (!u.expr.v3->is_unfoldable()) { @@ -7899,7 +8252,17 @@ void Value::chk_expr_operand_execute_refd(Value *v1, v1->set_lowerid_to_ref(); v2->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int_float(tt1, first, opname, v1); chk_expr_operandtype_int_float(tt2, second, opname, v2); chk_expr_eval_value(v1, t_chk, refch, exp_val); @@ -7916,6 +8279,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -7924,6 +8292,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_float_not0(v2, right, opname); @@ -7938,12 +8311,22 @@ void Value::chk_expr_operand_execute_refd(Value *v1, { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_str(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_str(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -7951,6 +8334,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, || (tt2==Type::T_CSTR && tt1==Type::T_USTR))) chk_expr_operandtypes_same(tt1, tt2, opname); } else { // other list types + v1->get_value_refd_last(); + v2->get_value_refd_last(); Type* v1_gov = v1->get_expr_governor(exp_val); Type* v2_gov = v2->get_expr_governor(exp_val); if (!v1_gov) { @@ -7959,6 +8344,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return; } else { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); + if (v1->is_ref() && v1_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } v1_gov->chk_this_value_ref(v1); (void)v1_gov->chk_this_value(v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); @@ -7972,6 +8362,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); + if (v2->is_ref() && v2_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } v2_gov->chk_this_value_ref(v2); (void)v2_gov->chk_this_value(v2, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); @@ -8027,6 +8422,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int_float_enum(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -8034,6 +8434,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the right operand of operation `%s'", opname); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int_float_enum(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -8047,6 +8452,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bool(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -8056,6 +8466,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_bool(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -8069,6 +8484,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_binstr(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -8078,6 +8498,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_binstr(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } @@ -8091,6 +8516,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_binstr(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } @@ -8099,6 +8529,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_large_int(v2, right, opname); @@ -8111,14 +8546,25 @@ void Value::chk_expr_operand_execute_refd(Value *v1, if (v1->is_string_type(exp_val)) { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_str(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } else { // other list types + v1->get_value_refd_last(); Type* v1_gov = v1->get_expr_governor(exp_val); if (!v1_gov) { // a recof/setof literal would be a syntax error here error("Cannot determine the type of the left operand of `%s' operation", opname); } else { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); + if (v1->is_ref() && v1_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } v1_gov->chk_this_value_ref(v1); (void)v1_gov->chk_this_value(v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); @@ -8130,6 +8576,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_large_int(v2, right, opname); @@ -8143,6 +8594,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); + if (tt1 == Type::T_CHOICE_T && v1->is_ref() && + chk_expr_operand_default_alternative(v1, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt1, first, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos0(v1, first, opname); @@ -8152,6 +8608,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); @@ -8168,6 +8629,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype!=V_ERROR) u.expr.ti1->get_Template()->chk_specific_value(false); @@ -8178,6 +8644,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); @@ -8187,6 +8658,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the third operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); + if (tt3 == Type::T_CHOICE_T && v3->is_ref() && + chk_expr_operand_default_alternative(v3, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); @@ -8200,6 +8676,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the first operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype!=V_ERROR) { u.expr.ti1->get_Template()->chk_specific_value(false); @@ -8211,6 +8692,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the second operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.t2, ti_exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.t2, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_eval_ti(u.expr.t2, governor, refch, ti_exp_val); chk_expr_operandtype_charstr(governor->get_type_refd_last()-> get_typetype_ttcn3(), second, opname, u.expr.t2); @@ -8220,6 +8706,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the third operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); + if (tt3 == Type::T_CHOICE_T && v3->is_ref() && + chk_expr_operand_default_alternative(v3, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); @@ -8283,6 +8774,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the operand of operation `%s'", opname); Type *governor = chk_expr_operands_ti(u.expr.ti1, exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_list(governor, the, opname, u.expr.ti1, true); if (valuetype == V_ERROR) return; chk_expr_eval_ti(u.expr.ti1, governor, refch, exp_val); @@ -8384,8 +8880,13 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); - chk_expr_operandtype_cstr(tt2, first, opname, v2); - chk_expr_eval_value(v2, t_chk, refch, exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } + chk_expr_operandtype_cstr(tt2, first, opname, v2); + chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_ACTIVATE_REFD:{ //v1 t_list2 @@ -8417,6 +8918,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype != V_ERROR) u.expr.ti1->get_Template()->chk_specific_value(false); @@ -8428,6 +8934,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v2->set_lowerid_to_ref(); tt2 = v2->get_expr_returntype(exp_val); + if (tt2 == Type::T_CHOICE_T && v2->is_ref() && + chk_expr_operand_default_alternative(v2, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); @@ -8438,6 +8949,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); v3->set_lowerid_to_ref(); tt3 = v3->get_expr_returntype(exp_val); + if (tt3 == Type::T_CHOICE_T && v3->is_ref() && + chk_expr_operand_default_alternative(v3, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); @@ -8447,6 +8963,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, opname); Type* governor = chk_expr_operands_ti(u.expr.ti4, ti_exp_val); if (!governor) return; + if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && + chk_expr_operand_default_alternative(u.expr.ti4, governor, refch, exp_val)) { + // this function was already re-called with the default alternative, abort this call + return; + } chk_expr_eval_ti(u.expr.ti4, governor, refch, ti_exp_val); if (valuetype != V_ERROR) u.expr.ti4->get_Template()->chk_specific_value(false); @@ -9682,6 +10203,26 @@ void Value::chk_expr_operand_execute_refd(Value *v1, FATAL_ERROR("Value::add_id()"); } // switch } + + void Value::use_default_alternative(Type* p_union_type) + { + if (valuetype == V_ERROR) { + return; + } + CompField* def_alt = p_union_type->get_default_alternative(); + if (def_alt == NULL) { + FATAL_ERROR("Value::use_default_alternative"); + } + Value* def_val = clone(); + def_val->my_governor = def_alt->get_type(); + def_val->set_my_scope(my_scope); + def_val->set_fullname(get_fullname() + ".<default_alternative>"); + clean_up(); + valuetype = V_CHOICE; + u.choice.alt_name = def_alt->get_name().clone(); + u.choice.alt_value = def_val; + my_governor = p_union_type; + } Value* Value::get_value_refd_last(ReferenceChain *refch, Type::expected_value_t exp_val) @@ -10546,8 +11087,23 @@ void Value::chk_expr_operand_execute_refd(Value *v1, set_lowerid_to_ref(); Type::typetype_t r_tt = get_expr_returntype(exp_val); bool error_flag = r_tt != Type::T_ERROR && r_tt != p_tt; - if (error_flag) + if (error_flag) { + if (is_ref() && r_tt == Type::T_CHOICE_T) { + Type* t = get_expr_governor(exp_val); + if (t != NULL) { + CompField* def_alt = t->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(get_reference()); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(this, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + chk_expr_type(p_tt, type_name, exp_val); + return; + } + } + } error("A value or expression of type %s was expected", type_name); + } if (valuetype == V_REFD) { Type *t_chk = Type::get_pooltype(Type::T_ERROR); t_chk->chk_this_refd_value(this, 0, exp_val); @@ -12898,7 +13454,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, bool Value::is_string_type(Type::expected_value_t exp_val) { - switch (get_expr_returntype(exp_val)) { + switch (get_expr_returntype(exp_val, true)) { case Type::T_CSTR: case Type::T_USTR: case Type::T_BSTR: diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 5e24451ee17218457b92e4426a311e76efb9091e..2be02078ee864996736ec69711cd3845ff7222ed 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -523,6 +523,12 @@ namespace Common { void set_valuetype(valuetype_t p_valuetype, Identifier *p_id); void set_valuetype(valuetype_t p_valuetype, Assignment *p_ass); void add_id(Identifier *p_id); + /** Converts the value into a union value, with the union type's @default alternative + * as its name and the original (cloned) value as its value. + * Used when a value of a different type appears in a context, where a value of + * the specified union type was expected. + * This attempts to use the value as the union's default alternative instead. */ + void use_default_alternative(Type* p_union_type); /** Follows the chain of references if any and returns the last * element of the chain. In other words, the returned value is * the first value which is not a reference. */ @@ -551,7 +557,8 @@ namespace Common { /** If this value is used in an expression, what is its return type? */ Type::typetype_t get_expr_returntype - (Type::expected_value_t exp_val=Type::EXPECTED_DYNAMIC_VALUE); + (Type::expected_value_t exp_val=Type::EXPECTED_DYNAMIC_VALUE, + bool use_def_alt = false); /** If this value is used in an expression, what is its governor? * If has no governor, but is reference, then tries the * referenced stuff... If not known, returns NULL. */ @@ -565,8 +572,6 @@ namespace Common { /** Used to determine whether the reference points to value or * template in ISCHOSEN, then convert to {ISCHOSEN}_{V,T} */ void chk_expr_ref_ischosen(); - void chk_expr_operandtype_enum(const char *opname, Value *v, - Type::expected_value_t exp_val); void chk_expr_operandtype_bool(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc); void chk_expr_operandtype_int(Type::typetype_t tt, const char *opnum, @@ -697,7 +702,8 @@ namespace Common { * should be a referenced value pointing to a optional record/set field. */ void chk_expr_omit_comparison(Type::expected_value_t exp_val); Int chk_eval_expr_sizeof(ReferenceChain *refch, - Type::expected_value_t exp_val); + Type::expected_value_t exp_val, + Type* def_alt_type = NULL); /** The governor is returned. */ Type *chk_expr_operands_ti(TemplateInstance* ti, Type::expected_value_t exp_val); void chk_expr_operands_match(Type::expected_value_t exp_val); @@ -709,6 +715,17 @@ namespace Common { void chk_expr_operands(ReferenceChain *refch, Type::expected_value_t exp_val); void chk_expr_operand_valid_float(Value* v, const char *opnum, const char *opname); + /** Checks whether the type of the specified union value has a @default alternative. + * If it is, then the default alternative's subreference is appended to the end of + * the value (which must be a reference) and 'chk_expr_operands' is re-called. */ + bool chk_expr_operand_default_alternative(Value* v, ReferenceChain *refch, + Type::expected_value_t exp_val); + /** Checks whether the template instance is a reference to a value or template of a union + * type, that has a @default alternative. + * If it is, then the default alternative's subreference is appended to the end of + * the value/template reference and 'chk_expr_operands' is re-called. */ + bool chk_expr_operand_default_alternative(TemplateInstance* ti, Type* ti_gov, + ReferenceChain *refch, Type::expected_value_t exp_val); /** Evaluate... * Called by Value::get_value_refd_last() for V_EXPR */ void evaluate_value(ReferenceChain *refch, Type::expected_value_t exp_val); diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index f3f13e321bf03cb3cde763e4fd0d8cbd246b8b4c..e5d3569b29b367ea7e45063b885afab7d8ff4c33 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -554,6 +554,14 @@ namespace Ttcn { { for (size_t i = 0; i < refs.size(); i++) refs[i]->append_stringRepr(str); } + + void FieldOrArrayRefs::use_default_alternative(size_t p_idx, const Identifier& p_alt_name) + { + FieldOrArrayRef* alt_ref = new FieldOrArrayRef(new Identifier(p_alt_name)); + alt_ref->set_my_scope(my_scope); + refs.insert(alt_ref, p_idx); + set_fullname(get_fullname()); + } // ================================= // ===== Ref_base @@ -564,7 +572,7 @@ namespace Ttcn { { modid = p.modid ? p.modid->clone() : 0; id = p.id ? p.id->clone() : 0; - params_checked = p.is_erroneous; + params_checked = p.params_checked; } Ref_base::Ref_base(Identifier *p_modid, Identifier *p_id) @@ -696,10 +704,11 @@ namespace Ttcn { // ================================= Reference::Reference(const Reference& p) - : Ref_base(p), reftype(p.reftype), parlist(NULL), gen_const_prefix(false), + : Ref_base(p), reftype(p.reftype), gen_const_prefix(false), expr_cache(NULL) { params = p.params != NULL ? p.params->clone() : NULL; + parlist = p.parlist != NULL ? p.parlist->clone() : NULL; } Reference::Reference(Identifier *p_id) @@ -1084,6 +1093,16 @@ namespace Ttcn { } } + + void Reference::use_default_alternative(const Identifier& p_alt_name) + { + FieldOrArrayRef* alt_ref = new FieldOrArrayRef(new Identifier(p_alt_name)); + alt_ref->set_my_scope(my_scope); + alt_ref->set_fullname(get_fullname() + + ".<sub_reference" + Int2string(subrefs.get_nof_refs()) + ">"); + subrefs.add(alt_ref); + } + void Reference::set_code_section( GovernedSimple::code_section_t p_code_section) { diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 2d7039ac1dd358e8abb3fa70180455deabd9a681..39ac73082b8e4adb948ad1e821d5ed4ee4a54673 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -288,6 +288,10 @@ namespace Ttcn { bool refers_to_string_element() const { return refs_str_element; } void set_string_element_ref() { refs_str_element = true; } void clear_string_element_ref() { refs_str_element = false; } + /** Adds a new field ref for the union type's @default alternative at the specified index. + * Used when the subreference at the given index is not a valid field name or array index + * for the union type it is attributed to. This attempts to use the union's default alternative instead. */ + void use_default_alternative(size_t p_idx, const Identifier& p_alt_name); }; /** @@ -409,6 +413,10 @@ namespace Ttcn { /** Lets the referenced assignment object know, that the reference is used * at least once (only relevant for formal parameters and external constants). */ void ref_usage_found(); + /** Appends a new field subref for the union type's @default alternative at the end of the reference. + * Used when the reference points to a union value or template in a context where a union is not allowed. + * This attempts to use the union's default alternative instead. */ + void use_default_alternative(const Identifier& p_alt_name); private: /** Detects whether the first identifier in subrefs is a module id */ void detect_modid(); diff --git a/compiler2/ttcn3/PatternString.cc b/compiler2/ttcn3/PatternString.cc index 89cc7350ba72ae0dcd7ba2b51b3ee287caf22a6b..2a355cf6cafd02a4014a2f45ee463b7ac57c7423 100644 --- a/compiler2/ttcn3/PatternString.cc +++ b/compiler2/ttcn3/PatternString.cc @@ -276,7 +276,8 @@ namespace Ttcn { // ================================= PatternString::PatternString(const PatternString& p) - : Node(p), my_scope(0), cstr_value(0), pattern_type(p.pattern_type) + : Node(p), my_scope(0), cstr_value(0), pattern_type(p.pattern_type), + nocase(p.nocase) { size_t nof_elems = p.elems.size(); for (size_t i = 0; i < nof_elems; i++) elems.add(p.elems[i]->clone()); diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 7b6fc066286f82b4f2c9cd4c311a359cc4b448d1..9c69f8e8854fd2b73bf0ad4ed37ea5591b3816f9 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -3003,10 +3003,24 @@ namespace Ttcn { error("Could not determine the assignment for second parameter"); goto error; } - if (Type::T_ENUM_T != convert_op.ref->chk_variable_ref()->get_type_refd_last()->get_typetype_ttcn3()) { - convert_op.ref->error("A reference to variable or value parameter of " - "type enumerated was expected"); - goto error; + { + Type* t = convert_op.ref->chk_variable_ref()->get_type_refd_last(); + Type::typetype_t tt = t->get_typetype_ttcn3(); + if (Type::T_ENUM_T != tt) { + if (Type::T_CHOICE_T == tt) { + CompField* def_alt = t->get_default_alternative(); + if (def_alt != NULL) { + Error_Context cntxt2(convert_op.ref, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); + convert_op.ref->use_default_alternative(def_alt->get_name()); + chk_int2enum(); + return; + } + } + convert_op.ref->error("A reference to variable or value parameter of " + "type enumerated was expected"); + goto error; + } } return; error: @@ -5953,6 +5967,18 @@ error: } } break; + case Type::T_CHOICE_T: + if (v->is_ref()) { + CompField* def_alt = ret_val->get_default_alternative(); + Reference* ttcn_ref = dynamic_cast<Reference*>(v->get_reference()); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(v, "Using default alternative `%s' in value of union type `%s'", + def_alt->get_name().get_dispname().c_str(), ret_val->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + return chk_comp_ref(p_val, allow_mtc, allow_system, p_any_from); + } + } + break; default: break; } diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index a1c734238f80e97f595fcdbd1d6bed37b197713a..808d039d02697c5b93446c3982573e75e1dcc954 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -42,7 +42,8 @@ namespace Ttcn { Template::Template(const Template& p) : GovernedSimple(p), templatetype(p.templatetype), my_governor(p.my_governor), is_ifpresent(p.is_ifpresent), specific_value_checked(false), - has_permutation(p.has_permutation), base_template(p.base_template) + has_permutation(p.has_permutation), flattened(p.flattened), + base_template(p.base_template) { switch (templatetype) { case TEMPLATE_ERROR: @@ -1431,6 +1432,27 @@ namespace Ttcn { return 0; } else return u.templates->get_t_byIndex(n); } + + void Template::use_default_alternative(Type* p_union_type) + { + if (templatetype == TEMPLATE_ERROR) { + return; + } + CompField* def_alt = p_union_type->get_default_alternative(); + if (def_alt == NULL) { + FATAL_ERROR("Value::use_default_alternative"); + } + Template* def_temp = clone(); + def_temp->my_governor = def_alt->get_type(); + def_temp->set_my_scope(my_scope); + def_temp->set_fullname(get_fullname() + ".<default_alternative>"); + clean_up(); + NamedTemplate* nt = new NamedTemplate(def_alt->get_name().clone(), def_temp); + templatetype = NAMED_TEMPLATE_LIST; + u.named_templates = new NamedTemplates; + u.named_templates->add_nt(nt); + my_governor = p_union_type; + } /** \todo revise and merge with get_template_refd() */ Template* Template::get_template_refd_last(ReferenceChain *refch) @@ -2989,6 +3011,17 @@ end: delete new_templates; // cannot flatten at compile time new_templates = 0; break; + case Common::Type::T_CHOICE_T: { + CompField* def_alt = type->get_default_alternative(); + Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); + if (def_alt != NULL && ttcn_ref != NULL) { + Error_Context cntxt(t, "Using default alternative `%s' in template of union type `%s'", + def_alt->get_name().get_dispname().c_str(), type->get_typename().c_str()); + ttcn_ref->use_default_alternative(def_alt->get_name()); + delete new_templates; + return harbinger(t, from_permutation, killer); + } + /* otherwise fall through */ } default: { // not an array type => error const char* ass_name = ass->get_assname(); @@ -3028,6 +3061,7 @@ end: } type->error("%s of type `%s' can not be used as target of 'all from'", descr.c_str(), type->get_typename().c_str()); + delete new_templates; break; } } } // switch(typetype) @@ -4066,10 +4100,10 @@ end: char* str_set_size = NULL; char* str_preamble = NULL; char* str_body = NULL; - string counter = get_temporary_id(); + string counter_str = get_temporary_id(); if (has_permutation || has_allfrom()) { - str_body = mputprintf(str_body, "int %s = %lld;\n", counter.c_str(), index_offset); + str_body = mputprintf(str_body, "int %s = %lld;\n", counter_str.c_str(), index_offset); for (size_t i = 0; i < nof_ts; ++i) { Template *t = u.templates->get_t_byIndex(i); if (t->templatetype == ALL_FROM) { @@ -4172,16 +4206,16 @@ end: "for (int i_i = 0, i_lim = %s.n_elem(); i_i < i_lim; ++i_i) {\n", expr.expr); str_body = t->generate_code_init_seof_element(str_body, name, - (counter + " + i_i").c_str(), + (counter_str + " + i_i").c_str(), oftype_name_str); str_body = mputstrn(str_body, "}\n", 2); - str_body = mputprintf(str_body, "%s += %s.n_elem();\n", counter.c_str(), expr.expr); + str_body = mputprintf(str_body, "%s += %s.n_elem();\n", counter_str.c_str(), expr.expr); Code::free_expr(&expr); t->set_code_generated(); } else if (t->templatetype == PERMUTATION_MATCH) { string permutation_start = get_temporary_id(); str_body = mputprintf(str_body, "int %s = %s;\n", - permutation_start.c_str(), counter.c_str()); + permutation_start.c_str(), counter_str.c_str()); size_t nof_perm_ts = t->u.templates->get_nof_ts(); for (size_t j = 0; j < nof_perm_ts; j++) { Template *subt = t->u.templates->get_t_byIndex(j); @@ -4240,7 +4274,7 @@ end: } else { fixed_part++; str_body = subt->generate_code_init_seof_element(str_body, name, - counter.c_str(), oftype_name_str); + counter_str.c_str(), oftype_name_str); } if (subt->templatetype == ALL_FROM) { @@ -4294,29 +4328,29 @@ end: expr.expr); str_body = subt->generate_code_init_seof_element(str_body, name, - (counter + " + i_i").c_str(), + (counter_str + " + i_i").c_str(), oftype_name_str); str_body = mputstrn(str_body, "}\n", 2); - str_body = mputprintf(str_body, "%s += %s.n_elem();\n", counter.c_str(), expr.expr); + str_body = mputprintf(str_body, "%s += %s.n_elem();\n", counter_str.c_str(), expr.expr); Code::free_expr(&expr); } else { str_body = subt->generate_code_init_seof_element(str_body, name, - counter.c_str(), oftype_name_str); - str_body = mputprintf(str_body, "%s++;\n", counter.c_str()); + counter_str.c_str(), oftype_name_str); + str_body = mputprintf(str_body, "%s++;\n", counter_str.c_str()); } } // do not consider index_offset in case of permutation indicators str_body = mputprintf(str_body, "%s.add_permutation(%s-%lld, %s-%lld-1);\n", name, - permutation_start.c_str(), index_offset, counter.c_str(), index_offset); + permutation_start.c_str(), index_offset, counter_str.c_str(), index_offset); t->set_code_generated(); } else { fixed_part++; str_body = t->generate_code_init_seof_element(str_body, name, - counter.c_str(), oftype_name_str); - str_body = mputprintf(str_body, "%s++;\n", counter.c_str()); + counter_str.c_str(), oftype_name_str); + str_body = mputprintf(str_body, "%s++;\n", counter_str.c_str()); } } str = mputstr(str, str_preamble); diff --git a/compiler2/ttcn3/TtcnTemplate.hh b/compiler2/ttcn3/TtcnTemplate.hh index 8681438994e3ca0b1f8d67a567340dfb819baec1..4fd69e2e8180921b285dbf69b69bcb5fa347b618 100644 --- a/compiler2/ttcn3/TtcnTemplate.hh +++ b/compiler2/ttcn3/TtcnTemplate.hh @@ -296,6 +296,14 @@ namespace Ttcn { * PERMUTATION_MATCH constructs are also counted. */ Template *get_listitem_byIndex(size_t n) const; + /** Converts the template into a named template list, with one element that + * has the union type's @default alternative as its name and the original template (cloned) + * as its value. + * Used when a template of a different type appears in a context, where a template of + * the specified union type was expected. + * This attempts to use the template as the union's default alternative instead. */ + void use_default_alternative(Type* p_union_type); + Template* get_template_refd_last(ReferenceChain *refch=0); Template* get_refd_sub_template(Ttcn::FieldOrArrayRefs *subrefs, bool usedInIsbound, diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l index 56afedbbb9a5950a7c041b69d3f09b0c2897ad67..b4ddd18e95413e6d9ee67e54c17324d9eac4ccd3 100644 --- a/compiler2/ttcn3/compiler.l +++ b/compiler2/ttcn3/compiler.l @@ -630,6 +630,7 @@ object { "@local" RETURN(LocalKeyword); "@final" RETURN(FinalKeyword); "@abstract" RETURN(AbstractKeyword); +"@default" RETURN(DefaultModifier); /* special TITAN specific keywords */ diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 9f5c4a18adab05472fbfe0710f7c47bb98a8fc53..7ec431d7893f28df167ebc8edc045dd2619af48b 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -821,6 +821,7 @@ static const string anyname("anytype"); %token LocalKeyword %token FinalKeyword %token AbstractKeyword +%token DefaultModifier /* TITAN specific keywords */ %token TitanSpecificTryKeyword @@ -957,7 +958,7 @@ static const string anyname("anytype"); %type <bool_val> optAliveKeyword optOptionalKeyword optErrValueRaw optAllKeyword optDeterministicModifier optRealtimeClause - optExtKeyword optFinalModifier optAbstractModifier + optExtKeyword optFinalModifier optAbstractModifier optDefaultModifier %type <str> FreeText optLanguageSpec PatternChunk PatternChunkList %type <uchar_val> Group Plane Row Cell %type <id> FieldReference GlobalModuleId @@ -2634,25 +2635,30 @@ UnionFieldDefList: | error { $$ = new CompFieldMap; } ; +optDefaultModifier: + /* empty */ { $$ = false; } +| DefaultModifier { $$ = true; } +; + UnionFieldDef: // 34 - TypeOrNestedTypeDef IDentifier optArrayDef optSubTypeSpec + optDefaultModifier TypeOrNestedTypeDef IDentifier optArrayDef optSubTypeSpec { - if ($4) { + if ($5) { /* The subtype constraint belongs to the innermost embedded type of * possible nested 'record of' or 'set of' constructs. */ - Type *t = $1; + Type *t = $2; while (t->is_seof()) t = t->get_ofType(); - t->set_parsed_restrictions($4); + t->set_parsed_restrictions($5); } - Type *type = $1; + Type *type = $2; /* creation of array type(s) if necessary (from right to left) */ - for (size_t i = $3.nElements; i > 0; i--) { - type = new Type(Type::T_ARRAY, type, $3.elements[i - 1], true); - type->set_location(*$1); + for (size_t i = $4.nElements; i > 0; i--) { + type = new Type(Type::T_ARRAY, type, $4.elements[i - 1], true); + type->set_location(*$2); } - Free($3.elements); - $$ = new CompField($2, type, false); - $$->set_location(infile, @$); + Free($4.elements); + $$ = new CompField($3, type, false, 0, $1); + $$->set_location(infile, $1 ? @1 : @2, @5); } ; diff --git a/compiler2/vector.hh b/compiler2/vector.hh index 25017e827222e127258442626d6021fc5f9c5e42..ff992570ab0c4701f676eb128fe9f7189a0b19dd 100644 --- a/compiler2/vector.hh +++ b/compiler2/vector.hh @@ -129,6 +129,29 @@ public: num_e++; e_ptr[0] = elem; } + + /** Inserts the elem to a specified position in the vector. */ + void insert(T* elem, size_t pos) { + if (e_ptr == NULL) { + e_ptr = static_cast<T**>(Malloc(initial_size * sizeof(*e_ptr))); + } + else { + size_t max_e = initial_size; + while (max_e < num_e) { + max_e *= increment_factor; + } + if (max_e <= num_e) { + if (max_e >= max_vector_length / increment_factor) { + FATAL_ERROR("vector::insert(): vector index overflow"); + } + e_ptr = static_cast<T**> + (Realloc(e_ptr, max_e * increment_factor * sizeof(*e_ptr))); + } + } + memmove(e_ptr + pos + 1, e_ptr + pos, (num_e - pos) * sizeof(*e_ptr)); + num_e++; + e_ptr[pos] = elem; + } /** Returns the <em>n</em>th element. The index of the first element is * zero. If no such index, then FATAL_ERROR occurs. */ diff --git a/function_test/Semantic_Analyser/Makefile.semantic b/function_test/Semantic_Analyser/Makefile.semantic index e36e6ad41ec9a8bde4d211dab3ec5d02801c5be0..f1c85fadf4e7ec6b2ad3bac05acc81c7ab3a1af9 100644 --- a/function_test/Semantic_Analyser/Makefile.semantic +++ b/function_test/Semantic_Analyser/Makefile.semantic @@ -16,7 +16,7 @@ include ../../Makefile.personal SADIRS := ver param template any_from pattern_ref float recof_index \ port_translation mtc_and_system_clause port_map_connect deterministic invoking_function_from_specific_places \ -json realtime map_param oop +json realtime map_param oop defaultAlternative ifdef RT2 SADIRS += deprecated erroneous_attributes template_concat endif diff --git a/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script index e8f6ef574ddc03e008d1ecf3b166debd1cb4ec09..d2eb3ece9e487c0d7b6adc8dd4bdb0b35bf87285 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_5_TD.script @@ -4080,12 +4080,9 @@ template boolean b3 := b1 @> 1 } <END_MODULE> <RESULT COUNT 2> -(?im)operand.+?should.+?be.+?string.+?value -<END_RESULT> -<RESULT COUNT 2> (?im)reference.+?to.+?value.+?expected.+?instead.+?of.+?template <END_RESULT> -<RESULT COUNT 4> +<RESULT COUNT 2> (?is)\berror: <END_RESULT> <RESULT> @@ -4726,15 +4723,12 @@ template rtype r3 := r1 & r2 } <END_MODULE> <RESULT LTRT COUNT 2> -(?im)operand.+?should.+?be.+?string.+?value -<END_RESULT> -<RESULT LTRT COUNT 2> (?im)reference.+?to.+?value.+?expected.+?instead.+?of.+?template <END_RESULT> <RESULT FTRT COUNT 2> (?im)Templates.+?of.+?type.+?`@Temp.rtype'.+?cannot.+?be.+?concatenated <END_RESULT> -<RESULT LTRT COUNT 4> +<RESULT LTRT COUNT 2> (?is)\berror: <END_RESULT> <RESULT FTRT COUNT 2> @@ -4852,12 +4846,9 @@ template utype u3 := u1 @> 1 } <END_MODULE> <RESULT COUNT 2> -(?im)operand.+?should.+?be.+?string.+?value -<END_RESULT> -<RESULT COUNT 2> (?im)reference.+?to.+?value.+?expected.+?instead.+?of.+?template <END_RESULT> -<RESULT COUNT 4> +<RESULT COUNT 2> (?is)\berror: <END_RESULT> <RESULT> diff --git a/function_test/Semantic_Analyser/defaultAlternative/.gitignore b/function_test/Semantic_Analyser/defaultAlternative/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2d293255e6d2f314e34950e486a48630d873491 --- /dev/null +++ b/function_test/Semantic_Analyser/defaultAlternative/.gitignore @@ -0,0 +1,2 @@ +!Makefile +!*.ttcn diff --git a/function_test/Semantic_Analyser/defaultAlternative/Makefile b/function_test/Semantic_Analyser/defaultAlternative/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..064785297138a4348dad364eab61948e5f3053df --- /dev/null +++ b/function_test/Semantic_Analyser/defaultAlternative/Makefile @@ -0,0 +1,12 @@ +############################################################################## +# Copyright (c) 2000-2020 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################## +include ../common.mk diff --git a/function_test/Semantic_Analyser/defaultAlternative/defaultAlternative_SE.ttcn b/function_test/Semantic_Analyser/defaultAlternative/defaultAlternative_SE.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..f75040b76c617c0790393058a298aede1a0457d1 --- /dev/null +++ b/function_test/Semantic_Analyser/defaultAlternative/defaultAlternative_SE.ttcn @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2000-2020 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +module defaultAlternative_SE { //^In TTCN-3 module// + +type union MyDefaultUnionType { + @default integer number, + charstring string //Field `string' of the default alternative is here// +} + +type union MyDefaultUnionType2 { + @default MyDefaultUnionType ageInYears, //Field `ageInYears' of the default alternative is here// + integer ageInDays +} + +type union MyUnionTypeWithDefaultErr { //^In type definition// + @default //Duplicate union field name `ageInYears'// + MyDefaultUnionType2 ageInYears, + charstring string //Duplicate union field name `string'// +} + +type union MyUnionTypeWithTwoDefaults { //^In type definition// + @default integer number, //The `@default' modifier was already used here// + charstring string, + @default octetstring bytes //Multiple union fields defined with the `@default' modifier// +} + +} diff --git a/function_test/Semantic_Analyser/defaultAlternative/t b/function_test/Semantic_Analyser/defaultAlternative/t new file mode 100755 index 0000000000000000000000000000000000000000..3a4b58ec16cf2f1390a36c7a92f8823e3b94b425 --- /dev/null +++ b/function_test/Semantic_Analyser/defaultAlternative/t @@ -0,0 +1,9 @@ +#!/usr/bin/perl +# note this is called through "perl -w" +use strict; + +my $self = $0; +$self =~ s!/t!!; + +exec('make check --no-print-directory -s -C ' . $self); + diff --git a/function_test/Semantic_Analyser/template/TempNoDefaultOrPort_SE.ttcn b/function_test/Semantic_Analyser/template/TempNoDefaultOrPort_SE.ttcn index 499e6d66227facd56d8f1cf35f388dd911f1ca7e..0171c1ff1aa5f1556fbc2c0e19749861c9b0b588 100644 --- a/function_test/Semantic_Analyser/template/TempNoDefaultOrPort_SE.ttcn +++ b/function_test/Semantic_Analyser/template/TempNoDefaultOrPort_SE.ttcn @@ -46,4 +46,4 @@ type record MyRecordDefault { //In type \`\@TempNoDefaultOrPort\_SE\.MyRecordDef } with { extension "anytype MyRecordDefault2" //In field \`MyRecordDefault2\'\:// -} \ No newline at end of file +} diff --git a/regression_test/Makefile b/regression_test/Makefile index d863ec973f1716889efcaa208e8dac18934b6dc6..2b62cc01d5d255ea551bf3913ec7ad9215678616 100644 --- a/regression_test/Makefile +++ b/regression_test/Makefile @@ -50,7 +50,7 @@ customEncoding makefilegen uidChars checkstate hostid templateIstemplatekind \ selectUnion templateExclusiveRange any_from templatePatternRef indexWithRecofArray \ connectMapOperTest fuzzy portTranslation ischosen functionSubref done \ nondeterministicDefaultParam predefFunction2 realtime portTranslationCentralStorage \ -locale oop references unicharstrToCharstr +locale oop references unicharstrToCharstr defaultAlternative ifdef DYN DIRS += loggerplugin junitlogger diff --git a/regression_test/defaultAlternative/.gitignore b/regression_test/defaultAlternative/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..126ab1ca4c4c18dd05205616eff3186ee6390871 --- /dev/null +++ b/regression_test/defaultAlternative/.gitignore @@ -0,0 +1,5 @@ +defaultAlternative +defaultAlternative.exe +defaultAlternative*.cc +defaultAlternative*.hh +defaultAlternative*.log diff --git a/regression_test/defaultAlternative/Makefile b/regression_test/defaultAlternative/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fc8e5701d783e5496c838150fce040adf3b73e24 --- /dev/null +++ b/regression_test/defaultAlternative/Makefile @@ -0,0 +1,56 @@ +############################################################################## +# Copyright (c) 2000-2020 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################## +TOPDIR := .. +include $(TOPDIR)/Makefile.regression + +.SUFFIXES: .ttcn .hh +.PHONY: all clean dep run + +TTCN3_LIB = ttcn3$(RT2_SUFFIX)-parallel$(DYNAMIC_SUFFIX) + +TTCN3_MODULES = defaultAlternative.ttcn + +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) +GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) +ifdef CODE_SPLIT +GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc)) +else ifdef SPLIT_TO_SLICES +POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_)) +POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc)) +GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES))) +GENERATED_SOURCES += $(GENERATED_SOURCES2) +endif + +OBJECTS = $(GENERATED_SOURCES:.cc=.o) + +TARGET = defaultAlternative$(EXESUFFIX) + +all: $(TARGET) + +$(TARGET): $(GENERATED_SOURCES) $(USER_SOURCES) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS) + +.ttcn.cc .ttcn.hh: + $(TTCN3_COMPILER) $< + +clean distclean: + -rm -f $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) *.log Makefile.bak + +dep: $(GENERATED_SOURCES) + makedepend $(CPPFLAGS) $(GENERATED_SOURCES) + +run: $(TARGET) + ttcn3_start $(TARGET) config.cfg + +.NOTPARALLEL: + diff --git a/regression_test/defaultAlternative/config.cfg b/regression_test/defaultAlternative/config.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e9f0745a7b6c56b05c0e6d5b3306ede9dbf5b29d --- /dev/null +++ b/regression_test/defaultAlternative/config.cfg @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2000-2020 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################### +[MODULE_PARAMETERS] +[LOGGING] +Logfile := "defaultAlternative.log" +FileMask := LOG_ALL +ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS +[EXECUTE] +defaultAlternative diff --git a/regression_test/defaultAlternative/defaultAlternative.ttcn b/regression_test/defaultAlternative/defaultAlternative.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..6cbae29a067cc8d9e307f46a079c560feecabd32 --- /dev/null +++ b/regression_test/defaultAlternative/defaultAlternative.ttcn @@ -0,0 +1,800 @@ +/****************************************************************************** + * Copyright (c) 2000-2020 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +module defaultAlternative { + +type record Rec { + integer num, + charstring str optional +} +with { + encode "JSON"; +} + +type record of integer RecOf; + +type enumerated Enum { first (0), second }; + +type union Uni { + integer num, + charstring str +} + +type union UniDefInt { + @default integer def, + charstring str +} + +type union UniDefStr { + @default charstring def, + integer num +} + +type union UniDefRec { + @default Rec def, + boolean bool +} + +type union UniDefRecOf { + boolean bool, + @default RecOf def +} + +type union UniDefUni { + boolean bool, + @default Uni def +} + +type union UniDefIntEmb { + @default UniDefInt def2, + octetstring oct +} + +type union UniDefIntDblEmb { + @default UniDefIntEmb def3, + Rec rec +} + +type union UniWithDefStr { + UniDefStr uni, + octetstring oct +} + +type union UniDefStrEmbBroken { + @default UniWithDefStr def2, + boolean bool +} + +type union UniDefBool { + @default boolean def, + integer num +} + +type union UniDefBit { + @default bitstring def, + integer num +} + +type union UniDefEnum { + @default Enum def +} + +type union UniDefFloat { + @default float def +} + +type union UniDefHex { + @default hexstring def +} + +type union UniDefOct { + @default octetstring def +} + +type union UniDefUstr { + @default universal charstring def +} + +type union UniDefVerdict { + @default verdicttype def +} + +type union UniDefComp { + @default CT def +} + +type port PT message { + inout integer +} +with { extension "internal" } + +type component CT { + timer tmr_comp; + port PT pt; +} + +type union UniDefDef { + @default default def +} + +testcase tc_init_and_assign() runs on CT { + var UniDefInt u1 := 3; + if (u1.def != 3) { + setverdict(fail, "u1: ", u1); + } + + var UniDefStr u2; + u2 := "abc"; + if (u2.def != "abc") { + setverdict(fail, "u2: ", u2); + } + + var UniDefRec u3 := { num := 4, str := "xy" }; + if (u3.def != { num := 4, str := "xy" }) { + setverdict(fail, "u3: ", u3); + } + + u3.num := 5; + if (u3.def != { num := 5, str := "xy" }) { + setverdict(fail, "u3 mod: ", u3); + } + + var UniDefRecOf u4 := { 1, 2, 3 }; + if (u4.def != { 1, 2, 3}) { + setverdict(fail, "u4: ", u4); + } + + u4[2] := 4; + if (u4.def != { 1, 2, 4}) { + setverdict(fail, "u4 mod: ", u4); + } + + var UniDefUni u5 := { str := "def" }; + if (u5.def.str != "def") { + setverdict(fail, "u5: ", u5); + } + + u5.num := 0; + if (u5.def.num != 0) { + setverdict(fail, "u5 mod: ", u5); + } + + var UniDefIntEmb u6 := 2; + if (u6.def2.def != 2) { + setverdict(fail, "u6: ", u6); + } + + var UniDefIntDblEmb u7 := 1; + if (u7.def3.def2.def != 1) { + setverdict(fail, "u7: ", u7); + } + + var UniDefStrEmbBroken u8; + u8.uni := "ghi"; + if (u8.def2.uni.def != "ghi") { + setverdict(fail, "u8: ", u8); + } + + var UniDefEnum u9 := first; + if (u9.def != first) { + setverdict(fail, "u9: ", u9); + } + u9 := second; + if (u9.def != second) { + setverdict(fail, "u9 mod: ", u9); + } + + var template UniDefInt tu1 := 3; + var template UniDefInt tu1_exp := { def := 3 }; + if (log2str(tu1) != log2str(tu1_exp)) { + setverdict(fail, "tu1: ", tu1); + } + + var template UniDefInt tu2 := (0..4); + var template UniDefInt tu2_exp := { def := (0..4) }; + if (log2str(tu2) != log2str(tu2_exp)) { + setverdict(fail, "tu2: ", tu2); + } + + var template UniDefIntEmb tu3 := (1, 2, 3, (6..10)); + var template UniDefIntEmb tu3_exp := ( + { def2 := { def := 1 } }, + { def2 := { def := 2 } }, + { def2 := { def := 3 } }, + { def2 := { def := (6 .. 10) } } + ); + if (log2str(tu3) != log2str(tu3_exp)) { + setverdict(fail, "tu3: ", tu3); + } + + var template UniDefStr tu4 := "abc"; + var template UniDefStr tu4_exp := { def := "abc" }; + if (log2str(tu4) != log2str(tu4_exp)) { + setverdict(fail, "tu4: ", tu4); + } + tu4[1] := "z"; + tu4_exp.def[1] := "z"; + if (log2str(tu4) != log2str(tu4_exp)) { + setverdict(fail, "tu4 mod: ", tu4); + } + + var template UniDefStr tu5; + tu5 := pattern "ab?c"; + var template UniDefStr tu5_exp := { def := pattern "ab?c" }; + if (log2str(tu5) != log2str(tu5_exp)) { + setverdict(fail, "tu5: ", tu5); + } + + var template UniDefRec tu6 := { num := 1, str := "xy" }; + var template UniDefRec tu6_exp := { def := { num := 1, str := "xy" } }; + if (log2str(tu6) != log2str(tu6_exp)) { + setverdict(fail, "tu6: ", tu6); + } + tu6.num := -6; + tu6_exp.def.num := -6; + if (log2str(tu6) != log2str(tu6_exp)) { + setverdict(fail, "tu6 mod: ", tu6); + } + + var template UniDefRec tu7 := { 1, "xy" }; + var template UniDefRec tu7_exp := { def := { 1, "xy" } }; + if (log2str(tu7) != log2str(tu7_exp)) { + setverdict(fail, "tu7: ", tu7); + } + + var template UniDefRecOf tu8 := { 1, 2, 3 }; + var template UniDefRecOf tu8_exp := { def := { 1, 2, 3 } }; + if (log2str(tu8) != log2str(tu8_exp)) { + setverdict(fail, "tu8: ", tu8); + } + tu8[1] := 22; + tu8_exp.def[1] := 22; + if (log2str(tu8) != log2str(tu8_exp)) { + setverdict(fail, "tu8 mod: ", tu8); + } + + var template UniDefRecOf tu9 := { [1] := 1, [0] := 0 }; + var template UniDefRecOf tu9_exp := { def := { [1] := 1, [0] := 0 } }; + if (log2str(tu9) != log2str(tu9_exp)) { + setverdict(fail, "tu9: ", tu9); + } + + var template UniDefUni tu10 := { str := "qwe" }; + var template UniDefUni tu10_exp := { def := { str := "qwe" } }; + if (log2str(tu10) != log2str(tu10_exp)) { + setverdict(fail, "tu10: ", tu10); + } + tu10.num := 2; + tu10_exp.def.num := 2; + if (log2str(tu10) != log2str(tu10_exp)) { + setverdict(fail, "tu10 mod: ", tu10); + } + + var template UniDefEnum tu11 := first; + var template UniDefEnum tu11_exp := { def := first }; + if (log2str(tu11) != log2str(tu11_exp)) { + setverdict(fail, "tu11: ", tu11); + } + tu11 := second; + tu11_exp.def := second; + if (log2str(tu11) != log2str(tu11_exp)) { + setverdict(fail, "tu11 mod: ", tu11); + } + setverdict(pass); +} + +testcase tc_ref() runs on CT { + var UniDefInt u1 := 1; + var integer i1 := u1; + if (i1 != 1) { + setverdict(fail, "i1: ", i1); + } + + var UniDefRec u2 := { num := 4, str := "xy" }; + var charstring cs1 := u2.str; + if (cs1 != "xy") { + setverdict(fail, "cs1: ", cs1); + } + + var UniDefRecOf u3 := { 1, 2, 3 }; + var integer i2 := u3[1]; + if (i2 != 2) { + setverdict(fail, "i2: ", i2); + } + + var charstring cs2 := "abc"; + var UniDefStr u4 := cs2; + if (u4.def != "abc") { + setverdict(fail, "u4: ", u4); + } + + var UniDefIntEmb u5 := u1; + if (u5.def2.def != 1) { + setverdict(fail, "u5: ", u5); + } + + var UniDefStrEmbBroken u6 := { uni := cs2 }; + if (u6.def2.uni.def != "abc") { + setverdict(fail, "u6: ", u6); + } + + var template UniDefRecOf tu1 := { 1, 2, 3 }; + var template integer ti1 := (0, all from tu1); + var template integer ti1_exp := (0, all from tu1.def); + if (log2str(ti1) != log2str(ti1_exp)) { + setverdict(fail, "ti1: ", ti1); + } + /*template UniDefRecOf tu2 := { 1, 2, 3 }; TODO + template integer ti2 := (0, all from tu2); + template integer ti2_exp := (0, all from tu2.def); + if (log2str(ti2) != log2str(ti2_exp)) { + setverdict(fail, "ti2: ", ti2); + } + var template UniDefInt tu3 := (0, all from tu1); + var template UniDefInt tu3_exp := (0, all from tu1.def); + if (log2str(tu3) != log2str(tu3_exp)) { + setverdict(fail, "tu3: ", tu3); + }*/ + var template RecOf tro1 := { 0, permutation(all from tu1) }; + var template RecOf tro1_exp := { 0, permutation(all from tu1.def) }; + if (log2str(tro1) != log2str(tro1_exp)) { + setverdict(fail, "tro1: ", tro1); + } + setverdict(pass); +} + +testcase tc_expr() runs on CT { + var UniDefInt u1 := 2; + var integer i1 := u1 + 1; + if (i1 != 3) { + setverdict(fail, "i1: ", i1); + } + + var UniDefInt u2 := 3; + var UniDefInt u3 := ((+u1 - -u2) * (u2 + -1)) / (5 rem u2 + u2 mod 4); + if (u3.def != 2) { + setverdict(fail, "u3: ", u3); + } + + var UniDefStr u4 := "xy"; + var charstring cs1 := u4 & "a" & (u4 & u4) & "b" & u4; + if (cs1 != "xyaxyxybxy") { + setverdict(fail, "cs1: ", cs1); + } + + var UniDefRecOf u5 := { 1, 2, 3 }; + var RecOf ro1 := u5 & { 0 } & (u5 & u5) & { 6 } & u5; + if (ro1 != { 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 6, 1, 2, 3}) { + setverdict(fail, "ro1: ", ro1); + } + + var integer i2 := 4; + var UniDefIntEmb u6 := 4; + if (not i2 == u6) { + setverdict(fail, "ref not equal"); + } + if (u6 == u2) { + setverdict(fail, "ref equal"); + } + if (i2 == u6 - 1) { + setverdict(fail, "expr not equal"); + } + if (not u6 == u2 + 1) { + setverdict(fail, "ref equal"); + } + if (i2 < u6) { + setverdict(fail, "less than"); + } + if (u2 > u6) { + setverdict(fail, "greater than"); + } + if (u6 <= u2) { + setverdict(fail, "less or equal"); + } + if (u2 >= u6) { + setverdict(fail, "greater or equal"); + } + + var UniDefBool u7 := true; + if (not u7) { + setverdict(fail, "not u7"); + } + if (u7 and false) { + setverdict(fail, "and u7"); + } + if (not (false or u7)) { + setverdict(fail, "or u7"); + } + if (true xor u7) { + setverdict(fail, "xor u7"); + } + + var UniDefBit u8 := '1100'B; + var bitstring bs1 := (((not4b u8) xor4b u8) and4b u8) or4b u8; + if (bs1 != '1100'B) { + setverdict(fail, "bs1: ", bs1); + } + + var bitstring bs2 := u8 << 2; + if (bs2 != '0000'B) { + setverdict(fail, "bs2: ", bs2); + } + var UniDefBit u9 := u8 >> u2; + if (u9.def != '0001'B) { + setverdict(fail, "u9: ", u9); + } + var bitstring bs3 := u8 <@ (u2 - 1); + if (bs3 != '0011'B) { + setverdict(fail, "bs3: ", bs3); + } + var UniDefBit u10 := u8 @> 1; + if (u10.def != '0110'B) { + setverdict(fail, "u10: ", u10); + } + var RecOf ro2 := u5 <@ 1; + if (ro2 != { 2, 3, 1 }) { + setverdict(fail, "ro2: ", ro2); + } + var RecOf ro3 := u5 @> 1; + if (ro3 != { 3, 1, 2 }) { + setverdict(fail, "ro3: ", ro3); + } + setverdict(pass); +} + +testcase tc_predef_func() runs on CT { + var UniDefBit u1 := '1010'B; + var hexstring hs1 := bit2hex(u1); + if (hs1 != 'A'H) { + setverdict(fail, "hs1: ", hs1); + } + var octetstring os1 := bit2oct(u1); + if (os1 != '0A'O) { + setverdict(fail, "os1: ", os1); + } + var charstring cs1 := bit2str(u1); + if (cs1 != "1010") { + setverdict(fail, "cs1: ", cs1); + } + var integer i1 := bit2int(u1); + if (i1 != 10) { + setverdict(fail, "i1: ", i1); + } + + var UniDefStr u2 := "4"; + var integer i2 := char2int(u2); + if (i2 != 52) { + setverdict(fail, "i2: ", i2); + } + var octetstring os2 := char2oct(u2); + if (os2 != '34'O) { + setverdict(fail, "os2: ", os2); + } + var integer i3 := str2int(u2); + if (i3 != 4) { + setverdict(fail, "i3: ", i3); + } + var float f1 := str2float(u2); + if (f1 != 4.0) { + setverdict(fail, "f1: ", f1); + } + var UniDefStr u3 := "10"; + var bitstring bs1 := str2bit(u3); + if (bs1 != '10'B) { + setverdict(fail, "bs1: ", bs1); + } + var hexstring hs2 := str2hex(u2); + if (hs2 != '4'H) { + setverdict(fail, "hs2: ", hs2); + } + var octetstring os3 := str2oct(u3); + if (os3 != '10'O) { + setverdict(fail, "os3: ", os3); + } + + var UniDefEnum u4 := { def := first }; + var integer i4 := enum2int(u4); + if (i4 != 0) { + setverdict(fail, "i4: ", i4); + } + + var UniDefFloat u5 := 3.0; + var integer i5 := float2int(u5); + if (i5 != 3) { + setverdict(fail, "i5: ", i5); + } + var charstring cs2 := float2str(u5); + if (cs2 != "3.000000") { + setverdict(fail, "cs2: ", cs2); + } + + var float f2 := rnd(u5); + + var UniDefHex u6 := '20'H; + var bitstring bs2 := hex2bit(u6); + if (bs2 != '00100000'B) { + setverdict(fail, "bs2: ", bs2); + } + var octetstring os4 := hex2oct(u6); + if (os4 != '20'O) { + setverdict(fail, "os4: ", os4); + } + var charstring cs3 := hex2str(u6); + if (cs3 != "20") { + setverdict(fail, "cs3: ", cs3); + } + var integer i6 := hex2int(u6); + if (i6 != 32) { + setverdict(fail, "i6: ", i6); + } + + var UniDefInt u7 := 65; + var charstring cs4 := int2char(u7); + if (cs4 != "A") { + setverdict(fail, "cs4: ", cs4); + } + var universal charstring us1 := int2unichar(u7); + if (us1 != "A") { + setverdict(fail, "us1: ", us1); + } + var float f3 := int2float(u7); + if (f3 != 65.0) { + setverdict(fail, "f3: ", f3); + } + var charstring cs5 := int2str(u7); + if (cs5 != "65") { + setverdict(fail, "cs5: ", cs4); + } + var bitstring bs3 := int2bit(u7, u7 / 8); + if (bs3 != '01000001'B) { + setverdict(fail, "bs3: ", bs3); + } + var hexstring hs3 := int2hex(u7, u7 / 30); + if (hs3 != '41'H) { + setverdict(fail, "hs3: ", hs3); + } + var octetstring os5 := int2oct(u7, u7 / 50); + if (os5 != '41'O) { + setverdict(fail, "os5: ", os5); + } + + var UniDefOct u8 := '20'O; + var bitstring bs4 := oct2bit(u8); + if (bs4 != '00100000'B) { + setverdict(fail, "bs4: ", bs4); + } + var hexstring hs4 := oct2hex(u8); + if (hs4 != '20'H) { + setverdict(fail, "hs4: ", hs4); + } + var charstring cs6 := oct2str(u8); + if (cs6 != "20") { + setverdict(fail, "cs6: ", cs6); + } + var integer i7 := oct2int(u8); + if (i7 != 32) { + setverdict(fail, "i7: ", i7); + } + var charstring cs7 := oct2char(u8); + if (cs7 != " ") { + setverdict(fail, "cs7: ", cs7); + } + + var UniDefUstr u9 := "a"; + var integer i8 := unichar2int(u9); + if (i8 != 97) { + setverdict(fail, "i8: ", i8); + } + var charstring cs8 := unichar2char(u9); + if (cs8 != "a") { + setverdict(fail, "cs8: ", cs8); + } + + var UniDefStr u10 := "AnyValue"; + var template integer t := ?; + if (not istemplatekind(t, u10)) { + setverdict(fail, "istemplatekind"); + } + + var template UniDefStr u_str := "something"; + var UniDefInt u_idx := 4; + var UniDefInt u_len := 3; + var UniDefStr u_substr := substr(u_str, u_idx, u_len); + if (u_substr.def != "thi") { + setverdict(fail, "substr: ", u_str); + } + + var template UniDefStr u_input := " date: 2001-10-20; msgno: 17; exp "; + var UniDefStr u_pattern := "[ \\t]#(,)date: [\\d\\-]#(,);[ \\t]#(,)msgno: (\\d#(1,3));[ \\t]#(,)(exp[ \\t]#(,))#(0,1)"; + var UniDefInt u_groupno := 0; + var UniDefStr u_regexp := regexp(u_input, u_pattern, u_groupno); + if (u_regexp.def != "17") { + setverdict(fail, "regexp: ", u_regexp); + } + + var UniDefInt u_lengthof := lengthof(u_str); + if (u_lengthof.def != 9) { + setverdict(fail, "lengthof: ", u_lengthof); + } + + var UniDefRec u_rec := { num := 6, str := omit }; + var UniDefInt u_sizeof := sizeof(u_rec); + if (u_sizeof.def != 1) { + setverdict(fail, "sizeof: ", u_sizeof); + } + var template UniDefRec u_rec_t := { num := 6, str := omit }; + var UniDefInt u_sizeof2 := sizeof(u_rec_t); + if (u_sizeof2.def != 1) { + setverdict(fail, "sizeof temp: ", u_sizeof2); + } + + var template UniDefInt u_temp := (0..5); + var UniDefInt u_val := 3; + var template integer i_temp := (0..5); + var integer i_val := 3; + if (not match(i_val, u_temp)) { + setverdict(fail, "match int with union"); + } + if (not match(u_val, i_temp)) { + setverdict(fail, "match union with int"); + } + if (not match(u_val, u_temp)) { + setverdict(fail, "match union with union"); + } + + var template UniDefStr u_str2 := "My name is JJ"; + var UniDefInt u_idx2 := 11; + var UniDefInt u_len2 := 1; + var template UniDefStr u_repl := "xx"; + var UniDefStr u_replace := replace(u_str2, u_idx2, u_len2, u_repl); + if (u_replace.def != "My name is xxJ") { + setverdict(fail, "replace: ", u_replace); + } + + var UniDefUni u_uni := { num := 6 }; + if (not ischosen(u_uni.num)) { + setverdict(fail, "ischosen"); + } + setverdict(pass); +} + +testcase tc_encdec() runs on CT { + var Rec val := { num := 3, str := "abc" }; + var UniDefStr str_enc := "UTF-8"; + var UniDefUstr enc_info := ""; + var UniDefUstr dyn_enc := "JSON"; + var UniDefUstr buf := encvalue_unichar(val, str_enc, enc_info, dyn_enc); + if (buf.def != "{\"num\":3,\"str\":\"abc\"}") { + setverdict(fail, "encoded value: ", buf); + } + var Rec dec_val; + var UniDefInt res := decvalue_unichar(buf, dec_val, str_enc, enc_info, dyn_enc); + if (res.def != 0) { + setverdict(fail, "decoding result: ", res); + } + if (dec_val != val) { + setverdict(fail, "decoded value: ", dec_val); + } + setverdict(pass); +} + +function f_behavior() runs on CT { +} + +testcase tc_comp_and_port() runs on CT { + var UniDefComp u1 := CT.create; + + if (u1.running) { + setverdict(fail, "u1 running"); + } + + if (not u1.alive) { + setverdict(fail, "u1 alive"); + } + + var UniDefStr u2 := "Started"; + if (not pt.checkstate(u2)) { + setverdict(fail, "checkstate"); + } + if (not any port.checkstate(u2)) { + setverdict(fail, "any checkstate"); + } + if (not all port.checkstate(u2)) { + setverdict(fail, "all checkstate"); + } + + u1.start(f_behavior()); + u1.stop; + u1.killed; + + setverdict(pass); +} + +altstep as() runs on CT { + [] tmr_comp.timeout { setverdict(fail, "altstep is still active"); } +} + +testcase tc_default_altstep() runs on CT { + timer tmr_local; + var UniDefDef u_def := activate(as()); + deactivate(u_def); + tmr_comp.start(0.1); + tmr_local.start(2.0); + alt { + [] tmr_local.timeout { setverdict(pass); } + } +} + +function f_func() return integer { + var UniDefInt x := 3; + return x; +} + +type record RecEnc { + integer f +} +with { + encode "XML"; + encode "JSON"; +} + +testcase tc_statements() runs on CT { + var UniDefInt ret_val := f_func(); + if (ret_val.def != 3) { + setverdict(fail, "return value: ", ret_val); + } + + var UniDefBool u_bool := false; + while (u_bool) { + setverdict(fail, "while"); + break; + } + + var UniDefStr u_text := "32"; + var integer i; + string2ttcn(u_text, i); + if (i != 32) { + setverdict(fail, "string2ttcn: ", i); + } + var UniDefStr u_text_res := ttcn2string(i); + if (u_text_res.def != "32") { + setverdict(fail, "ttcn2string: ", u_text_res); + } + + var UniDefInt u_int := 1; + var UniDefEnum u_enum; + int2enum(u_int, u_enum); + if (u_enum.def != second) { + setverdict(fail, "int2enum: ", u_enum); + } + + var UniDefUstr u_enc := "JSON"; + self.setencode(RecEnc, u_enc); + setverdict(pass); +} + +testcase tc_setverdict() runs on CT { + var UniDefVerdict u_verdict := pass; + setverdict(u_verdict); +} + +control { + execute(tc_init_and_assign()); + execute(tc_ref()); + execute(tc_expr()); + execute(tc_predef_func()); + execute(tc_comp_and_port()); + execute(tc_statements()); + execute(tc_setverdict()); +} + +}