From 78a82971bdd606e92e522b9808e27991ddad7dc9 Mon Sep 17 00:00:00 2001 From: Botond Baranyi <botond.baranyi@ericsson.com> Date: Wed, 28 Mar 2018 16:48:17 +0200 Subject: [PATCH] Implemented operation 'port.getref()' (bug 533006) Change-Id: I9158d29e0e81ed2265a148081d8bcea6f3e82025 Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com> --- compiler2/Value.cc | 54 +++++++++++++++++++ compiler2/Value.hh | 5 +- compiler2/ttcn3/AST_ttcn3.cc | 21 ++++++-- compiler2/ttcn3/Ttcnstuff.cc | 6 ++- compiler2/ttcn3/Ttcnstuff.hh | 1 + compiler2/ttcn3/compiler.l | 2 + compiler2/ttcn3/compiler.y | 17 ++++-- core/Runtime.cc | 7 +++ core/Runtime.hh | 1 + .../portTranslation/PortTranslation.ttcn | 19 +++++-- xsdconvert/converter.cc | 2 +- 11 files changed, 121 insertions(+), 14 deletions(-) diff --git a/compiler2/Value.cc b/compiler2/Value.cc index c4a679e1e..d551c1c13 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -171,6 +171,9 @@ namespace Common { case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: break; + case OPTYPE_GET_PORT_REF: + u.expr.type = p.u.expr.type; // the type is not owned, don't copy it + break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: u.expr.r2 = p.u.expr.r2 != NULL ? p.u.expr.r2->clone() : NULL; @@ -526,6 +529,7 @@ namespace Common { case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: // type (not owned) break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: @@ -928,6 +932,9 @@ namespace Common { case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: break; + case OPTYPE_GET_PORT_REF: + u.expr.type = NULL; // will be set during semantic analysis + break; default: FATAL_ERROR("Value::Value()"); } // switch @@ -1751,6 +1758,7 @@ namespace Common { case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: @@ -1998,6 +2006,7 @@ namespace Common { case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: @@ -2373,6 +2382,7 @@ namespace Common { case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: @@ -3345,6 +3355,8 @@ namespace Common { return Type::T_BOOL; case OPTYPE_GETVERDICT: return Type::T_VERDICT; + case OPTYPE_GET_PORT_REF: + return Type::T_PORT; case OPTYPE_VALUEOF: { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); @@ -3790,6 +3802,9 @@ namespace Common { } else return 0; case OPTYPE_COMP_CREATE: return chk_expr_operand_comptyperef_create(); + case OPTYPE_GET_PORT_REF: + chk_expr_operands(NULL, exp_val); // calculate the port type + return u.expr.type; default: break; } @@ -4079,6 +4094,8 @@ namespace Common { return "ttcn2string()"; case OPTYPE_PROF_RUNNING: return "@profiler.running"; + case OPTYPE_GET_PORT_REF: + return "port.getref()"; default: FATAL_ERROR("Value::get_opname()"); } // switch @@ -6876,6 +6893,26 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: break; + case OPTYPE_GET_PORT_REF: + if (u.expr.type == NULL) { + Ttcn::PortScope* port_scope = my_scope->get_scope_port(); + if (port_scope == NULL) { + error("Operation `%s' can only be used in a function with a port clause.", + opname); + set_valuetype(V_ERROR); + break; + } + u.expr.type = port_scope->get_port_type(); + if (u.expr.type == NULL) { + FATAL_ERROR("Value::chk_expr_operands"); + } + if (my_governor != NULL && !u.expr.type->is_identical(my_governor)) { + error("Type mismatch: A value of type `%s' was expected instead of `%s'", + my_governor->get_typename().c_str(), u.expr.type->get_typename().c_str()); + set_valuetype(V_ERROR); + } + } + break; case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: chk_expr_comptype_compat(); @@ -7951,6 +7988,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_COMP_RUNNING: // v1 case OPTYPE_COMP_ALIVE: @@ -9275,6 +9313,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: + case OPTYPE_GET_PORT_REF: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_MATCH: // v1 t2 case OPTYPE_UNDEF_RUNNING: // v1 @@ -10949,6 +10988,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_TMR_RUNNING_ANY: // - case OPTYPE_GETVERDICT: // - case OPTYPE_PROF_RUNNING: // - + case OPTYPE_GET_PORT_REF: // - case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: break; // nothing to do @@ -11825,6 +11865,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return ret_val; } case OPTYPE_PROF_RUNNING: return string("@profiler.running"); + case OPTYPE_GET_PORT_REF: + return string("port.getref()"); default: return string("<unsupported optype>"); } // switch u.expr.v_optype @@ -13419,6 +13461,17 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_PROF_RUNNING: expr->expr = mputstr(expr->expr, "ttcn3_prof.is_running()"); break; + case OPTYPE_GET_PORT_REF: { + string tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, + "%s* %s = dynamic_cast<%s*>(TTCN_Runtime::get_translation_port());\n" + "if (%s == NULL) TTCN_error(\"Internal error: Conversion of port " + "reference to type `%s' failed.\");\n", + u.expr.type->get_genname_value(my_scope).c_str(), tmp_id.c_str(), + u.expr.type->get_genname_value(my_scope).c_str(), tmp_id.c_str(), + u.expr.type->get_typename().c_str()); + expr->expr = mputprintf(expr->expr, "(*%s)", tmp_id.c_str()); + break; } default: FATAL_ERROR("Value::generate_code_expr_expr()"); } @@ -15099,6 +15152,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_TTCN2STRING: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_DECVALUE_UNICHAR: + case OPTYPE_GET_PORT_REF: return false; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 3c5761cc6..46097c121 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -278,6 +278,8 @@ namespace Common { OPTYPE_JSON2CBOR, // v1 OPTYPE_BSON2JSON, // v1 OPTYPE_JSON2BSON, // v1 + + OPTYPE_GET_PORT_REF, // - NUMBER_OF_OPTYPES // must be last }; @@ -343,6 +345,7 @@ namespace Common { TemplateInstance *ti1; Ttcn::Ref_base *r1; /**< timer or component */ LogArguments *logargs; /**< arguments of log2str() */ + Type* type; }; union { Value *v2; @@ -413,7 +416,7 @@ namespace Common { /** Constructor used by V_EXPR "-": RND, TESTCASENAME, COMP_NULL, COMP_MTC, * COMP_SYSTEM, COMP_SELF, COMP_RUNNING_ANY, COMP_RUNNING_ALL, * COMP_ALIVE_ALL, COMP_ALIVE_ANY, TMR_RUNNING_ANY, GETVERDICT, - * PROF_RUNNING */ + * PROF_RUNNING, OPTYPE_GET_PORT_REF */ Value(operationtype_t p_optype); /** Constructor used by V_EXPR "v1" or [v1] */ Value(operationtype_t p_optype, Value *p_v1); diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index acbbab69a..a804f74c6 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -8382,11 +8382,10 @@ namespace Ttcn { if (!type) FATAL_ERROR("FormalPar::get_Type()"); return type; } - + void FormalPar::chk() { if (checked) return; - checked = true; TemplateInstance *default_value = defval.ti; defval.ti = 0; if (type) { @@ -8400,6 +8399,8 @@ namespace Ttcn { case A_PAR_VAL_INOUT: asstype = A_PAR_PORT; break; + case A_PAR_PORT: + break; // should only happen in recursive calls default: error("Port type `%s' cannot be used as %s", t->get_fullname().c_str(), get_assname()); @@ -8428,7 +8429,9 @@ namespace Ttcn { } } } else if (asstype != A_PAR_TIMER) FATAL_ERROR("FormalPar::chk()"); - + + checked = true; + if (default_value) { Error_Context cntxt(default_value, "In default value"); defval.ap = chk_actual_par(default_value, Type::EXPECTED_STATIC_VALUE); @@ -9016,6 +9019,18 @@ namespace Ttcn { } return new ActualPar(ref); } else { + if (ap_template->get_templatetype() == Template::SPECIFIC_VALUE) { + Value* val = ap_template->get_specific_value(); + if (val->get_valuetype() == Common::Value::V_EXPR && + val->get_optype() == Common::Value::OPTYPE_GET_PORT_REF) { + Value *v = ap_template->get_Value(); // steal the value + v->set_my_governor(type); + type->chk_this_value_ref(v); + type->chk_this_value(v, 0, exp_val, INCOMPLETE_NOT_ALLOWED, + OMIT_NOT_ALLOWED, SUB_CHK); + return new ActualPar(v); + } + } actual_par->error("Reference to a port or port parameter was expected " "for a port parameter"); return new ActualPar(); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index dfee3c3cc..6ef9b2598 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -1038,7 +1038,7 @@ namespace Ttcn { : 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), - checked(false), legacy(true), + checked(false), attributes_checked(false), legacy(true), in_msgs(0), out_msgs(0), in_sigs(0), out_sigs(0), testport_type(TP_REGULAR), port_type(PT_REGULAR), provider_refs(), provider_types(), mapper_types(), @@ -1784,6 +1784,10 @@ namespace Ttcn { { if (!w_attrib_path || !checked || !my_type) FATAL_ERROR("PortTypeBody::chk_attributes()"); + if (attributes_checked) { + return; + } + attributes_checked = true; Ttcn::ExtensionAttributes * extarts = parse_extattributes(w_attrib_path); if (extarts != 0) { // NULL means parsing error diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh index 6d937e98c..95a36a730 100644 --- a/compiler2/ttcn3/Ttcnstuff.hh +++ b/compiler2/ttcn3/Ttcnstuff.hh @@ -390,6 +390,7 @@ private: Types *in_list, *out_list, *inout_list; bool in_all, out_all, inout_all; // whether "(in|out|inout) all" was used bool checked; + bool attributes_checked; bool legacy; // Old extension syntax or new standard syntax /* Types and signatures that can be sent and received. * These are initially empty; filled by PortTypeBody::chk_list based on diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l index 603560351..22b41f9c6 100644 --- a/compiler2/ttcn3/compiler.l +++ b/compiler2/ttcn3/compiler.l @@ -535,6 +535,8 @@ xor4b RETURN(Xor4bKeyword); "@profiler" RETURN(TitanSpecificProfilerKeyword); "@update" RETURN(TitanSpecificUpdateKeyword); +"getref" RETURN_DOT(GetRefKeyword); + /* Predefined function identifiers */ bit2hex RETURN(bit2hexKeyword); diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index f396e1040..f122f657c 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -684,6 +684,7 @@ static const string anyname("anytype"); %token FromKeyword %token FunctionKeyword %token GetCallOpKeyword +%token GetRefKeyword %token GetReplyOpKeyword %token GetVerdictKeyword %token GotoKeyword @@ -819,6 +820,7 @@ static const string anyname("anytype"); %token DotCreateKeyword %token DotDoneKeyword %token DotGetCallOpKeyword +%token DotGetRefKeyword %token DotGetReplyOpKeyword %token DotHaltKeyword %token DotKillKeyword @@ -1899,16 +1901,16 @@ optDecodedModifier %left '*' '/' ModKeyword RemKeyword %left UnarySign -%expect 67 +%expect 69 %start GrammarRoot /* -XXX Source of conflicts (66 S/R): +XXX Source of conflicts (69 S/R): -1.) 9 conflicts in one state +1.) 10 conflicts in one state The Expression after 'return' keyword is optional in ReturnStatement. -For 9 tokens the parser cannot decide whether the token is a part of +For 10 tokens the parser cannot decide whether the token is a part of the return expression (shift) or it is the beginning of the next statement (reduce). @@ -1947,7 +1949,7 @@ non-standard language extension. 7.) 27 conflicts in one state In the DecodedContentMatch rule a SingleExpression encased in round brackets is -followed by an in-line template. For 26 tokens (after the ')' ) the parser cannot +followed by an in-line template. For 27 tokens (after the ')' ) the parser cannot decide whether the token is the beginning of the in-line template (shift) or the brackets are only part of the SingleExpression itself and the conflicting token is the next segment in the expression (reduce). @@ -9437,6 +9439,11 @@ OpCall: // 611 $$ = new Value(Value::OPTYPE_CHECKSTATE_ALL, r, $5); $$->set_location(infile, @$); } +| PortKeyword DotGetRefKeyword '(' ')' + { + $$ = new Value(Value::OPTYPE_GET_PORT_REF); + $$->set_location(infile, @$); + } ; PredefinedOps: diff --git a/core/Runtime.cc b/core/Runtime.cc index d059d9696..844ed1308 100644 --- a/core/Runtime.cc +++ b/core/Runtime.cc @@ -141,6 +141,13 @@ void TTCN_Runtime::set_port_state(const INTEGER& state, const CHARSTRING& info, } } +PORT* TTCN_Runtime::get_translation_port() { + if (p == NULL) { + TTCN_error("Operation 'port.getref' was called while not in a port translation procedure."); + } + return p; +} + void TTCN_Runtime::set_translation_mode(boolean enabled, PORT* port) { if (enabled) { translation_count++; diff --git a/core/Runtime.hh b/core/Runtime.hh index 2a90e372c..a665f575d 100644 --- a/core/Runtime.hh +++ b/core/Runtime.hh @@ -135,6 +135,7 @@ public: static void set_port_state(const INTEGER& state, const CHARSTRING& info, boolean by_system); static void set_translation_mode(boolean enabled, PORT* port); + static PORT* get_translation_port(); private: inline static boolean in_controlpart() diff --git a/regression_test/portTranslation/PortTranslation.ttcn b/regression_test/portTranslation/PortTranslation.ttcn index 7cf7c3e39..354dc2d93 100644 --- a/regression_test/portTranslation/PortTranslation.ttcn +++ b/regression_test/portTranslation/PortTranslation.ttcn @@ -208,8 +208,19 @@ module PortTranslation { extension "prototype(fast)"; } - function char_to_hex3(in charstring i, out hexstring j) { + function f_port_ref_test(PT3 p1, inout PT3 p2) + { + if (log2str(p1) != "port p3") { + setverdict(fail, "First port argument is invalid. Expected port p3, got: ", p1); + } + if (log2str(p2) != "port p3") { + setverdict(fail, "First port argument is invalid. Expected port p3, got: ", p1); + } + } + + function char_to_hex3(in charstring i, out hexstring j) port PT3 { j := oct2hex(char2oct(i)); + f_port_ref_test(port.getref(), port.getref()); port.setstate(0); // translated } with { extension "prototype(fast)"; @@ -788,7 +799,8 @@ module PortTranslation { } // This tests the 'discard' option in the 'setstate' operation when receiving - testcase tc_receive_discarded() runs on MyComp system System { + // It also tests the operation 'port.getref()' + testcase tc_receive_discarded_plus_port_ref() runs on MyComp system System { map(self:p3, system:p4); p3.send(123); @@ -810,6 +822,7 @@ module PortTranslation { // an integer (-10) and a charstring ("abc") are received on the provider port, // the translation functions discard the integer and convert the charstring into a hexstring, // so only the hexstring is received on the main port + // (the charstring-to-hexstring translation function also contains tests for operation 'port.getref()') alt { [] p3.receive(hexstring: '616263'H) { setverdict(pass); } [] p3.receive(hexstring: ?) -> value bad { setverdict(fail, "Test #2 failed. Received invalid hexstring: ", bad); } @@ -836,7 +849,7 @@ module PortTranslation { execute(tc_receive_partially_translated()); execute(tc_receive_fragmented()); - execute(tc_receive_discarded()); + execute(tc_receive_discarded_plus_port_ref()); } } diff --git a/xsdconvert/converter.cc b/xsdconvert/converter.cc index 9494ad5bb..ab1b3a8e4 100644 --- a/xsdconvert/converter.cc +++ b/xsdconvert/converter.cc @@ -253,7 +253,7 @@ static void printUsage(const char * argv0) { " -f|J file: the names of XSD files are taken from file instead of the command line\n" " -g: generate TTCN-3 code disallowing element substitution\n" " -h: generate TTCN-3 code allowing type substitution\n" - " -m: generate only the UsefulTtcn3Types and XSD predefined modules" + " -m: generate only the UsefulTtcn3Types and XSD predefined modules\n" " -p: do not generate the UsefulTtcn3Types and XSD predefined modules\n" " -q: quiet mode - disable the issue of status messages\n" " -s: parse and validate only - no TTCN-3 module generation\n" -- GitLab