Commit 50ad0063 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented object-oriented features - stage 5 (bug 552011)



Change-Id: I30e11c79aa3da5524b5a60cb4ef25a808aaf9516
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 1a4f2cf0
...@@ -728,6 +728,12 @@ public: ...@@ -728,6 +728,12 @@ public:
* scope-hierarchy) than a Module. * scope-hierarchy) than a Module.
*/ */
class Ref_simple : public Reference { class Ref_simple : public Reference {
public:
enum reftype_t {
REF_BASIC, // basic reference (not class related to any class scope)
REF_SUPER, // reference to the superclass
REF_THIS // reference to the current class object
};
protected: // Derived classes need access protected: // Derived classes need access
/** Points to the referred assignment. Used for caching. */ /** Points to the referred assignment. Used for caching. */
Assignment *refd_ass; Assignment *refd_ass;
...@@ -743,6 +749,8 @@ public: ...@@ -743,6 +749,8 @@ public:
/** Returns the \a id. */ /** Returns the \a id. */
virtual const Identifier* get_id() =0; virtual const Identifier* get_id() =0;
/** Creates a display-name for the reference. */ /** Creates a display-name for the reference. */
virtual reftype_t get_reftype() const { return REF_BASIC; }
virtual void set_reftype(reftype_t) { FATAL_ERROR("Ref_simple::set_reftype"); }
virtual string get_dispname(); virtual string get_dispname();
virtual Setting* get_refd_setting(); virtual Setting* get_refd_setting();
/** \param check_parlist is ignored */ /** \param check_parlist is ignored */
......
...@@ -1677,7 +1677,7 @@ namespace Common { ...@@ -1677,7 +1677,7 @@ namespace Common {
Type *Type::get_field_type(Ttcn::FieldOrArrayRefs *subrefs, Type *Type::get_field_type(Ttcn::FieldOrArrayRefs *subrefs,
expected_value_t expected_index, ReferenceChain *refch, expected_value_t expected_index, ReferenceChain *refch,
bool interrupt_if_optional) bool interrupt_if_optional, Assignment** last_method)
{ {
if (!subrefs) return this; if (!subrefs) return this;
Type *t = this; Type *t = this;
...@@ -1789,11 +1789,15 @@ namespace Common { ...@@ -1789,11 +1789,15 @@ namespace Common {
return 0; return 0;
case Assignment::A_FUNCTION: case Assignment::A_FUNCTION:
case Assignment::A_EXT_FUNCTION: case Assignment::A_EXT_FUNCTION:
// TODO: are these handled elsewhere? in some kind of statement? if (i != nof_refs - 1 || last_method == NULL) {
ref->error("Invalid reference to method `%s' with no return type in " ref->error("Invalid reference to method `%s' with no return type in "
"class type `%s'", "class type `%s'",
id.get_dispname().c_str(), t->get_typename().c_str()); id.get_dispname().c_str(), t->get_typename().c_str());
return 0; return 0;
}
// a method with no return value can still be valid (e.g. if it's
// in a statement)
// proceed as normal and return null at the end
case Assignment::A_FUNCTION_RVAL: case Assignment::A_FUNCTION_RVAL:
case Assignment::A_FUNCTION_RTEMP: case Assignment::A_FUNCTION_RTEMP:
case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL:
...@@ -1817,6 +1821,9 @@ namespace Common { ...@@ -1817,6 +1821,9 @@ namespace Common {
ap_list->set_my_scope(parsed_pars->get_my_scope()); ap_list->set_my_scope(parsed_pars->get_my_scope());
ref->set_actual_par_list(ap_list); ref->set_actual_par_list(ap_list);
} }
if (last_method != NULL) {
*last_method = ass;
}
break; } break; }
default: default:
FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class", FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class",
......
...@@ -634,10 +634,15 @@ namespace Common { ...@@ -634,10 +634,15 @@ namespace Common {
* Special case: if \a interrupt_if_optional is true then return NULL if an * Special case: if \a interrupt_if_optional is true then return NULL if an
* optional field has been reached. Using this bool parameter it can be * optional field has been reached. Using this bool parameter it can be
* checked if a referenced field is on an optional path (used by template * checked if a referenced field is on an optional path (used by template
* restriction checking code) */ * restriction checking code)
* @param last_method if not null, indicates that a method with no return
* value is valid at the end of the subreferences, and should not produce
* an error; the function assignment is also stored in the pointer pointed
* to by this parameter if the last subreference is a method (even if it has
* a return value) */
Type *get_field_type(Ttcn::FieldOrArrayRefs *subrefs, Type *get_field_type(Ttcn::FieldOrArrayRefs *subrefs,
expected_value_t expected_index, ReferenceChain *refch = 0, expected_value_t expected_index, ReferenceChain *refch = 0,
bool interrupt_if_optional = false); bool interrupt_if_optional = false, Assignment** last_method = NULL);
/** subrefs must point to an existing field, get_field_type() should be used /** subrefs must point to an existing field, get_field_type() should be used
* to check. subrefs_array will be filled with the indexes of the fields, * to check. subrefs_array will be filled with the indexes of the fields,
* type_array will be filled with types whose field indexes were collected, * type_array will be filled with types whose field indexes were collected,
...@@ -1003,6 +1008,7 @@ namespace Common { ...@@ -1003,6 +1008,7 @@ namespace Common {
expected_value_t expected_value, namedbool incomplete_allowed); expected_value_t expected_value, namedbool incomplete_allowed);
void chk_this_value_Component(Value *value); void chk_this_value_Component(Value *value);
void chk_this_value_FAT(Value *value); void chk_this_value_FAT(Value *value);
void chk_this_value_class(Value* value);
public: public:
/** Checks whether template \a t is a specific value and the embedded value /** Checks whether template \a t is a specific value and the embedded value
* is a referenced one. If the reference in the value points to a * is a referenced one. If the reference in the value points to a
...@@ -1300,7 +1306,7 @@ namespace Common { ...@@ -1300,7 +1306,7 @@ namespace Common {
void generate_code_ispresentboundchosen(expression_struct *expr, void generate_code_ispresentboundchosen(expression_struct *expr,
Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module, Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
const string& global_id, const string& external_id, const string& global_id, const string& external_id,
const bool is_template, const namedbool optype, const char* field); bool is_template, const namedbool optype, const char* field);
/** Extension attribute for optimized code generation of structured types: /** Extension attribute for optimized code generation of structured types:
* with { extension "optimize:xxx" } * with { extension "optimize:xxx" }
......
...@@ -4131,6 +4131,9 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ ...@@ -4131,6 +4131,9 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_
case T_TESTCASE: case T_TESTCASE:
chk_this_value_FAT(value); chk_this_value_FAT(value);
break; break;
case T_CLASS:
chk_this_value_class(value);
break;
default: default:
FATAL_ERROR("Type::chk_this_value()"); FATAL_ERROR("Type::chk_this_value()");
} // switch } // switch
...@@ -4194,6 +4197,15 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v ...@@ -4194,6 +4197,15 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v
error_flag = true; error_flag = true;
} }
break; break;
case Assignment::A_TYPE:
if (ass->get_Type()->get_type_refd_last()->typetype != T_CLASS) {
value->error("Reference to a %s was expected instead of %s",
expected_value == EXPECTED_TEMPLATE ? "value or template" : "value",
ass->get_description().c_str());
value->set_valuetype(Value::V_ERROR);
return self_ref;
}
// else fall through
case Assignment::A_VAR: case Assignment::A_VAR:
case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL:
case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_IN:
...@@ -5975,6 +5987,31 @@ void Type::chk_this_value_FAT(Value *value) ...@@ -5975,6 +5987,31 @@ void Type::chk_this_value_FAT(Value *value)
} }
} }
void Type::chk_this_value_class(Value* value)
{
Value* v = value->get_value_refd_last();
switch(v->get_valuetype()) {
case Value::V_TTCN3_NULL:
break; // OK
case Value::V_REFD:
// TODO
break;
case Value::V_EXPR:
switch (v->get_optype()) {
case Value::OPTYPE_CLASS_CREATE:
// TODO
break;
default:
// error
break;
}
break;
default:
// error
break;
}
}
void Type::chk_this_template_length_restriction(Template *t) void Type::chk_this_template_length_restriction(Template *t)
{ {
Ttcn::LengthRestriction *lr = t->get_length_restriction(); Ttcn::LengthRestriction *lr = t->get_length_restriction();
...@@ -6108,6 +6145,40 @@ void Type::chk_this_template_ref(Template *t) ...@@ -6108,6 +6145,40 @@ void Type::chk_this_template_ref(Template *t)
// endless recursion in case of embedded circular references. // endless recursion in case of embedded circular references.
// The parameter lists will be verified later. // The parameter lists will be verified later.
Assignment *ass = v->get_reference()->get_refd_assignment(false); Assignment *ass = v->get_reference()->get_refd_assignment(false);
if (ass != NULL && ass->get_asstype() == Assignment::A_VAR) {
// there could be class objects in the subreferences, which would change
// the type of the assignment (e.g. to a var template);
// use the assignment after the last class object in the subreference chain
Ttcn::FieldOrArrayRefs* subrefs = v->get_reference()->get_subrefs();
if (subrefs != NULL) {
Type* type = ass->get_Type();
if (type->get_field_type(subrefs, EXPECTED_DYNAMIC_VALUE) != NULL) {
// subrefs are valid
for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) {
type = type->get_type_refd_last();
Ttcn::FieldOrArrayRef* subref = subrefs->get_ref(i);
switch (subref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF:
case Ttcn::FieldOrArrayRef::FUNCTION_REF:
if (type->typetype == T_CLASS) {
ass = type->get_class_type_body()->
get_local_ass_byId(*subref->get_id());
type = ass->get_Type();
}
else {
type = type->get_comp_byName(*subref->get_id())->get_type();
}
break;
case Ttcn::FieldOrArrayRef::ARRAY_REF:
if (type->is_structured_type()) {
type = type->get_ofType();
}
break;
}
}
}
}
}
if (ass) { if (ass) {
switch (ass->get_asstype()) { switch (ass->get_asstype()) {
case Assignment::A_VAR_TEMPLATE: { case Assignment::A_VAR_TEMPLATE: {
......
...@@ -2893,7 +2893,6 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t, ...@@ -2893,7 +2893,6 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i); Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
switch (ref->get_type()) { switch (ref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF: { case Ttcn::FieldOrArrayRef::FIELD_REF: {
CompField* cf = t->get_comp_byName(*ref->get_id());
switch (t->typetype) { switch (t->typetype) {
case T_CHOICE_T: case T_CHOICE_T:
case T_CHOICE_A: case T_CHOICE_A:
...@@ -2903,13 +2902,17 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t, ...@@ -2903,13 +2902,17 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
case T_SEQ_T: case T_SEQ_T:
case T_SET_T: case T_SET_T:
case T_SEQ_A: case T_SEQ_A:
case T_SET_A: case T_SET_A: {
CompField* cf = t->get_comp_byName(*ref->get_id());
if (cf->get_is_optional()) return FALSE; if (cf->get_is_optional()) return FALSE;
t = cf->get_type();
break; }
case T_CLASS:
t = t->get_class_type_body()->get_local_ass_byId(*ref->get_id())->get_Type();
break; break;
default: default:
FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()"); FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
} }
t = cf->get_type();
} break; } break;
case Ttcn::FieldOrArrayRef::ARRAY_REF: case Ttcn::FieldOrArrayRef::ARRAY_REF:
switch (t->typetype) { switch (t->typetype) {
...@@ -2932,7 +2935,7 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t, ...@@ -2932,7 +2935,7 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
void Type::generate_code_ispresentboundchosen(expression_struct *expr, void Type::generate_code_ispresentboundchosen(expression_struct *expr,
Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module, Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
const string& global_id, const string& external_id, const bool is_template, const string& global_id, const string& external_id, bool is_template,
const namedbool optype, const char* field) const namedbool optype, const char* field)
{ {
if (!subrefs) return; if (!subrefs) return;
...@@ -2950,7 +2953,9 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, ...@@ -2950,7 +2953,9 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
// (e.g. because of circular reference) // (e.g. because of circular reference)
if (t->typetype == T_ERROR) return; if (t->typetype == T_ERROR) return;
if (is_template) { if (is_template && t->typetype != T_CLASS) {
// TODO: the initial value of 'is_template' is not always set properly
// (it seems to always be false in case of functions)
bool anyval_ret_val = TRUE; bool anyval_ret_val = TRUE;
if (optype == ISPRESENT) { if (optype == ISPRESENT) {
anyval_ret_val = ispresent_anyvalue_embedded_field(t, subrefs, i); anyval_ret_val = ispresent_anyvalue_embedded_field(t, subrefs, i);
...@@ -2987,9 +2992,23 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, ...@@ -2987,9 +2992,23 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
switch (ref->get_type()) { switch (ref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF: { case Ttcn::FieldOrArrayRef::FIELD_REF: {
const Identifier& id = *ref->get_id(); const Identifier& id = *ref->get_id();
CompField* cf = t->get_comp_byName(id); if (t->typetype == T_CLASS) {
next_t = cf->get_type(); Assignment* ass = t->get_class_type_body()->get_local_ass_byId(id);
next_o = !is_template && cf->get_is_optional(); if (ass->get_asstype() == Assignment::A_TEMPLATE ||
ass->get_asstype() == Assignment::A_VAR_TEMPLATE) {
is_template = true;
}
else {
is_template = false;
}
next_t = ass->get_Type();
next_o = false;
}
else {
CompField* cf = t->get_comp_byName(id);
next_t = cf->get_type();
next_o = !is_template && cf->get_is_optional();
}
switch (t->typetype) { switch (t->typetype) {
case T_CHOICE_A: case T_CHOICE_A:
...@@ -3008,6 +3027,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, ...@@ -3008,6 +3027,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
case T_SET_A: case T_SET_A:
case T_SET_T: case T_SET_T:
case T_ANYTYPE: case T_ANYTYPE:
case T_CLASS:
break; break;
default: default:
FATAL_ERROR("Type::generate_code_ispresentboundchosen()"); FATAL_ERROR("Type::generate_code_ispresentboundchosen()");
...@@ -3125,21 +3145,29 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, ...@@ -3125,21 +3145,29 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
const char *tmp_id_str = tmp_id.c_str(); const char *tmp_id_str = tmp_id.c_str();
const char *tmp_id2_str = tmp_id2.c_str(); const char *tmp_id2_str = tmp_id2.c_str();
// Own const ref to the temp value if (t->typetype == T_CLASS) {
expr->expr = mputprintf(expr->expr, expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s;\n",
"const %s%s& %s = %s;\n", next_t->get_genname_value(module).c_str(),
t->get_genname_value(module).c_str(), is_template ? "_template" : "", tmp_id2_str,
is_template ? "_template" : "", tmp_generalid_str, id.get_name().c_str());
tmp_id_str, tmp_generalid_str); }
// Get the const ref of the field from the previous const ref else {
// If we would get the const ref of the field immediately then the // Own const ref to the temp value
// value in the const ref would be free-d instantly. expr->expr = mputprintf(expr->expr,
expr->expr = mputprintf(expr->expr, "const %s%s& %s = %s;\n",
"const %s%s& %s = %s.%s%s();\n", t->get_genname_value(module).c_str(),
next_t->get_genname_value(module).c_str(), is_template ? "_template" : "",
is_template ? "_template" : "", tmp_id_str, tmp_generalid_str);
tmp_id2_str, tmp_id_str, // Get the const ref of the field from the previous const ref
t->typetype == T_ANYTYPE ? "AT_" : "", id.get_name().c_str()); // If we would get the const ref of the field immediately then the
// value in the const ref would be free-d instantly.
expr->expr = mputprintf(expr->expr,
"const %s%s& %s = %s.%s%s();\n",
next_t->get_genname_value(module).c_str(),
is_template ? "_template" : "",
tmp_id2_str, tmp_id_str,
t->typetype == T_ANYTYPE ? "AT_" : "", id.get_name().c_str());
}
if (i != nof_refs - 1 || optype == ISCHOSEN) { if (i != nof_refs - 1 || optype == ISCHOSEN) {
expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n", expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
...@@ -3174,6 +3202,68 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, ...@@ -3174,6 +3202,68 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
tmp_generalid_str = mcopystr(tmp_id2_str); tmp_generalid_str = mcopystr(tmp_id2_str);
} }
t = next_t;
break; }
case Ttcn::FieldOrArrayRef::FUNCTION_REF: {
const Identifier& id = *ref->get_id();
Assignment* ass = t->get_class_type_body()->get_local_ass_byId(id);
if (ass->get_asstype() == Assignment::A_FUNCTION_RTEMP ||
ass->get_asstype() == Assignment::A_EXT_FUNCTION_RTEMP) {
is_template = true;
}
else {
is_template = false;
}
Ttcn::Def_Function_Base* def_func = dynamic_cast<Ttcn::Def_Function_Base*>(ass);
next_t = def_func->get_return_type();
expr->expr = mputprintf(expr->expr, "if(%s) {\n", global_id.c_str());
expstring_t closing_brackets2 = mprintf("}\n%s", closing_brackets);
Free(closing_brackets);
closing_brackets = closing_brackets2;
const string& tmp_id = module->get_temporary_id();
const char *tmp_id_str = tmp_id.c_str();
expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s(",
next_t->get_genname_value(module).c_str(),
is_template ? "_template" : "", tmp_id_str,
tmp_generalid_str, id.get_name().c_str());
ref->get_actual_par_list()->generate_code_noalias(expr, ass->get_FormalParList());
expr->expr = mputstr(expr->expr, ");\n");
if (i != nof_refs - 1 || optype == ISCHOSEN) {
expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
global_id.c_str(), tmp_id_str);
}
if (i == nof_refs - 1) {
switch (optype) {
case ISBOUND:
expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
global_id.c_str(), tmp_id_str);
break;
case ISPRESENT:
expr->expr = mputprintf(expr->expr, "%s = %s.is_present(%s);\n",
global_id.c_str(), tmp_id_str,
(is_template && omit_in_value_list) ? "TRUE" : "");
break;
case ISCHOSEN:
expr->expr = mputprintf(expr->expr,
"if (%s) {\n"
"%s = %s.ischosen(%s);\n"
"}\n", global_id.c_str(), global_id.c_str(), tmp_id_str, field);
break;
case ISVALUE:
expr->expr = mputprintf(expr->expr, "%s = %s.is_value();\n",
global_id.c_str(), tmp_id_str);
break;
default:
FATAL_ERROR("Type::generate_code_ispresentboundchosen");
}
}
Free(tmp_generalid_str);
tmp_generalid_str = mcopystr(tmp_id_str);
t = next_t; t = next_t;
break; } break; }
case Ttcn::FieldOrArrayRef::ARRAY_REF: { case Ttcn::FieldOrArrayRef::ARRAY_REF: {
......
...@@ -4060,6 +4060,12 @@ namespace Common { ...@@ -4060,6 +4060,12 @@ namespace Common {
exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
ass->get_description().c_str()); ass->get_description().c_str());
goto error; goto error;
case Assignment::A_TYPE:
if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
tmp_type = ass->get_Type();
break;
}
// else fall through
default: default:
error("Reference to a %s was expected instead of %s", error("Reference to a %s was expected instead of %s",
exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
...@@ -9536,22 +9542,27 @@ void Value::chk_expr_operand_execute_refd(Value *v1, ...@@ -9536,22 +9542,27 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
destroy_refch = true; destroy_refch = true;
} }
if (refch->add(get_fullname())) { if (refch->add(get_fullname())) {
Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs(); if (ass->get_my_scope()->get_parent_scope()->is_class_scope()) {
Value *v_refd = ass->get_Value()
->get_refd_sub_value(subrefs, 0,
u.ref.ref->getUsedInIsbound(), refch);
if (v_refd) {
Value *v_last = v_refd->get_value_refd_last(refch);
// in case of circular recursion the valuetype is already set
// to V_ERROR, so don't set the cache
if (valuetype == V_REFD) u.ref.refd_last = v_last;
} else if (subrefs && subrefs->has_unfoldable_index()) {
u.ref.refd_last = this; u.ref.refd_last = this;
} else if (u.ref.ref->getUsedInIsbound()) { }
u.ref.refd_last = this; else {
} else { Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs();
// the sub-reference points to a non-existent field Value *v_refd = ass->get_Value()
set_valuetype(V_ERROR); ->get_refd_sub_value(subrefs, 0,
u.ref.ref->getUsedInIsbound(), refch);
if (v_refd) {
Value *v_last = v_refd->get_value_refd_last(refch);
// in case of circular recursion the valuetype is already set
// to V_ERROR, so don't set the cache
if (valuetype == V_REFD) u.ref.refd_last = v_last;
} else if (subrefs && subrefs->has_unfoldable_index()) {
u.ref.refd_last = this;
} else if (u.ref.ref->getUsedInIsbound()) {
u.ref.refd_last = this;
} else {
// the sub-reference points to a non-existent field
set_valuetype(V_ERROR);
}
} }
} else { } else {
// a circular recursion was detected // a circular recursion was detected
...@@ -9585,6 +9596,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1, ...@@ -9585,6 +9596,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
ass->get_description().c_str()); ass->get_description().c_str());
set_valuetype(V_ERROR); set_valuetype(V_ERROR);
break; break;
case Assignment::A_TYPE:
if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
u.ref.refd_last = this;
break;
}
// else fall through
default: default:
u.ref.ref->error("Reference to a value was expected instead of %s", u.ref.ref->error("Reference to a value was expected instead of %s",
ass->get_description().c_str()); ass->get_description().c_str());
...@@ -9641,12 +9658,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1, ...@@ -9641,12 +9658,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case V_OPENTYPE: case V_OPENTYPE:
case V_UNDEF_LOWERID: case V_UNDEF_LOWERID:
case V_UNDEF_BLOCK: case V_UNDEF_BLOCK:
case V_TTCN3_NULL:
case V_REFER: case V_REFER:
// these value types are eliminated during semantic analysis // these value types are eliminated during semantic analysis
FATAL_ERROR("Value::is_unfoldable()"); FATAL_ERROR("Value::is_unfoldable()");
case V_ERROR: case V_ERROR:
case V_INVOKE: case V_INVOKE:
case V_TTCN3_NULL:
return true; return true;
case V_CHOICE: case V_CHOICE:
return u.choice.alt_value->is_unfoldable(refch, exp_val); return u.choice.alt_value->is_unfoldable(refch, exp_val);
...@@ -12911,7 +12928,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, ...@@ -12911,7 +12928,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
void Value::generate_code_expr_mandatory(expression_struct *expr) void Value::generate_code_expr_mandatory(expression_struct *expr)
{ {
generate_code_expr(expr); generate_code_expr(expr);
if (valuetype == V_REFD && get_value_refd_last()->valuetype == V_REFD) if (valuetype == V_REFD && get_value_refd_last()->valuetype == V_REFD &&
u.ref.ref->get_refd_assignment()->get_Type()->get_type_refd_last()->get_typetype() != Type::T_CLASS)
generate_code_expr_optional_field_ref(expr, u.ref.ref); generate_code_expr_optional_field_ref(expr, u.ref.ref);
} }
   
...@@ -13641,6 +13659,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, ...@@ -13641,6 +13659,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case OPTYPE_ISBOUND: { case OPTYPE_ISBOUND: {
Template::templatetype_t temp = u.expr.ti1->get_Template() Template::templatetype_t temp = u.expr.ti1->get_Template()
->get_templatetype(); ->get_templatetype();
// TODO: use get_refd_assignment instead to determine whether it's a template?
if (temp == Template::SPECIFIC_VALUE) { if (temp == Template::SPECIFIC_VALUE) {
Value* specific_value = u.expr.ti1->get_Template()