Commit 3057fb81 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented '@default' modifier for union types (bug 564919)


Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
Change-Id: I54eb249100e7202b47290836ac84210b80cbcd17
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 195d8365
......@@ -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;
}
......
......@@ -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.
......
......@@ -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)
{
......
......@@ -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
*
......
......@@ -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;
......
This diff is collapsed.
......@@ -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);
......
......@@ -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)
{
......
......@@ -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();
......
......@@ -276,7 +276,8 @@ namespace Ttcn {
// =================================
PatternString::PatternString(const PatternString& p)
: Node(p), my_scope(0), cstr_value(0), pattern_type