Commit e1ade5ad authored by BenceJanosSzabo's avatar BenceJanosSzabo
Browse files

Allowed send and receive in translation functions (Bug 522632)



Change-Id: I591ef4fd722709f63576da0428a26ffce93dd1c5
Signed-off-by: default avatarBenceJanosSzabo <bence.janos.szabo@ericsson.com>
parent 603b99b3
......@@ -1089,14 +1089,15 @@ namespace Ttcn {
}
Statement::Statement(statementtype_t p_st, Reference *p_ref,
TemplateInstance *p_templinst, Value *p_val)
TemplateInstance *p_templinst, Value *p_val, bool p_translate)
: statementtype(p_st), my_sb(0)
{
switch(statementtype) {
case S_SEND:
if(!p_ref || !p_templinst)
if((!p_ref && p_translate == false) || !p_templinst)
FATAL_ERROR("Statement::Statement()");
port_op.portref=p_ref;
port_op.translate = p_translate;
port_op.s.sendpar=p_templinst;
port_op.s.toclause=p_val;
break;
......@@ -1169,13 +1170,14 @@ namespace Ttcn {
TemplateInstance *p_templinst,
TemplateInstance *p_fromclause,
ValueRedirect *p_redirectval, Reference *p_redirectsender,
Reference* p_redirectindex)
Reference* p_redirectindex, bool p_translate)
: statementtype(p_st), my_sb(0)
{
switch(statementtype) {
case S_RECEIVE:
case S_CHECK_RECEIVE:
case S_TRIGGER:
port_op.translate = p_translate;
port_op.portref=p_ref;
port_op.anyfrom = p_anyfrom;
port_op.r.rcvpar=p_templinst;
......@@ -1800,7 +1802,7 @@ namespace Ttcn {
if (deactivate) deactivate->set_my_scope(p_scope);
break;
case S_SEND:
port_op.portref->set_my_scope(p_scope);
if (!port_op.translate) port_op.portref->set_my_scope(p_scope);
port_op.s.sendpar->set_my_scope(p_scope);
if(port_op.s.toclause) port_op.s.toclause->set_my_scope(p_scope);
break;
......@@ -2075,7 +2077,7 @@ namespace Ttcn {
if (deactivate) deactivate->set_fullname(p_fullname+".deact");
break;
case S_SEND:
port_op.portref->set_fullname(p_fullname+".portref");
if (!port_op.translate) port_op.portref->set_fullname(p_fullname+".portref");
port_op.s.sendpar->set_fullname(p_fullname+".sendpar");
if(port_op.s.toclause)
port_op.s.toclause->set_fullname(p_fullname+".to");
......@@ -3577,7 +3579,17 @@ error:
{
Error_Context cntxt(this, "In send statement");
// checking the port reference
Type *port_type = chk_port_ref(port_op.portref);
Type *port_type;
if (port_op.translate) {
PortScope* ps = my_sb->get_scope_port();
if (ps) {
port_type = ps->get_port_type();
} else {
error("Cannot determine the type or the port: Missing port clause on the function.");
}
} else {
port_type = chk_port_ref(port_op.portref);
}
// determining the message type
Type *msg_type = 0;
bool msg_type_determined = false;
......@@ -3961,7 +3973,17 @@ error:
const char *stmt_name = get_stmt_name();
Error_Context cntxt(this, "In %s statement", stmt_name);
// checking the port reference
Type *port_type = chk_port_ref(port_op.portref, port_op.anyfrom);
Type *port_type;
if (port_op.translate) {
PortScope* ps = my_sb->get_scope_port();
if (ps) {
port_type = ps->get_port_type();
} else {
error("Cannot determine the type or the port: Missing port clause on the function.");
}
} else {
port_type = chk_port_ref(port_op.portref, port_op.anyfrom);
}
// checking the parameter and/or value redirect
if (port_op.r.rcvpar) {
// the receive parameter (template instance) is present
......@@ -4009,7 +4031,7 @@ error:
port_op.portref->error("Port type `%s' does not have any incoming "
"message types", port_type->get_typename().c_str());
}
} else if (!port_op.portref) {
} else if (!port_op.portref && port_op.translate == false) {
// the statement refers to 'any port'
port_op.r.rcvpar->error("Operation `any port.%s' cannot have parameter",
stmt_name);
......@@ -5902,7 +5924,7 @@ error:
if (deactivate) deactivate->set_code_section(p_code_section);
break;
case S_SEND:
port_op.portref->set_code_section(p_code_section);
if (!port_op.translate) port_op.portref->set_code_section(p_code_section);
port_op.s.sendpar->set_code_section(p_code_section);
if (port_op.s.toclause)
port_op.s.toclause->set_code_section(p_code_section);
......@@ -7395,8 +7417,12 @@ error:
{
expression_struct expr;
Code::init_expr(&expr);
port_op.portref->generate_code(&expr);
expr.expr = mputstr(expr.expr, ".send(");
if (!port_op.translate) {
port_op.portref->generate_code(&expr);
expr.expr = mputstr(expr.expr, ".send(");
} else {
expr.expr = mputstr(expr.expr, "send(");
}
generate_code_expr_sendpar(&expr);
if (port_op.s.toclause) {
expr.expr = mputstr(expr.expr, ", ");
......@@ -7878,10 +7904,16 @@ error:
void Statement::generate_code_expr_receive(expression_struct *expr,
const char *opname)
{
if (port_op.portref) {
// The operation refers to a specific port.
port_op.portref->generate_code(expr);
expr->expr = mputprintf(expr->expr, ".%s(", opname);
if (port_op.portref || port_op.translate) {
if (!port_op.translate) {
// The operation refers to a specific port.
port_op.portref->generate_code(expr);
expr->expr = mputprintf(expr->expr, ".%s(", opname);
} else {
// No need for a reference because the send will be called
// on *this in the c++ code.
expr->expr = mputprintf(expr->expr, "%s(", opname);
}
if (port_op.r.rcvpar) {
// The receive parameter is present.
bool has_decoded_redirect = port_op.r.redirect.value != NULL &&
......@@ -7901,7 +7933,7 @@ error:
generate_code_expr_fromclause(expr);
expr->expr = mputstr(expr->expr, ", ");
generate_code_expr_senderredirect(expr);
if (port_op.portref) {
if (port_op.portref || port_op.translate) {
expr->expr = mputstr(expr->expr, ", ");
if (port_op.r.redirect.index != NULL) {
generate_code_index_redirect(expr, port_op.r.redirect.index, my_sb);
......
......@@ -289,6 +289,8 @@ namespace Ttcn {
LogArguments *logargs; ///< used by S_ACTION, S_LOG, S_STOP_TESTCASE
struct {
Reference *portref; /**< NULL means any/all */
bool translate; /**< true if it an operation from a translation function:
* For example: port.send(3) or port.receive(4)*/
bool anyfrom;
union {
struct {
......@@ -547,7 +549,7 @@ namespace Ttcn {
Statement(statementtype_t p_st, Value *p_val, LogArguments *p_logargs);
/** Constructor used by S_SEND */
Statement(statementtype_t p_st, Reference *p_ref,
TemplateInstance *p_templinst, Value *p_val);
TemplateInstance *p_templinst, Value *p_val, bool p_translate);
/** Constructor used by S_CALL */
Statement(statementtype_t p_st, Reference *p_ref,
TemplateInstance *p_templinst, Value *p_timerval,
......@@ -565,7 +567,7 @@ namespace Ttcn {
Statement(statementtype_t p_st, Reference *p_ref, bool p_anyfrom,
TemplateInstance *p_templinst, TemplateInstance *p_fromclause,
ValueRedirect *p_redirectval, Reference *p_redirectsender,
Reference* p_redirectindex);
Reference* p_redirectindex, bool p_translate);
/** Constructor used by S_GETCALL and S_CHECK_GETCALL. p_ref==0
* means any port. */
Statement(statementtype_t p_st, Reference *p_ref, bool p_anyfrom,
......
......@@ -6320,7 +6320,12 @@ CommunicationStatements: // 353
SendStatement: // 354
Port DotSendOpKeyword PortSendOp
{
$$ = new Statement(Statement::S_SEND, $1, $3.templ_inst, $3.val);
$$ = new Statement(Statement::S_SEND, $1, $3.templ_inst, $3.val, false);
$$->set_location(infile, @$);
}
| PortKeyword DotSendOpKeyword PortSendOp
{
$$ = new Statement(Statement::S_SEND, NULL, $3.templ_inst, $3.val, true);
$$->set_location(infile, @$);
}
;
......@@ -6549,7 +6554,14 @@ ReceiveStatement: // 380
{
$$ = new Statement(Statement::S_RECEIVE, $1.reference, $1.any_from,
$3.templ_inst, $3.fromclause, $3.redirectval,
$3.redirectsender, $3.redirectindex);
$3.redirectsender, $3.redirectindex, false);
$$->set_location(infile, @$);
}
| PortKeyword DotReceiveOpKeyword PortReceiveOp
{
$$ = new Statement(Statement::S_RECEIVE, NULL, false,
$3.templ_inst, $3.fromclause, $3.redirectval,
$3.redirectsender, $3.redirectindex, true);
$$->set_location(infile, @$);
}
;
......@@ -6731,7 +6743,7 @@ TriggerStatement: // 393
{
$$ = new Statement(Statement::S_TRIGGER, $1.reference, $1.any_from,
$3.templ_inst, $3.fromclause, $3.redirectval,
$3.redirectsender, $3.redirectindex);
$3.redirectsender, $3.redirectindex, false);
$$->set_location(infile, @$);
}
;
......@@ -7113,7 +7125,7 @@ CheckStatement: // 415
case Statement::S_CHECK_RECEIVE:
$$ = new Statement(Statement::S_CHECK_RECEIVE, $1.reference, $1.any_from,
$3.templ_inst, $3.fromclause, $3.redirectval,
$3.redirectsender, $3.redirectindex);
$3.redirectsender, $3.redirectindex, false);
break;
case Statement::S_CHECK_GETCALL:
$$ = new Statement(Statement::S_CHECK_GETCALL, $1.reference, $1.any_from,
......
......@@ -118,14 +118,15 @@ struct TTCN_Runtime::component_process_struct {
} **TTCN_Runtime::components_by_compref = NULL,
**TTCN_Runtime::components_by_pid = NULL;
boolean TTCN_Runtime::translation_flag = FALSE;
int TTCN_Runtime::translation_count = 0;
PORT* TTCN_Runtime::p = NULL;
void TTCN_Runtime::set_port_state(const INTEGER& state, const CHARSTRING& info, boolean by_system) {
if (translation_flag) {
if (translation_count > 0) {
if (p != NULL) {
int lowed_end = by_system ? -1 : 0;
if (state < lowed_end || state > 3) {
translation_count--;
TTCN_error("The value of the first parameter in the setstate operation must be 0, 1, 2 or 3.");
}
p->change_port_state((translation_port_state)((int)state));
......@@ -135,12 +136,23 @@ void TTCN_Runtime::set_port_state(const INTEGER& state, const CHARSTRING& info,
}
} else {
TTCN_error("setstate operation was called without being in a translation procedure.");
translation_count--;
}
}
void TTCN_Runtime::set_translation_mode(boolean enabled, PORT* port) {
translation_flag = enabled;
p = port;
if (enabled) {
translation_count++;
} else {
translation_count--;
if (translation_count < 0) {
translation_count = 0; // Expect the unexpected
}
}
// Only allow p to be null if we really not in a translation procedure.
if (translation_count == 0 || port != NULL) {
p = port;
}
}
boolean TTCN_Runtime::is_idle()
......
......@@ -96,9 +96,11 @@ private:
static component_process_struct **components_by_compref,
**components_by_pid;
// Translation flag is set to true before each port translation function called,
// and set to false after each port translation function.
static boolean translation_flag;
// Translation count is increased before each port translation function called,
// and decreased after each port translation function.
// Need to count because we can now send and receive in translation
// functions and can call another translation function.
static int translation_count;
// The port which state will be changed by change_port_state
static PORT* p;
......
......@@ -22,7 +22,12 @@ module PortVariables {
type port NVP1 message map to VP1 {
out charstring to integer with char_to_default_int_template() : charstring with char_to_default_char() : charstring with char_to_default_const_char() : RoI with char_to_default_roi() : integer with char_to_int();
in integer, charstring, RoI;
in octetstring from integer with double_receive_test();
in integer from integer with int_to_int(), charstring, RoI;
out octetstring to integer with double_send_test();
const charstring c_cs := "DefaultConst"
var charstring cs := "Default";
......@@ -95,7 +100,65 @@ module PortVariables {
}
function double_send_test(in octetstring input, out integer output) port NVP1 {
if (input == 'BEEF'O) {
output := lengthof(input);
// Send here and receive here
port.send('12345678'O);
timer t := 0.5;
t.start;
// '12345678'O was mapped to its length in double_receive_test() function
alt {
[] port.receive(4) { setverdict(pass); }
[] t.timeout { setverdict(fail); }
}
t.stop;
port.setstate(0);
// Send again to receive in the testcase
port.send('1234567891'O);
} else if (input == '1234567891'O or input == '12345678'O) {
output := lengthof(input);
port.setstate(0);
} else if (input == 'AB'O or input == 'CD'O) {
// This just maps the value to integer, needed for the receive test
output := oct2int(input);
port.setstate(0);
}
} with {
extension "prototype(fast)";
}
function double_receive_test(in integer input, out octetstring output) port NVP1 {
if (int2oct(input,2) == '00AB'O) {
timer t := 0.5;
// Send and receive
port.send('12345678'O);
t.start;
// '12345678'O was mapped to its length in double_receive_test() function
alt {
[] port.receive(4) { setverdict(pass); }
[] t.timeout { setverdict(fail); }
}
t.stop;
output := int2oct(input, 1);
port.setstate(0);
} else {
port.setstate(1);
}
} with {
extension "prototype(fast)";
}
function int_to_int(in integer input, out integer output) port NVP1 {
// we receive the length of '1234567891'O here
output := input;
port.setstate(0);
} with {
extension "prototype(fast)";
}
type component MyComp {
......@@ -294,9 +357,46 @@ module PortVariables {
}
}
testcase tc_double_send_and_receive_test() runs on MyComp system System {
map(self:p[0], system:p1);
// Test that we can send and receive during the execution of the translation function
p[0].send('BEEF'O);
timer t := 0.5;
t.start;
alt {
// First receive the length of 1234567891
[] p[0].receive(5) { setverdict(pass); }
[] t.timeout { setverdict(fail); }
}
t.stop;
t.start;
alt {
// Then receive length of BEEF
[] p[0].receive(2) { setverdict(pass); }
[] t.timeout { setverdict(fail); }
}
t.stop;
// Test that we can send and receive during a receiving translation function
p[0].send('AB'O);
t.start;
alt {
// Then receive back 'AB'O
[] p[0].receive('AB'O) { setverdict(pass); }
[] t.timeout { setverdict(fail); }
}
t.stop;
}
control {
execute(tc_variable_change_test(true));
// Test that the variables are restored to the default values
execute(tc_variable_change_test(false));
execute(tc_double_send_and_receive_test());
}
}
\ No newline at end of file
......@@ -103,7 +103,6 @@ module Setstate_neg {
setverdict(fail);
}
}
@try {
var charstring cs;
int_to_char(4, cs);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment