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:
* scope-hierarchy) than a Module.
*/
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
/** Points to the referred assignment. Used for caching. */
Assignment *refd_ass;
......@@ -743,6 +749,8 @@ public:
/** Returns the \a id. */
virtual const Identifier* get_id() =0;
/** 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 Setting* get_refd_setting();
/** \param check_parlist is ignored */
......
......@@ -1677,7 +1677,7 @@ namespace Common {
Type *Type::get_field_type(Ttcn::FieldOrArrayRefs *subrefs,
expected_value_t expected_index, ReferenceChain *refch,
bool interrupt_if_optional)
bool interrupt_if_optional, Assignment** last_method)
{
if (!subrefs) return this;
Type *t = this;
......@@ -1789,11 +1789,15 @@ namespace Common {
return 0;
case Assignment::A_FUNCTION:
case Assignment::A_EXT_FUNCTION:
// TODO: are these handled elsewhere? in some kind of statement?
ref->error("Invalid reference to method `%s' with no return type in "
"class type `%s'",
id.get_dispname().c_str(), t->get_typename().c_str());
return 0;
if (i != nof_refs - 1 || last_method == NULL) {
ref->error("Invalid reference to method `%s' with no return type in "
"class type `%s'",
id.get_dispname().c_str(), t->get_typename().c_str());
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_RTEMP:
case Assignment::A_EXT_FUNCTION_RVAL:
......@@ -1817,6 +1821,9 @@ namespace Common {
ap_list->set_my_scope(parsed_pars->get_my_scope());
ref->set_actual_par_list(ap_list);
}
if (last_method != NULL) {
*last_method = ass;
}
break; }
default:
FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class",
......
......@@ -634,10 +634,15 @@ namespace Common {
* 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
* 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,
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
* 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,
......@@ -1003,6 +1008,7 @@ namespace Common {
expected_value_t expected_value, namedbool incomplete_allowed);
void chk_this_value_Component(Value *value);
void chk_this_value_FAT(Value *value);
void chk_this_value_class(Value* value);
public:
/** 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
......@@ -1300,7 +1306,7 @@ namespace Common {
void generate_code_ispresentboundchosen(expression_struct *expr,
Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
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:
* with { extension "optimize:xxx" }
......
......@@ -4131,6 +4131,9 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_
case T_TESTCASE:
chk_this_value_FAT(value);
break;
case T_CLASS:
chk_this_value_class(value);
break;
default:
FATAL_ERROR("Type::chk_this_value()");
} // switch
......@@ -4194,6 +4197,15 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v
error_flag = true;
}
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_PAR_VAL:
case Assignment::A_PAR_VAL_IN:
......@@ -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)
{
Ttcn::LengthRestriction *lr = t->get_length_restriction();
......@@ -6108,6 +6145,40 @@ void Type::chk_this_template_ref(Template *t)
// endless recursion in case of embedded circular references.
// The parameter lists will be verified later.
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) {
switch (ass->get_asstype()) {
case Assignment::A_VAR_TEMPLATE: {
......
......@@ -2893,7 +2893,6 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
switch (ref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF: {
CompField* cf = t->get_comp_byName(*ref->get_id());
switch (t->typetype) {
case T_CHOICE_T:
case T_CHOICE_A:
......@@ -2903,13 +2902,17 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
case T_SEQ_T:
case T_SET_T:
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;
t = cf->get_type();
break; }
case T_CLASS:
t = t->get_class_type_body()->get_local_ass_byId(*ref->get_id())->get_Type();
break;
default:
FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
}
t = cf->get_type();
} break;
case Ttcn::FieldOrArrayRef::ARRAY_REF:
switch (t->typetype) {
......@@ -2932,7 +2935,7 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
void Type::generate_code_ispresentboundchosen(expression_struct *expr,
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)
{
if (!subrefs) return;
......@@ -2950,7 +2953,9 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
// (e.g. because of circular reference)
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;
if (optype == ISPRESENT) {
anyval_ret_val = ispresent_anyvalue_embedded_field(t, subrefs, i);
......@@ -2987,9 +2992,23 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
switch (ref->get_type()) {
case Ttcn::FieldOrArrayRef::FIELD_REF: {
const Identifier& id = *ref->get_id();
CompField* cf = t->get_comp_byName(id);
next_t = cf->get_type();
next_o = !is_template && cf->get_is_optional();
if (t->typetype == T_CLASS) {
Assignment* ass = t->get_class_type_body()->get_local_ass_byId(id);
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) {
case T_CHOICE_A:
......@@ -3008,6 +3027,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
case T_SET_A:
case T_SET_T:
case T_ANYTYPE:
case T_CLASS:
break;
default:
FATAL_ERROR("Type::generate_code_ispresentboundchosen()");
......@@ -3125,21 +3145,29 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
const char *tmp_id_str = tmp_id.c_str();
const char *tmp_id2_str = tmp_id2.c_str();
// Own const ref to the temp value
expr->expr = mputprintf(expr->expr,
"const %s%s& %s = %s;\n",
t->get_genname_value(module).c_str(),
is_template ? "_template" : "",
tmp_id_str, tmp_generalid_str);
// Get the const ref of the field from the previous const ref
// 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 (t->typetype == T_CLASS) {
expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s;\n",
next_t->get_genname_value(module).c_str(),
is_template ? "_template" : "", tmp_id2_str,
tmp_generalid_str, id.get_name().c_str());
}
else {
// Own const ref to the temp value
expr->expr = mputprintf(expr->expr,
"const %s%s& %s = %s;\n",
t->get_genname_value(module).c_str(),
is_template ? "_template" : "",
tmp_id_str, tmp_generalid_str);
// Get the const ref of the field from the previous const ref
// 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) {
expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
......@@ -3174,6 +3202,68 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
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;
break; }
case Ttcn::FieldOrArrayRef::ARRAY_REF: {
......
......@@ -4060,6 +4060,12 @@ namespace Common {
exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
ass->get_description().c_str());
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:
error("Reference to a %s was expected instead of %s",
exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
......@@ -9536,22 +9542,27 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
destroy_refch = true;
}
if (refch->add(get_fullname())) {
Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs();
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()) {
if (ass->get_my_scope()->get_parent_scope()->is_class_scope()) {
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 {
Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs();
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;
} 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 {
// a circular recursion was detected
......@@ -9585,6 +9596,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
ass->get_description().c_str());
set_valuetype(V_ERROR);
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:
u.ref.ref->error("Reference to a value was expected instead of %s",
ass->get_description().c_str());
......@@ -9641,12 +9658,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case V_OPENTYPE:
case V_UNDEF_LOWERID:
case V_UNDEF_BLOCK:
case V_TTCN3_NULL:
case V_REFER:
// these value types are eliminated during semantic analysis
FATAL_ERROR("Value::is_unfoldable()");
case V_ERROR:
case V_INVOKE:
case V_TTCN3_NULL:
return true;
case V_CHOICE:
return u.choice.alt_value->is_unfoldable(refch, exp_val);
......@@ -12911,7 +12928,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
void Value::generate_code_expr_mandatory(expression_struct *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);
}
 
......@@ -13641,6 +13659,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case OPTYPE_ISBOUND: {
Template::templatetype_t temp = u.expr.ti1->get_Template()
->get_templatetype();
// TODO: use get_refd_assignment instead to determine whether it's a template?
if (temp == Template::SPECIFIC_VALUE) {
Value* specific_value = u.expr.ti1->get_Template()
->get_specific_value();
......@@ -15542,6 +15561,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case V_ALTSTEP:
case V_TESTCASE:
return get_single_expr_fat();
case V_TTCN3_NULL:
return string("NULL_VALUE");
default:
FATAL_ERROR("Value::get_single_expr()");
return string();
......
......@@ -116,7 +116,7 @@ namespace Common {
V_UNDEF_BLOCK, /**< undefined {block} */
V_OMIT, /**< special value for optional values */
V_VERDICT, /**< verdict */
V_TTCN3_NULL, /**< TTCN-3 null (for component or default references) */
V_TTCN3_NULL, /**< TTCN-3 null (for component, default or class references) */
V_DEFAULT_NULL, /**< null default reference */
V_FAT_NULL, /**< null for function, altstep and testcase */
V_EXPR, /**< expressions */
......
......@@ -430,11 +430,7 @@ namespace Ttcn {
bool const_ref, /* = false */
bool is_template, /* = false */
size_t nof_subrefs /* = UINT_MAX */)
{
// ensure everything is checked
// TODO: incorporate this into the semantic analysis somehow...
if (type) type->get_field_type(this, Common::Type::EXPECTED_DYNAMIC_VALUE);
{
size_t n_refs = (nof_subrefs != UINT_MAX) ? nof_subrefs : refs.size();
for (size_t i = 0; i < n_refs; i++) {
if (type) type = type->get_type_refd_last();
......@@ -691,21 +687,31 @@ namespace Ttcn {
// =================================
Reference::Reference(const Reference& p)
: Ref_base(p), parlist(NULL), gen_const_prefix(false), expr_cache(NULL)
: Ref_base(p), reftype(p.reftype), parlist(NULL), gen_const_prefix(false),
expr_cache(NULL)
{
params = p.params != NULL ? p.params->clone() : NULL;
}
Reference::Reference(Identifier *p_id)
: Ref_base(), parlist(NULL), params(NULL), gen_const_prefix(false),
expr_cache(NULL)
: Ref_base(), reftype(REF_BASIC), parlist(NULL), params(NULL),
gen_const_prefix(false), expr_cache(NULL)
{
subrefs.add(new FieldOrArrayRef(p_id));
}
Reference::Reference(reftype_t p_reftype)
: Ref_base(), reftype(p_reftype), parlist(NULL), params(NULL),
gen_const_prefix(false), expr_cache(NULL)
{
if (reftype != REF_THIS) {
FATAL_ERROR("Ttcn::Reference(): basic or 'super' reference with no ID");
}
}
Reference::Reference(Identifier *p_modid, Identifier *p_id,
ParsedActualParameters *p_params)
: Ref_base(p_modid, p_id), parlist(NULL), params(p_params),
ParsedActualParameters *p_params, reftype_t p_reftype)
: Ref_base(p_modid, p_id), reftype(p_reftype), parlist(NULL), params(p_params),
gen_const_prefix(false), expr_cache(NULL)
{
if (p_params == NULL) {
......@@ -1043,6 +1049,21 @@ namespace Ttcn {
ref_usage_found();
Common::Assignment *ass = get_refd_assignment();
if (!ass) FATAL_ERROR("Reference::generate_code()");
if (reftype == REF_THIS) {
if (id != NULL) {
expr->expr = mputstr(expr->expr, "this->");
}
else { // no 'id' means it's just a 'this' reference
expr->expr = mputprintf(expr->expr, "OBJECT_REF<%s>(this)",
ass->get_Type()->get_genname_value(my_scope).c_str());
return;
}
}
else if (reftype == REF_SUPER) {
expr->expr = mputprintf(expr->expr, "%s::",
my_scope->get_scope_class()->get_base_type()->
get_genname_value(my_scope).c_str());
}
string const_prefix; // empty by default
if (gen_const_prefix) {
if (ass->get_asstype() == Common::Assignment::A_CONST) {
......@@ -1053,8 +1074,6 @@ namespace Ttcn {
}
}
if (parlist != NULL) {
// reference without parameters to a template that has only default formal parameters.
// if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
expr->expr = mputprintf(expr->expr, "%s(",
ass->get_genname_from_scope(my_scope).c_str());
parlist->generate_code_alias(expr, ass->get_FormalParList(),
......@@ -1208,9 +1227,16 @@ namespace Ttcn {
expression_struct isbound_expr;
Code::init_expr(&isbound_expr);
isbound_expr.preamble = mputprintf(isbound_expr.preamble,
if (ass->get_Type()->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) {
isbound_expr.preamble = mputprintf(isbound_expr.preamble,
"boolean %s = %s != NULL_VALUE;\n", tmp_generalid_str,
ass_id_str);
}
else {
isbound_expr.preamble = mputprintf(isbound_expr.preamble,
"boolean %s = %s.is_bound();\n", tmp_generalid_str,
ass_id_str);
}
namedbool p_optype;
if (optype == Value::OPTYPE_ISBOUND) {
p_optype = ISBOUND;
......@@ -1268,7 +1294,7 @@ namespace Ttcn {
void Reference::detect_modid()
{
// do nothing if detection is already performed
if (id) return;
if (id || reftype == REF_THIS) return;
// the first element of subrefs must be an <id>
const Identifier *first_id = subrefs.get_ref(0)->get_id(), *second_id = 0;
const ParsedActualParameters* second_params = 0;
......@@ -2177,14 +2203,16 @@ namespace Ttcn {