Commit c5e6cf1a authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Removed template concatenation from Runtime1 and fixed some issues caused by template concatenation



Change-Id: I8eda699882618331a4c422741aa54b2db59b5d9a
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent f723f731
......@@ -5640,6 +5640,9 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed,
break;
case Ttcn::Template::TEMPLATE_CONCAT:
{
if (!use_runtime_2) {
FATAL_ERROR("Type::chk_this_template_generic()");
}
Error_Context cntxt(t, "In template concatenation");
Template* t_left = t->get_concat_operand(true);
Template* t_right = t->get_concat_operand(false);
......
......@@ -408,17 +408,6 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
"}\n"
"return ret_val;\n"
"}\n\n", name, name, name, dispname, name, type, type);
def = mputprintf(def,
"%s operator+(const OPTIONAL<%s>& other_value) const;\n\n", name, name);
src = mputprintf(src,
"%s %s::operator+(const OPTIONAL<%s>& other_value) const\n"
"{\n"
"if (other_value.is_present()) {\n"
"return *this + (const %s&)other_value;\n"
"}\n"
"TTCN_error(\"Unbound or omitted right operand of %s concatenation.\");\n"
"}\n\n", name, name, name, name, dispname);
/* substr() */
def = mputprintf(def,
......@@ -1973,17 +1962,6 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
"}\n"
"return ret_val;\n"
"}\n\n", name, name, name, dispname, name);
def = mputprintf(def,
"%s operator+(const OPTIONAL<%s>& other_value) const;\n\n", name, name);
src = mputprintf(src,
"%s %s::operator+(const OPTIONAL<%s>& other_value) const\n"
"{\n"
"if (other_value.is_present()) {\n"
"return *this + (const %s&)other_value;\n"
"}\n"
"TTCN_error(\"Unbound or omitted right operand of %s concatenation.\");\n"
"}\n\n", name, name, name, name, dispname);
/* substr() */
def = mputprintf(def,
......@@ -3405,22 +3383,6 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
"} value_set;\n", type);
}
def = mputstr(def, "};\n");
/* friend functions */
def = mputprintf(def, "friend %s_template operator+(template_sel left_template, "
"const %s_template& right_template);\n", name, name);
def = mputprintf(def, "friend %s_template operator+(const %s& left_value, "
"const %s_template& right_template);\n", name, name, name);
def = mputprintf(def, "friend %s_template operator+(const OPTIONAL<%s>& left_value, "
"const %s_template& right_template);\n", name, name, name);
def = mputprintf(def, "friend %s_template operator+(template_sel left_template, "
"const %s& right_value);\n", name, name);
def = mputprintf(def, "friend %s_template operator+(template_sel left_template, "
"const OPTIONAL<%s>& right_value);\n", name, name);
def = mputprintf(def, "friend %s_template operator+(const %s& left_value, "
"template_sel right_template);\n", name, name);
def = mputprintf(def, "friend %s_template operator+(const OPTIONAL<%s>& left_value, "
"template_sel right_template);\n", name, name);
/* private member functions */
......@@ -3557,143 +3519,6 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
"}\n\n", name, name, name, name, name);
}
/* helper functions for template concatenation */
def = mputstr(def, "int get_length_for_concat(boolean& is_any_value) const;\n");
src = mputprintf(src,
"int %s_template::get_length_for_concat(boolean& is_any_value) const\n"
"{\n"
"switch (template_selection) {\n"
"case SPECIFIC_VALUE:\n"
"return single_value.n_elements;\n"
"case ANY_VALUE:\n"
"case ANY_OR_OMIT:\n"
"switch (length_restriction_type) {\n"
"case NO_LENGTH_RESTRICTION:\n"
"if (template_selection == ANY_VALUE) {\n"
// ? => { * }
"is_any_value = TRUE;\n"
"return 1;\n"
"}\n"
"TTCN_error(\"Operand of %s of template concatenation is an "
"AnyValueOrNone (*) matching mechanism with no length restriction\");\n"
"case RANGE_LENGTH_RESTRICTION:\n"
"if (!length_restriction.range_length.max_length || "
"length_restriction.range_length.max_length != "
"length_restriction.range_length.min_length) {\n"
"TTCN_error(\"Operand of %s of template concatenation is an %%s matching "
"mechanism with non-fixed length restriction\", "
"template_selection == ANY_VALUE ? \"AnyValue (?)\" : \"AnyValueOrNone (*)\");\n"
"}\n"
// else fall through (range length restriction is allowed if the minimum
// and maximum value are the same)
"case SINGLE_LENGTH_RESTRICTION:\n"
// ? length(N) or * length(N) => { ?, ?, ... ? } N times
"return length_restriction_type == SINGLE_LENGTH_RESTRICTION ? "
"length_restriction.single_length : length_restriction.range_length.min_length;\n"
"}\n"
"default:\n"
"TTCN_error(\"Operand of %s of template concatenation is an "
"uninitialized or unsupported template.\");\n"
"}\n"
"}\n\n", name, sdef->kind == RECORD_OF ? "record" : "set",
sdef->kind == RECORD_OF ? "record" : "set",
sdef->kind == RECORD_OF ? "record" : "set");
def = mputprintf(def, "static int get_length_for_concat(const %s& operand);\n",
name);
src = mputprintf(src,
"int %s_template::get_length_for_concat(const %s& operand)\n"
"{\n"
"if (!operand.is_bound()) {\n"
"TTCN_error(\"Operand of %s of template concatenation is an unbound value.\");\n"
"}\n"
"return operand.size_of();\n"
"}\n\n", name, name, sdef->kind == RECORD_OF ? "record" : "set");
def = mputstr(def, "static int get_length_for_concat(template_sel operand);\n");
src = mputprintf(src,
"int %s_template::get_length_for_concat(template_sel operand)\n"
"{\n"
"if (operand == ANY_VALUE) {\n"
// ? => { * }
"return 1;\n"
"}\n"
"TTCN_error(\"Operand of %s of template concatenation is an "
"uninitialized or unsupported template.\");\n"
"}\n\n", name, sdef->kind == RECORD_OF ? "record" : "set");
def = mputprintf(def, "void concat(int& pos, const %s_template& operand);\n",
name);
src = mputprintf(src,
"void %s_template::concat(int& pos, const %s_template& operand)\n"
"{\n"
// all errors should have already been caught by the operand's
// get_length_for_concat() call;
// the result template (this) should already be set to SPECIFIC_VALUE and
// single_value.value_elements should already be allocated
"switch (operand.template_selection) {\n"
"case SPECIFIC_VALUE:\n"
"for (int i = 0; i < operand.single_value.n_elements; ++i) {\n"
"single_value.value_elements[pos + i] = "
"new %s_template(*operand.single_value.value_elements[i]);\n"
"}\n"
"pos += operand.single_value.n_elements;\n"
"break;\n"
"case ANY_VALUE:\n"
"case ANY_OR_OMIT:\n"
"switch (operand.length_restriction_type) {\n"
"case NO_LENGTH_RESTRICTION:\n"
// ? => { * }
"single_value.value_elements[pos] = new %s_template(ANY_OR_OMIT);\n"
"++pos;\n"
"break;\n"
"case RANGE_LENGTH_RESTRICTION:\n"
"case SINGLE_LENGTH_RESTRICTION: {\n"
// ? length(N) or * length(N) => { ?, ?, ... ? } N times
"int N = operand.length_restriction_type == SINGLE_LENGTH_RESTRICTION ? "
"operand.length_restriction.single_length : "
"operand.length_restriction.range_length.min_length;\n"
"for (int i = 0; i < N; ++i) {\n"
"single_value.value_elements[pos + i] = new %s_template(ANY_VALUE);\n"
"}\n"
"pos += N;\n"
"break; }\n"
"}\n"
"default:\n"
"break;\n"
"}\n"
"}\n\n", name, name, type, type, type);
def = mputprintf(def, "void concat(int& pos, const %s& operand);\n", name);
src = mputprintf(src,
"void %s_template::concat(int& pos, const %s& operand)\n"
"{\n"
// all errors should have already been caught by the
// get_length_for_concat() call;
// the result template (this) should already be set to SPECIFIC_VALUE and
// single_value.value_elements should already be allocated
"int len = operand.size_of();\n"
"for (int i = 0; i < len; ++i) {\n"
"single_value.value_elements[pos + i] = new %s_template(operand[i]);\n"
"}\n"
"pos += len;\n"
"}\n\n", name, name, type);
def = mputstr(def, "void concat(int& pos);\n");
src = mputprintf(src,
"void %s_template::concat(int& pos)\n"
"{\n"
// this concatenates a template_sel to the result template;
// there is no need for a template_sel parameter, since the only template
// selection that can be concatenated is ANY_VALUE;
// the template selection has already been checked in the
// get_length_for_concat() call;
// the result template (this) should already be set to SPECIFIC_VALUE and
// single_value.value_elements should already be allocated
"single_value.value_elements[pos] = new %s_template(ANY_OR_OMIT);\n"
"++pos;\n"
"}\n\n", name, type);
/* public member functions */
def = mputstr(def, "\npublic:\n");
......@@ -3854,83 +3679,6 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
"}\n"
"return *this;\n"
"}\n\n", name, name, name);
/* concatenation operators */
def = mputprintf(def, "%s_template operator+(const %s_template& "
"other_value) const;\n", name, name);
src = mputprintf(src,
"%s_template %s_template::operator+(const %s_template& other_value) const\n"
"{\n"
"boolean left_is_any_value = FALSE;\n"
"boolean right_is_any_value = FALSE;\n"
"int res_length = get_length_for_concat(left_is_any_value) + "
"other_value.get_length_for_concat(right_is_any_value);\n"
"if (left_is_any_value && right_is_any_value) {\n"
"return %s_template(ANY_VALUE);\n" // special case: ? & ? => ?
"}\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos, *this);\n"
"ret_val.concat(pos, other_value);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, name, type);
def = mputprintf(def, "%s_template operator+(const %s& other_value) const;\n",
name, name);
src = mputprintf(src,
"%s_template %s_template::operator+(const %s& other_value) const\n"
"{\n"
"boolean dummy = FALSE;\n"
"int res_length = get_length_for_concat(dummy) + "
"get_length_for_concat(other_value);\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos, *this);\n"
"ret_val.concat(pos, other_value);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, type);
def = mputprintf(def, "%s_template operator+("
"const OPTIONAL<%s>& other_value) const;\n", name, name);
src = mputprintf(src,
"%s_template %s_template::operator+(const OPTIONAL<%s>& other_value) const\n"
"{\n"
"if (other_value.is_present()) {\n"
"return *this + (const %s&)other_value;\n"
"}\n"
"TTCN_error(\"Operand of %s of template concatenation is an unbound or "
"omitted record/set field.\");\n"
"}\n\n", name, name, name, name, sdef->kind == RECORD_OF ? "record" : "set");
def = mputprintf(def, "%s_template operator+(template_sel other_value) const;\n",
name);
src = mputprintf(src,
"%s_template %s_template::operator+(template_sel other_value) const\n"
"{\n"
"boolean left_is_any_value = FALSE;\n"
"int res_length = get_length_for_concat(left_is_any_value) + "
"get_length_for_concat(other_value);\n"
"if (left_is_any_value) {\n" // other_value can only be ANY_VALUE at this point
"return %s_template(ANY_VALUE);\n" // special case: ? & ? => ?
"}\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos, *this);\n"
"ret_val.concat(pos);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, type);
/* indexing operators */
/* Non-const operator[] is allowed to extend */
......@@ -4789,146 +4537,6 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
Free(def);
output->source.methods = mputstr(output->source.methods, src);
Free(src);
/* global functions */
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(template_sel left_template, "
"const %s_template& right_template);\n", name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(template_sel left_template, "
"const %s_template& right_template)\n"
"{\n"
"boolean right_is_any_value = FALSE;\n"
"int res_length = %s_template::get_length_for_concat(left_template) + "
"right_template.get_length_for_concat(right_is_any_value);\n"
"if (right_is_any_value) {\n" // left_template can only be ANY_VALUE at this point
"return %s_template(ANY_VALUE);\n" // special case: ? & ? => ?
"}\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos);\n"
"ret_val.concat(pos, right_template);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, name, type);
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(const %s& left_value, "
"const %s_template& right_template);\n", name, name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(const %s& left_value, "
"const %s_template& right_template)\n"
"{\n"
"boolean dummy = FALSE;\n"
"int res_length = %s_template::get_length_for_concat(left_value) + "
"right_template.get_length_for_concat(dummy);\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos, left_value);\n"
"ret_val.concat(pos, right_template);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, name, type);
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(const OPTIONAL<%s>& left_value, "
"const %s_template& right_template);\n", name, name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(const OPTIONAL<%s>& left_value, "
"const %s_template& right_template)\n"
"{\n"
"if (left_value.is_present()) {\n"
"return (const %s&)left_value + right_template;\n"
"}\n"
"TTCN_error(\"Operand of %s of template concatenation is an unbound or "
"omitted record/set field.\");\n"
"}\n\n", name, name, name, name, sdef->kind == RECORD_OF ? "record" : "set");
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(template_sel left_template, "
"const %s& right_value);\n", name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(template_sel left_template, const %s& right_value)\n"
"{\n"
"int res_length = %s_template::get_length_for_concat(left_template) + "
"%s_template::get_length_for_concat(right_value);\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos);\n"
"ret_val.concat(pos, right_value);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, name, type);
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(template_sel left_template, "
"const OPTIONAL<%s>& right_value);\n", name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(template_sel left_template, "
"const OPTIONAL<%s>& right_value)\n"
"{\n"
"if (right_value.is_present()) {\n"
"return left_template + (const %s&)right_value;\n"
"}\n"
"TTCN_error(\"Operand of %s template concatenation is an unbound or "
"omitted record/set field.\");\n"
"}\n\n", name, name, name, sdef->kind == RECORD_OF ? "record" : "set");
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(const %s& left_value, "
"template_sel right_template);\n", name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(const %s& left_value, template_sel right_template)\n"
"{\n"
"int res_length = %s_template::get_length_for_concat(left_value) + "
"%s_template::get_length_for_concat(right_template);\n"
"%s_template ret_val;\n"
"ret_val.template_selection = SPECIFIC_VALUE;\n"
"ret_val.single_value.n_elements = res_length;\n"
"ret_val.single_value.value_elements = "
"(%s_template**)allocate_pointers(res_length);\n"
"int pos = 0;\n"
"ret_val.concat(pos, left_value);\n"
"ret_val.concat(pos);\n"
"return ret_val;\n"
"}\n\n", name, name, name, name, name, type);
output->header.function_prototypes =
mputprintf(output->header.function_prototypes,
"extern %s_template operator+(const OPTIONAL<%s>& left_value, "
"template_sel right_template);\n", name, name);
output->source.function_bodies =
mputprintf(output->source.function_bodies,
"%s_template operator+(const OPTIONAL<%s>& left_value, "
"template_sel right_template)\n"
"{\n"
"if (left_value.is_present()) {\n"
"return (const %s&)left_value + right_template;\n"
"}\n"
"TTCN_error(\"Operand of %s template concatenation is an unbound or "
"omitted record/set field.\");\n"
"}\n\n", name, name, name, sdef->kind == RECORD_OF ? "record" : "set");
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
......
......@@ -37,6 +37,7 @@
#include "Constraint.hh"
#include "../common/JSON_Tokenizer.hh"
#include "ttcn3/Ttcn2Json.hh"
#include "main.hh"
#include <limits.h>
......@@ -1952,7 +1953,11 @@ void SubType::chk_this_template(Template *templ)
break;
case Template::ALL_FROM:
case Template::DECODE_MATCH:
break;
case Template::TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("SubType::chk_this_template()");
}
break;
case Template::SUPERSET_MATCH:
case Template::SUBSET_MATCH:
......
......@@ -8505,6 +8505,9 @@ namespace Ttcn {
chk_defpar_template(body->get_decode_target()->get_Template(), exp_val);
break;
case Template::TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("template concatenation in default parameter");
}
chk_defpar_template(body->get_concat_operand(true), exp_val);
chk_defpar_template(body->get_concat_operand(false), exp_val);
break;
......
......@@ -653,7 +653,7 @@ namespace Ttcn {
break;
case Type::T_USTR:
if (!type->has_encoding(Type::CT_XER) && !type->has_encoding(Type::CT_JSON)) {
act_attr->error("A `raw' %s value was used for erroneous type `%s' which has no XER or JSON encoding.",
act_attr->error("A `raw' %s value was used for erroneous type `%s' which has no XER or JSON encodings.",
ti_type->get_typename().c_str(), type->get_typename().c_str());
}
break;
......
......@@ -21,6 +21,7 @@
#include "../CompilerError.hh"
#include "../Code.hh"
#include "../../common/JSON_Tokenizer.hh"
#include "../main.hh"
#include "TtcnTemplate.hh"
......@@ -170,6 +171,9 @@ namespace Ttcn {
v_last = templ->get_specific_value();
break;
case Template::TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
}
if (templ->is_Value()) {
v = templ->get_Value();
v->set_my_governor(refcheckertype);
......
......@@ -97,6 +97,9 @@ namespace Ttcn {
u.dec_match.target = p.u.dec_match.target->clone();
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::clone()");
}
u.concat.op1 = p.u.concat.op1->clone();
u.concat.op2 = p.u.concat.op2->clone();
break;
......@@ -163,6 +166,9 @@ namespace Ttcn {
delete u.dec_match.target;
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::clean_up()");
}
delete u.concat.op1;
delete u.concat.op2;
break;
......@@ -306,6 +312,9 @@ namespace Ttcn {
ret_val += u.dec_match.target->get_Template()->create_stringRepr();
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::create_stringRepr()");
}
ret_val += u.concat.op1->create_stringRepr();
ret_val += " & ";
ret_val += u.concat.op2->create_stringRepr();
......@@ -357,8 +366,9 @@ namespace Ttcn {
delete v;
break;
case Value::V_EXPR:
if (v->get_optype() == Value::OPTYPE_CONCAT) {
if (use_runtime_2 && v->get_optype() == Value::OPTYPE_CONCAT) {
// convert the operands to templates with recursive calls to this constructor
// only in RT2
templatetype = TEMPLATE_CONCAT;
u.concat.op1 = new Template(v->get_concat_operand(true)->clone());
u.concat.op1->set_location(*v->get_concat_operand(true));
......@@ -586,6 +596,9 @@ namespace Ttcn {
u.dec_match.target->set_fullname(p_fullname + ".<decoding_target>");
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::set_fullname()");
}
u.concat.op1->set_fullname(p_fullname + ".operand1");
u.concat.op2->set_fullname(p_fullname + ".operand2");
break;
......@@ -651,6 +664,9 @@ namespace Ttcn {
u.dec_match.target->set_my_scope(p_scope);
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::set_my_scope()");
}
u.concat.op1->set_my_scope(p_scope);
u.concat.op2->set_my_scope(p_scope);
break;
......@@ -773,6 +789,9 @@ namespace Ttcn {
u.dec_match.target->set_code_section(p_code_section);
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::set_code_section()");
}
u.concat.op1->set_code_section(p_code_section);
u.concat.op2->set_code_section(p_code_section);
break;
......@@ -1007,6 +1026,9 @@ namespace Ttcn {
u.value_range->set_lowerid_to_ref();
break;
case TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("Template::set_lowerid_to_ref()");
}
u.concat.op1->set_lowerid_to_ref();
u.concat.op2->set_lowerid_to_ref();
break;
......@@ -1054,6 +1076,9 @@ namespace Ttcn {
case USTR_PATTERN:
return Type::T_USTR;
case TEMPLATE_CONCAT: {
if (!use_runtime_2) {
FATAL_ERROR("Template::get_expr_returntype()");
}
Type::typetype_t tt1 = u.concat.op1->get_expr_returntype(exp_val);
Type::typetype_t tt2 = u.concat.op2->get_expr_returntype(exp_val);
if (tt1 == Type::T_UNDEF) {
......@@ -1127,6 +1152,33 @@ namespace Ttcn {
goto error;
}
break; }
case TEMPLATE_CONCAT:
{
Type* t1_gov = u.concat.op1->get_expr_governor(exp_val);
Type* t2_gov = u.concat.op2->get_expr_governor(exp_val);
if (t1_gov != NULL) {
if (t2_gov != NULL) { // both have governors
// return the type that is compatible with both (if there is no type mismatch)
if (t1_gov->is_compatible(t2_gov, NULL, NULL)) {
return t1_gov;
}
else {
return t2_gov;
}
}
else {
return t1_gov;