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

Implemented 'map'/'unmap' parameters (bug 546286)



Change-Id: Ia0126bdc738d1abda7d2281ad95545e3443f59a8
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 20b35fba
......@@ -702,6 +702,10 @@ namespace Common {
* Only used with new codec handling. */
bool can_have_coding(MessageEncodingType_t coding);
/** Checks whether the type itself or one of its fields/elements is a
* component or default type. Recursive. */
void chk_map_param(Location* usage);
/** Return whether the two typetypes are compatible. Sometimes, this is
* just a question of \p p_tt1 == \p p_tt2. When there are multiple
* typetypes for a type (e.g. T_ENUM_A and T_ENUM_T) then all
......
......@@ -163,10 +163,18 @@ void Type::chk()
case T_ARRAY:
chk_Array();
break;
case T_PORT:
case T_PORT: {
u.port->chk();
Ttcn::FormalParList* map_params = u.port->get_map_parameters(true);
if (map_params != NULL) {
map_params->set_genname(get_genname_own());
}
Ttcn::FormalParList* unmap_params = u.port->get_map_parameters(false);
if (unmap_params != NULL) {
unmap_params->set_genname(get_genname_own());
}
if (w_attrib_path) u.port->chk_attributes(w_attrib_path);
break;
break; }
case T_SIGNATURE:
chk_Signature();
break;
......@@ -7730,4 +7738,43 @@ void Type::chk_this_template_Signature(Template *t, namedbool incomplete_allowed
"signature `%s'", get_typename().c_str());
}
void Type::chk_map_param(Location* usage)
{
Type* t = get_type_refd_last();
if (RecursionTracker::is_happening(t)) {
return;
}
RecursionTracker tracker(t);
switch (t->typetype) {
case T_COMPONENT:
case T_DEFAULT:
usage->error("The `map'/`unmap' parameters of a port type cannot be or "
"contain a field/element of %s type",
t->typetype == T_COMPONENT ? "component" : "default");
note("Prohibited type is here");
break;
case T_SEQ_T:
case T_SET_T:
case T_CHOICE_T:
case T_CHOICE_A:
case T_SEQ_A:
case T_SET_A:
case T_OPENTYPE:
case T_ANYTYPE:
for (size_t i = 0; i < t->u.secho.cfm->get_nof_comps(); ++i) {
t->u.secho.cfm->get_comp_byIndex(i)->get_type()->chk_map_param(usage);
}
break;
case T_SEQOF:
case T_SETOF:
case T_ARRAY:
t->get_ofType()->chk_map_param(usage);
break;
default:
// everything else is allowed
break;
}
}
} // namespace Common
......@@ -9583,6 +9583,22 @@ namespace Ttcn {
default:
break;
}
break;
case Definition::A_PORT:
switch (par->get_asstype()) {
case Definition::A_PAR_VAL:
case Definition::A_PAR_VAL_IN:
case Definition::A_PAR_VAL_OUT:
case Definition::A_PAR_VAL_INOUT:
// these are allowed
par->get_Type()->chk_map_param(par);
break;
default:
par->error("The `map'/`unmap' parameters of a port type cannot have %s",
par->get_assname());
break;
}
break;
default:
// everything is allowed for functions and altsteps
break;
......
......@@ -697,6 +697,7 @@ namespace Ttcn {
delete config_op.portref1;
delete config_op.compref2;
delete config_op.portref2;
delete config_op.ap_list;
break;
case S_START_TIMER:
delete timer_op.timerref;
......@@ -1423,7 +1424,8 @@ namespace Ttcn {
Statement::Statement(statementtype_t p_st,
Value *p_compref1, Reference *p_portref1,
Value *p_compref2, Reference *p_portref2)
Value *p_compref2, Reference *p_portref2,
ParsedActualParameters* p_params)
: statementtype(p_st), my_sb(0)
{
switch(statementtype) {
......@@ -1438,6 +1440,8 @@ namespace Ttcn {
config_op.compref2=p_compref2;
config_op.portref2=p_portref2;
config_op.translate=false;
config_op.parsed_params=p_params;
config_op.fp_list=NULL;
break;
default:
FATAL_ERROR("Statement::Statement()");
......@@ -1989,6 +1993,9 @@ namespace Ttcn {
config_op.portref1->set_my_scope(p_scope);
config_op.compref2->set_my_scope(p_scope);
config_op.portref2->set_my_scope(p_scope);
if (config_op.parsed_params != NULL) {
config_op.parsed_params->set_my_scope(p_scope);
}
break;
case S_START_TIMER:
timer_op.timerref->set_my_scope(p_scope);
......@@ -2307,6 +2314,9 @@ namespace Ttcn {
config_op.portref1->set_fullname(p_fullname+".portref1");
config_op.compref2->set_fullname(p_fullname+".compref2");
config_op.portref2->set_fullname(p_fullname+".portref2");
if (config_op.parsed_params != NULL) {
config_op.parsed_params->set_fullname(p_fullname+".<parameters>");
}
break;
case S_START_TIMER:
timer_op.timerref->set_fullname(p_fullname+".timerref");
......@@ -5031,6 +5041,12 @@ error:
"endpoint is unknown",
ptb1 != NULL ? "second" : "first");
}
if (config_op.parsed_params != NULL &&
((cref1_is_system && ptb1 == NULL) ||
(cref2_is_system && ptb2 == NULL))) {
error("Cannot determine system component in `%s' operation with "
"`param' clause", get_stmt_name());
}
return;
}
if (cref1_is_tc || cref2_is_system) {
......@@ -5100,6 +5116,32 @@ error:
}
}
}
if (config_op.parsed_params != NULL) {
if (cref1_is_system) {
config_op.fp_list = ptb1->get_map_parameters(statementtype == S_MAP);
}
else if (cref2_is_system) {
config_op.fp_list = ptb2->get_map_parameters(statementtype == S_MAP);
}
else {
error("Cannot determine system component in `%s' operation with "
"`param' clause", get_stmt_name());
}
if (config_op.fp_list != NULL) {
ActualParList* parlist = new ActualParList;
if (config_op.fp_list->fold_named_and_chk(config_op.parsed_params, parlist)) {
delete parlist;
delete config_op.parsed_params;
config_op.ap_list = NULL;
} else {
delete config_op.parsed_params;
parlist->set_fullname(get_fullname());
parlist->set_my_scope(my_sb);
config_op.ap_list = parlist;
}
}
}
}
void Statement::chk_start_timer()
......@@ -7816,6 +7858,60 @@ error:
// a simple string shall be formed from the port name and array indices
generate_code_portref(&expr, config_op.portref2);
}
if (config_op.ap_list != NULL) {
// handle 'map'/'unmap' parameters
size_t nof_pars = config_op.ap_list->get_nof_pars();
string tmp_id = my_sb->get_scope_mod_gen()->get_temporary_id();
expr.preamble = mputprintf(expr.preamble,
"Map_Params %s(%u);\n", tmp_id.c_str(), (unsigned int) nof_pars);
for (size_t i = 0; i < nof_pars; ++i) {
ActualPar* ap = config_op.ap_list->get_par(i);
FormalPar* fp = config_op.fp_list->get_fp_byIndex(i);
bool copy_needed = ap->get_selection() == ActualPar::AP_VALUE;
expression_struct par_expr;
Code::init_expr(&par_expr);
ap->generate_code(&par_expr, copy_needed, fp);
if (fp->get_asstype() != Definition::A_PAR_VAL_OUT) {
// set the values of 'in' and 'inout' parameters before the call
if (par_expr.preamble != NULL) {
expr.preamble = mputstr(expr.preamble, par_expr.preamble);
}
expr.preamble = mputprintf(expr.preamble,
"%s.set_param(%u, ttcn_to_string(%s));\n",
tmp_id.c_str(), (unsigned int) i, par_expr.expr);
}
else {
// set empty strings for 'out' parameters
expr.preamble = mputprintf(expr.preamble,
"%s.set_param(%u, CHARSTRING(\"\"));\n",
tmp_id.c_str(), (unsigned int) i);
}
if (fp->get_asstype() == Definition::A_PAR_VAL_OUT ||
fp->get_asstype() == Definition::A_PAR_VAL_INOUT) {
// store the new values of 'out' and 'inout' parameters after the call
// note: this only works in single mode, in parallel mode execution
// will continue after the mapping request, without waiting for a
// reply that could contain the new values of the parameters
expr.postamble = mputprintf(expr.postamble,
"if (%s.get_param(%u).lengthof() > 0) "
"string_to_ttcn(%s.get_param(%u), %s);\n",
tmp_id.c_str(), (unsigned int) i,
tmp_id.c_str(), (unsigned int) i, par_expr.expr);
if (par_expr.postamble != NULL) {
expr.postamble = mputstr(expr.postamble, par_expr.postamble);
}
}
Code::free_expr(&par_expr);
}
expr.expr = mputprintf(expr.expr, ", %s", tmp_id.c_str());
}
else if (statementtype == S_MAP || statementtype == S_UNMAP) {
// create an empty struct for 'connect' and 'disconnect'
string tmp_id = my_sb->get_scope_mod_gen()->get_temporary_id();
expr.preamble = mputprintf(expr.preamble,
"Map_Params %s(0);\n", tmp_id.c_str());
expr.expr = mputprintf(expr.expr, ", %s", tmp_id.c_str());
}
if (config_op.translate == true) {
expr.expr = mputstr(expr.expr, ", TRUE");
}
......
......@@ -350,6 +350,11 @@ namespace Ttcn {
Value *compref2;
Reference *portref2;
bool translate; // true if a map statement enables translation mode
union {
ParsedActualParameters* parsed_params;
ActualParList* ap_list;
};
FormalParList* fp_list; // not owned
} config_op; ///< used by S_CONNECT, S_MAP, S_DISCONNECT, S_UNMAP
struct {
......@@ -618,7 +623,8 @@ namespace Ttcn {
/** Constructor used by S_CONNECT, S_DISCONNECT, S_MAP, S_UNMAP */
Statement(statementtype_t p_st,
Value *p_compref1, Reference *p_portref1,
Value *p_compref2, Reference *p_portref2);
Value *p_compref2, Reference *p_portref2,
ParsedActualParameters* p_params);
/** Constructor used by S_TESTCASE_INSTANCE */
Statement(statementtype_t p_st, Ref_pard *p_ref, Value *p_val);
/** Constructor used by S_ACTIVATE_REFD */
......
......@@ -1036,7 +1036,7 @@ namespace Ttcn {
PortTypeBody::PortTypeBody(PortOperationMode_t p_operation_mode,
Types *p_in_list, Types *p_out_list, Types *p_inout_list,
bool p_in_all, bool p_out_all, bool p_inout_all, Definitions *defs,
bool p_realtime)
bool p_realtime, FormalParList *p_map_params, FormalParList *p_unmap_params)
: Node(), Location(), my_type(0), operation_mode(p_operation_mode),
in_list(p_in_list), out_list(p_out_list), inout_list(p_inout_list),
in_all(p_in_all), out_all(p_out_all), inout_all(p_inout_all),
......@@ -1044,7 +1044,8 @@ namespace Ttcn {
in_msgs(0), out_msgs(0), in_sigs(0), out_sigs(0),
testport_type(TP_REGULAR), port_type(PT_REGULAR),
provider_refs(), provider_types(),
in_mappings(0), out_mappings(0), vardefs(defs), realtime(p_realtime)
in_mappings(0), out_mappings(0), vardefs(defs), realtime(p_realtime),
map_params(p_map_params), unmap_params(p_unmap_params)
{
}
......@@ -1065,6 +1066,8 @@ namespace Ttcn {
delete in_mappings;
delete out_mappings;
delete vardefs;
delete map_params;
delete unmap_params;
}
PortTypeBody *PortTypeBody::clone() const
......@@ -1088,6 +1091,12 @@ namespace Ttcn {
if (in_mappings) in_mappings->set_fullname(p_fullname + ".<in_mappings>");
if (out_mappings) out_mappings->set_fullname(p_fullname + ".<out_mappings>");
vardefs->set_fullname(p_fullname + ".<port_var>");
if (map_params != NULL) {
map_params->set_fullname(p_fullname + ".<map_params>");
}
if (unmap_params != NULL) {
unmap_params->set_fullname(p_fullname + ".<unmap_params>");
}
}
void PortTypeBody::set_my_scope(Scope *p_scope)
......@@ -1101,6 +1110,12 @@ namespace Ttcn {
if (in_mappings) in_mappings->set_my_scope(p_scope);
if (out_mappings) out_mappings->set_my_scope(p_scope);
vardefs->set_parent_scope(p_scope);
if (map_params != NULL) {
map_params->set_my_scope(p_scope);
}
if (unmap_params != NULL) {
unmap_params->set_my_scope(p_scope);
}
}
void PortTypeBody::set_my_type(Type *p_type)
......@@ -1186,6 +1201,11 @@ namespace Ttcn {
if (!checked) FATAL_ERROR("PortTypeBody::is_internal_port()");
return testport_type == TP_INTERNAL;
}
FormalParList* PortTypeBody::get_map_parameters(bool map) const
{
return map ? map_params : unmap_params;
}
Type *PortTypeBody::get_address_type()
{
......@@ -1776,6 +1796,15 @@ namespace Ttcn {
if (provider_refs.size() == 0 && vardefs->get_nof_asss() > 0) {
error("Port variables can only be used when the port is a translation port.");
}
if (map_params != NULL) {
Error_Context cntxt(map_params, "In `map' parameters");
map_params->chk(Definition::A_PORT);
}
if (unmap_params != NULL) {
Error_Context cntxt(unmap_params, "In `unmap' parameters");
unmap_params->chk(Definition::A_PORT);
}
}
void PortTypeBody::chk_attributes(Ttcn::WithAttribPath *w_attrib_path)
......@@ -2115,6 +2144,12 @@ namespace Ttcn {
void PortTypeBody::generate_code(output_struct *target)
{
if (!checked || !my_type) FATAL_ERROR("PortTypeBody::generate_code()");
if (map_params != NULL) {
map_params->generate_code_defval(target);
}
if (unmap_params != NULL) {
unmap_params->generate_code_defval(target);
}
stringpool pool;
port_def pdef;
memset(&pdef, 0, sizeof(pdef));
......@@ -2593,6 +2628,14 @@ namespace Ttcn {
DEBUG(level, "out mappings:");
out_mappings->dump(level + 1);
}
if (map_params != NULL) {
DEBUG(level, "map parameters:");
map_params->dump(level + 1);
}
if (unmap_params != NULL) {
DEBUG(level, "unmap parameters:");
unmap_params->dump(level + 1);
}
}
// =================================
......
......@@ -405,6 +405,7 @@ private:
TypeMappings *in_mappings, *out_mappings; ///< mappings for PT_USER
Definitions *vardefs; ///< variable definitions inside the port
bool realtime;
FormalParList *map_params, *unmap_params;
/** Copy constructor not implemented */
PortTypeBody(const PortTypeBody& p);
/** Assignment disabled */
......@@ -413,7 +414,7 @@ public:
PortTypeBody(PortOperationMode_t p_operation_mode,
Types *p_in_list, Types *p_out_list, Types *p_inout_list,
bool p_in_all, bool p_out_all, bool p_inout_all, Definitions *defs,
bool p_realtime);
bool p_realtime, FormalParList *p_map_params, FormalParList *p_unmap_params);
~PortTypeBody();
virtual PortTypeBody *clone() const;
virtual void set_fullname(const string& p_fullname);
......@@ -430,6 +431,7 @@ public:
bool getreply_allowed() const;
bool catch_allowed() const;
bool is_internal() const;
FormalParList* get_map_parameters(bool map) const;
/** Returns the address type that can be used in communication operations
* on this port type. NULL is returned if addressing inside SUT is not
* supported or the address type does not exist. */
......
......@@ -288,6 +288,7 @@ static const string anyname("anytype");
TypeMappings *in_mappings, *out_mappings;
size_t varnElements;
Ttcn::Definition **varElements;
FormalParList *map_params, *unmap_params;
} portdefbody;
struct {
......@@ -978,7 +979,7 @@ static const string anyname("anytype");
TemplateFormalPar FunctionFormalPar TestcaseFormalPar
%type <formalparlist> optTemplateFormalParList TemplateFormalParList
optFunctionFormalParList FunctionFormalParList optTestcaseFormalParList
TestcaseFormalParList optAltstepFormalParList
TestcaseFormalParList optAltstepFormalParList FormalValueParList
%type <group> GroupDef GroupIdentifier
%type <friend_list> FriendModuleDef
%type <ifclause> ElseIfClause
......@@ -1038,7 +1039,7 @@ static const string anyname("anytype");
optReceiveParameter
%type <parsedpar> FunctionActualParList TestcaseActualParList
optFunctionActualParList optTestcaseActualParList
NamedPart UnnamedPart
NamedPart UnnamedPart optParamClause
%type <templinsts> optTemplateActualParList
seqTemplateActualPar seqTemplateInstance
%type <templs> ValueOrAttribList seqValueOrAttrib ValueList Complement
......@@ -1269,6 +1270,7 @@ ForStatement
FormalTemplatePar
FormalTimerPar
FormalValuePar
FormalValueParList
FromClause
FullGroupIdentifier
FunctionActualPar
......@@ -1475,6 +1477,7 @@ optFunctionActualParList
optFunctionFormalParList
optMtcSpec
optParDefaultValue
optParamClause
optPortCallBody
optPortRedirectOutgoing
optReceiveParameter
......@@ -1576,6 +1579,8 @@ StructOfDefBody
delete $$.varElements[i];
}
delete $$.varElements;
delete $$.map_params;
delete $$.unmap_params;
}
PortDefList
PortDefLists
......@@ -2886,7 +2891,8 @@ PortDefAttribs: // 60
Free($3.varElements);
PortTypeBody *body = new PortTypeBody($1,
$3.in_list, $3.out_list, $3.inout_list,
$3.in_all, $3.out_all, $3.inout_all, defs, $2);
$3.in_all, $3.out_all, $3.inout_all, defs, $2,
$3.map_params, $3.unmap_params);
body->set_location(infile, @$);
$$ = new Type(Type::T_PORT, body);
$$->set_location(infile, @$);
......@@ -2904,7 +2910,8 @@ PortDefAttribs: // 60
Free($6.varElements);
PortTypeBody *body = new PortTypeBody($1,
$6.in_list, $6.out_list, $6.inout_list,
$6.in_all, $6.out_all, $6.inout_all, defs, $2);
$6.in_all, $6.out_all, $6.inout_all, defs, $2,
$6.map_params, $6.unmap_params);
body->set_location(infile, @$);
$$ = new Type(Type::T_PORT, body);
body->add_user_attribute($5.elements, $5.nElements, $6.in_mappings, $6.out_mappings, false);
......@@ -2934,6 +2941,8 @@ PortDefLists:
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
;
......@@ -3004,6 +3013,26 @@ seqPortDefList:
}
Free($2.varElements);
}
if ($2.map_params != NULL) {
if ($$.map_params != NULL) {
Location loc(infile, @2);
loc.error("Multiple `map' parameter lists in port type definition");
delete $2.map_params;
}
else {
$$.map_params = $2.map_params;
}
}
if ($2.unmap_params != NULL) {
if ($$.unmap_params != NULL) {
Location loc(infile, @2);
loc.error("Multiple `unmap' parameter lists in port type definition");
delete $2.unmap_params;
}
else {
$$.unmap_params = $2.unmap_params;
}
}
}
;
......@@ -3031,6 +3060,8 @@ PortDefList:
$$.inout_all = false;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| OutParKeyword AllOrTypeListWithTo
{
......@@ -3055,6 +3086,8 @@ PortDefList:
$$.inout_all = false;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| InOutParKeyword AllOrTypeList
{
......@@ -3075,6 +3108,8 @@ PortDefList:
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| InParKeyword error
{
......@@ -3088,6 +3123,8 @@ PortDefList:
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| OutParKeyword error
{
......@@ -3101,6 +3138,8 @@ PortDefList:
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| InOutParKeyword error
{
......@@ -3114,6 +3153,8 @@ PortDefList:
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| PortElementVarDef optSemiColon {
$$.in_list = 0;
......@@ -3130,7 +3171,54 @@ PortDefList:
$$.varElements[i] = $1.elements[i];
}
delete $1.elements;
}
$$.map_params = NULL;
$$.unmap_params = NULL;
}
| MapKeyword ParamKeyword '(' FormalValueParList ')'
{
$$.in_list = 0;
$$.out_list = 0;
$$.inout_list = 0;
$$.in_all = false;
$$.out_all = false;
$$.inout_all = false;
$$.in_mappings = 0;
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = $4;
$$.map_params->set_location(infile, @4);
$$.unmap_params = NULL;
}
| UnmapKeyword ParamKeyword '(' FormalValueParList ')'
{
$$.in_list = 0;
$$.out_list = 0;
$$.inout_list = 0;
$$.in_all = false;
$$.out_all = false;
$$.inout_all = false;
$$.in_mappings = 0;
$$.out_mappings = 0;
$$.varnElements = 0;
$$.varElements = 0;
$$.map_params = NULL;
$$.unmap_params = $4;
$$.unmap_params->set_location(infile, @4);
}
;
FormalValueParList:
FormalValuePar
{
$$ = new FormalParList;
$$->add_fp($1);
}
| FormalValueParList ',' FormalValuePar
{
$$ = $1;
$$->add_fp($3);
}
;
WithList:
......@@ -6072,7 +6160,7 @@ ConnectStatement: // 329
ConnectKeyword SingleConnectionSpec
{
$$=new Statement(Statement::S_CONNECT,
$2.compref1, $2.portref1, $2.compref2, $2.portref2);
$2.compref1, $2.portref1, $2.compref2, $2.portref2, NULL);
$$->set_location(infile, @$);
}
;
......@@ -6115,7 +6203,7 @@ DisconnectStatement: // 335
{
if ($2.portref1 && $2.portref2 && $2.compref1 && $2.compref2) {