diff --git a/compiler2/AST.cc b/compiler2/AST.cc index 291f03c0382eb409a00068a51309c2287645abc8..6f4f2ad03b24fdbb9ec305ce4247a00812cf3783 100644 --- a/compiler2/AST.cc +++ b/compiler2/AST.cc @@ -1907,10 +1907,10 @@ namespace Common { return 0; } - bool Assignment::get_lazy_eval() const + param_eval_t Assignment::get_eval_type() const { - FATAL_ERROR("Common::Assignment::get_lazy_eval()"); - return false; + FATAL_ERROR("Common::Assignment::get_eval_type()"); + return NORMAL_EVAL; } Ttcn::FormalParList *Assignment::get_FormalParList() @@ -1958,12 +1958,12 @@ namespace Common { } if (p_prefix) ret_val += p_prefix; ret_val += get_genname(); - // add the cast to real type if its a lazy formal paramter + // add the cast to real type if it's a lazy or fuzzy formal parameter switch (asstype) { case A_PAR_VAL: case A_PAR_VAL_IN: case A_PAR_TEMPL_IN: - if (get_lazy_eval() && p_prefix==NULL) { + if (get_eval_type() != NORMAL_EVAL && p_prefix==NULL) { Type* type = get_Type(); string type_genname = (asstype==A_PAR_TEMPL_IN) ? type->get_genname_template(p_scope) : type->get_genname_value(p_scope); ret_val = string("((") + type_genname + string("&)") + ret_val + string(")"); diff --git a/compiler2/AST.hh b/compiler2/AST.hh index 4a7c5a05841a8cf24d442ecb0add82658f4661cc..4d986ab0ec465488c60ab8b664663aed82340b65 100644 --- a/compiler2/AST.hh +++ b/compiler2/AST.hh @@ -487,6 +487,12 @@ namespace Common { * named assignments are visible. */ virtual Assignment* get_ass_byIndex(size_t p_i) = 0; }; + + enum param_eval_t { + NORMAL_EVAL, + LAZY_EVAL, + FUZZY_EVAL + }; /** * Abstract class to represent different kinds of assignments. @@ -572,7 +578,7 @@ namespace Common { virtual Type *get_Type(); virtual Value *get_Value(); virtual Ttcn::Template *get_Template(); - virtual bool get_lazy_eval() const; + virtual param_eval_t get_eval_type() const; /** @} */ /** Returns the formal parameter list of a TTCN-3 definition */ virtual Ttcn::FormalParList *get_FormalParList(); diff --git a/compiler2/DebuggerStuff.cc b/compiler2/DebuggerStuff.cc index 2fbbd2864c001a5d207ee9603bec691d9787cd19..f7505aea1ed464c7b6848a70d38123edff62f61a 100644 --- a/compiler2/DebuggerStuff.cc +++ b/compiler2/DebuggerStuff.cc @@ -188,16 +188,14 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, current_mod = var_ass->get_my_scope()->get_scope_mod(); } - bool is_lazy_param = false; + param_eval_t eval = NORMAL_EVAL; bool is_constant = false; switch (var_ass->get_asstype()) { case Common::Assignment::A_PAR_VAL: case Common::Assignment::A_PAR_VAL_IN: case Common::Assignment::A_PAR_TEMPL_IN: { - if (var_ass->get_lazy_eval()) { - // lazy parameters have their own printing function - is_lazy_param = true; - } + // lazy and fuzzy parameters have their own printing functions + eval = var_ass->get_eval_type(); Ttcn::FormalPar* fpar = dynamic_cast<Ttcn::FormalPar*>(var_ass); is_constant = fpar == NULL || !fpar->get_used_as_lvalue(); break; } @@ -214,8 +212,19 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, // recreate the TTCN-3 version of the type name and determine the type's // printing and overwriting functions string type_name, print_function, set_function; - print_function = is_lazy_param ? "TTCN3_Debugger::print_lazy_param<" : - "TTCN3_Debugger::print_base_var"; + switch (eval) { + case NORMAL_EVAL: + print_function = "TTCN3_Debugger::print_base_var"; + break; + case LAZY_EVAL: + print_function = "TTCN3_Debugger::print_lazy_param<"; + break; + case FUZZY_EVAL: + print_function = "TTCN3_Debugger::print_fuzzy_param"; + break; + default: + FATAL_ERROR("generate_code_debugger_add_var"); + } set_function = "TTCN3_Debugger::set_base_var"; if (var_ass->get_asstype() == Common::Assignment::A_TIMER || var_ass->get_asstype() == Common::Assignment::A_PAR_TIMER) { @@ -238,14 +247,14 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, var_type->get_typetype() != Type::T_UNRESTRICTEDSTRING) { var_type = var_type->get_type_refd(); } - if (is_lazy_param) { + if (eval == LAZY_EVAL) { print_function += var_type->get_genname_value(current_mod); } if (var_type->get_typetype() == Type::T_PORT && var_ass->get_Dimensions() != NULL) { // port array type_name = var_type->get_dispname() + array_dimensions_to_string(var_ass->get_Dimensions()); - if (!is_lazy_param) { + if (eval == NORMAL_EVAL) { print_function = string("TTCN3_Debugger::print_port_array<") + function_params_for_array_dims(var_ass->get_Dimensions(), var_type->get_genname_value(current_mod), @@ -264,7 +273,7 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, calculate_type_name_and_debug_functions_from_type(t, t, current_mod, type_name, dummy1, dummy2); type_name += dims_str; - if (!is_lazy_param) { + if (eval == NORMAL_EVAL) { switch (var_ass->get_asstype()) { case Common::Assignment::A_MODULEPAR_TEMP: case Common::Assignment::A_TEMPLATE: @@ -295,7 +304,7 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, else { string dummy; calculate_type_name_and_debug_functions_from_type(var_ass->get_Type(), - var_type, current_mod, type_name, is_lazy_param ? dummy : print_function, + var_type, current_mod, type_name, eval != NORMAL_EVAL ? dummy : print_function, set_function); } } @@ -309,7 +318,7 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, case Common::Assignment::A_PAR_TEMPL_INOUT: // add a suffix, if it's a template type_name += " template"; - if (is_lazy_param) { + if (eval == LAZY_EVAL) { print_function += "_template"; } break; @@ -317,7 +326,7 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, break; } - if (is_lazy_param) { + if (eval == LAZY_EVAL) { print_function += ">"; } diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 118a56b38967ccbf92dfe01078bd66060546996a..2f8e128488c5b783a14e1b203d7b760d7708a554 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -2947,7 +2947,7 @@ void Type::chk_Fat() switch (typetype) { case T_FUNCTION: u.fatref.fp_list->chk(Ttcn::Definition::A_FUNCTION); - u.fatref.fp_list->chk_noLazyParams(); + u.fatref.fp_list->chk_noLazyFuzzyParams(); if (u.fatref.is_startable && !u.fatref.fp_list->get_startability()) u.fatref.is_startable = false; if (u.fatref.return_type) { @@ -2962,11 +2962,11 @@ void Type::chk_Fat() break; case T_ALTSTEP: u.fatref.fp_list->chk(Ttcn::Definition::A_ALTSTEP); - u.fatref.fp_list->chk_noLazyParams(); + u.fatref.fp_list->chk_noLazyFuzzyParams(); break; case T_TESTCASE: u.fatref.fp_list->chk(Ttcn::Definition::A_TESTCASE); - u.fatref.fp_list->chk_noLazyParams(); + u.fatref.fp_list->chk_noLazyFuzzyParams(); if (u.fatref.system.ref) { Error_Context cntxt2(u.fatref.runs_on.ref, "In `system' clause"); u.fatref.system.type = u.fatref.system.ref->chk_comptype_ref(); diff --git a/compiler2/Value.cc b/compiler2/Value.cc index f3f1c912ea4ed2506c9e65ec49f575bd7c154d24..614923264e02f58496c5b790c73115de12b1cd4c 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -14428,17 +14428,17 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) } /////////////////////////////////////////////////////////////////////////////// -// class LazyParamData +// class LazyFuzzyParamData - int LazyParamData::depth = 0; - bool LazyParamData::used_as_lvalue = false; - vector<string>* LazyParamData::type_vec = NULL; - vector<string>* LazyParamData::refd_vec = NULL; + int LazyFuzzyParamData::depth = 0; + bool LazyFuzzyParamData::used_as_lvalue = false; + vector<string>* LazyFuzzyParamData::type_vec = NULL; + vector<string>* LazyFuzzyParamData::refd_vec = NULL; - void LazyParamData::init(bool p_used_as_lvalue) { - if (depth<0) FATAL_ERROR("LazyParamData::init()"); + void LazyFuzzyParamData::init(bool p_used_as_lvalue) { + if (depth<0) FATAL_ERROR("LazyFuzzyParamData::init()"); if (depth==0) { - if (type_vec || refd_vec) FATAL_ERROR("LazyParamData::init()"); + if (type_vec || refd_vec) FATAL_ERROR("LazyFuzzyParamData::init()"); used_as_lvalue = p_used_as_lvalue; type_vec = new vector<string>; refd_vec = new vector<string>; @@ -14446,9 +14446,9 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) depth++; } - void LazyParamData::clean() { - if (depth<=0) FATAL_ERROR("LazyParamData::clean()"); - if (!type_vec || !refd_vec) FATAL_ERROR("LazyParamData::clean()"); + void LazyFuzzyParamData::clean() { + if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::clean()"); + if (!type_vec || !refd_vec) FATAL_ERROR("LazyFuzzyParamData::clean()"); if (depth==1) { // type_vec for (size_t i=0; i<type_vec->size(); i++) delete (*type_vec)[i]; @@ -14464,17 +14464,18 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) depth--; } - bool LazyParamData::in_lazy() { - if (depth<0) FATAL_ERROR("LazyParamData::in_lazy()"); + bool LazyFuzzyParamData::in_lazy_or_fuzzy() { + if (depth<0) FATAL_ERROR("LazyFuzzyParamData::in_lazy_or_fuzzy()"); return depth>0; } // returns a temporary id instead of the C++ reference to a definition - // stores in vectors the C++ type of the definiton, the C++ reference to the definition and if it refers to a lazy formal parameter - string LazyParamData::add_ref_genname(Assignment* ass, Scope* scope) { - if (!ass || !scope) FATAL_ERROR("LazyParamData::add_ref_genname()"); - if (!type_vec || !refd_vec) FATAL_ERROR("LazyParamData::add_ref_genname()"); - if (type_vec->size()!=refd_vec->size()) FATAL_ERROR("LazyParamData::add_ref_genname()"); + // stores in vectors the C++ type of the definiton, the C++ reference to the + // definition and whether it refers to a lazy/fuzzy formal parameter + string LazyFuzzyParamData::add_ref_genname(Assignment* ass, Scope* scope) { + if (!ass || !scope) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); + if (!type_vec || !refd_vec) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); + if (type_vec->size()!=refd_vec->size()) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); // store the type of the assignment string* type_str = new string; switch (ass->get_asstype()) { @@ -14489,22 +14490,22 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) default: *type_str = ass->get_Type()->get_genname_value(scope); } - // add the Lazy_Param<> part if the referenced assignment is a FormalPar with lazy_eval == true - bool refd_ass_is_lazy_fpar = false; + // add the Lazy_Fuzzy_Expr<> part if the referenced assignment is a FormalPar lazy or fuzzy + bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: - refd_ass_is_lazy_fpar = ass->get_lazy_eval(); - if (refd_ass_is_lazy_fpar) { - *type_str = string("Lazy_Param<") + *type_str + string(">"); + refd_ass_is_lazy_or_fuzzy_fpar = ass->get_eval_type() != NORMAL_EVAL; + if (ass->get_eval_type() != NORMAL_EVAL) { + *type_str = string("Lazy_Fuzzy_Expr<") + *type_str + string(">"); } break; default: break; } // add the "const" part if the referenced assignment is a constant thing - if (!refd_ass_is_lazy_fpar) { + if (!refd_ass_is_lazy_or_fuzzy_fpar) { switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_OC: @@ -14529,7 +14530,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) type_vec->add(type_str); // store the C++ reference string refd_vec->add(new string(ass->get_genname_from_scope(scope,""))); // the "" parameter makes sure that no casting to type is generated into the string - if (refd_ass_is_lazy_fpar) { + if (refd_ass_is_lazy_or_fuzzy_fpar) { Type* refd_ass_type = ass->get_Type(); string refd_ass_type_genname = (ass->get_asstype()==Assignment::A_PAR_TEMPL_IN) ? refd_ass_type->get_genname_template(scope) : refd_ass_type->get_genname_value(scope); return string("((") + refd_ass_type_genname + string("&)") + get_member_name(refd_vec->size()-1) + string(")"); @@ -14538,15 +14539,15 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) } } - string LazyParamData::get_member_name(size_t idx) { + string LazyFuzzyParamData::get_member_name(size_t idx) { return string("lpm_") + Int2string(idx); } - string LazyParamData::get_constr_param_name(size_t idx) { + string LazyFuzzyParamData::get_constr_param_name(size_t idx) { return string("lpp_") + Int2string(idx); } - void LazyParamData::generate_code_for_value(expression_struct* expr, Value* val, Scope* my_scope) { + void LazyFuzzyParamData::generate_code_for_value(expression_struct* expr, Value* val, Scope* my_scope) { // copied from ActualPar::generate_code(), TODO: remove duplication by refactoring if (use_runtime_2 && TypeConv::needs_conv_refd(val)) { const string& tmp_id = val->get_temporary_id(); @@ -14562,7 +14563,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) } } - void LazyParamData::generate_code_for_template(expression_struct* expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* my_scope) { + void LazyFuzzyParamData::generate_code_for_template(expression_struct* expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* my_scope) { // copied from ActualPar::generate_code(), TODO: remove duplication by refactoring if (use_runtime_2 && TypeConv::needs_conv_refd(temp->get_Template())) { const string& tmp_id = temp->get_Template()->get_temporary_id(); @@ -14580,43 +14581,49 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) } else temp->generate_code(expr, gen_restriction_check); } - void LazyParamData::generate_code(expression_struct *expr, Value* value, Scope* scope) { - if (depth<=0) FATAL_ERROR("LazyParamData::generate_code()"); + void LazyFuzzyParamData::generate_code(expression_struct *expr, Value* value, Scope* scope, boolean lazy) { + if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::generate_code()"); if (depth>1) { // if a function with lazy parameter(s) was called inside a lazy parameter then don't generate code for - // lazy parameter inside a lazy parameter, call the funcion as a normal call - // wrap the calculated parameter value inside a special constructor which calculates the value of it's cache immediately + // lazy parameter inside a lazy parameter, call the function as a normal call + // wrap the calculated parameter value inside a special constructor which calculates the value of its cache immediately expression_struct value_expr; Code::init_expr(&value_expr); generate_code_for_value(&value_expr, value, scope); - // the id of the instance of Lazy_Param which will be used as the actual parameter - const string& lazy_param_id = value->get_temporary_id(); + // the id of the instance of Lazy_Fuzzy_Expr, which will be used as the actual parameter + const string& param_id = value->get_temporary_id(); if (value_expr.preamble) { expr->preamble = mputstr(expr->preamble, value_expr.preamble); } - expr->preamble = mputprintf(expr->preamble, "Lazy_Param<%s> %s(Lazy_Param<%s>::EXPR_EVALED, %s);\n", - value->get_my_governor()->get_genname_value(scope).c_str(), lazy_param_id.c_str(), - value->get_my_governor()->get_genname_value(scope).c_str(), value_expr.expr); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", + value->get_my_governor()->get_genname_value(scope).c_str(), param_id.c_str(), + lazy ? "FALSE" : "TRUE", value->get_my_governor()->get_genname_value(scope).c_str(), value_expr.expr); Code::free_expr(&value_expr); - expr->expr = mputstr(expr->expr, lazy_param_id.c_str()); + expr->expr = mputstr(expr->expr, param_id.c_str()); return; } // only if the formal parameter is *not* used as lvalue if (!used_as_lvalue && value->get_valuetype()==Value::V_REFD && value->get_reference()->get_subrefs()==NULL) { Assignment* refd_ass = value->get_reference()->get_refd_assignment(); if (refd_ass) { - bool refd_ass_is_lazy_fpar = false; + bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (refd_ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: - refd_ass_is_lazy_fpar = refd_ass->get_lazy_eval(); + refd_ass_is_lazy_or_fuzzy_fpar = refd_ass->get_eval_type() != NORMAL_EVAL; break; default: break; } - if (refd_ass_is_lazy_fpar) { - expr->expr = mputprintf(expr->expr, "%s", refd_ass->get_genname_from_scope(scope,"").c_str()); + if (refd_ass_is_lazy_or_fuzzy_fpar) { + string refd_str = refd_ass->get_genname_from_scope(scope, ""); + if ((refd_ass->get_eval_type() == LAZY_EVAL && !lazy) || + (refd_ass->get_eval_type() == FUZZY_EVAL && lazy)) { + expr->preamble = mputprintf(expr->preamble, "%s.change();\n", refd_str.c_str()); + expr->postamble = mputprintf(expr->postamble, "%s.revert();\n", refd_str.c_str()); + } + expr->expr = mputprintf(expr->expr, "%s", refd_str.c_str()); return; } } @@ -14625,49 +14632,55 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expression_struct value_expr; Code::init_expr(&value_expr); generate_code_for_value(&value_expr, value, scope); - // the id of the instance of Lazy_Param which will be used as the actual parameter - string lazy_param_id = value->get_temporary_id(); + // the id of the instance of Lazy_Fuzzy_Expr, which will be used as the actual parameter + string param_id = value->get_temporary_id(); string type_name = value->get_my_governor()->get_genname_value(scope); - generate_code_lazyparam_class(expr, value_expr, lazy_param_id, type_name); + generate_code_param_class(expr, value_expr, param_id, type_name, lazy); } - void LazyParamData::generate_code(expression_struct *expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* scope) { - if (depth<=0) FATAL_ERROR("LazyParamData::generate_code()"); + void LazyFuzzyParamData::generate_code(expression_struct *expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* scope, boolean lazy) { + if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::generate_code()"); if (depth>1) { // if a function with lazy parameter(s) was called inside a lazy parameter then don't generate code for - // lazy parameter inside a lazy parameter, call the funcion as a normal call - // wrap the calculated parameter value inside a special constructor which calculates the value of it's cache immediately + // lazy parameter inside a lazy parameter, call the function as a normal call + // wrap the calculated parameter value inside a special constructor which calculates the value of its cache immediately expression_struct tmpl_expr; Code::init_expr(&tmpl_expr); generate_code_for_template(&tmpl_expr, temp, gen_restriction_check, scope); - // the id of the instance of Lazy_Param which will be used as the actual parameter - const string& lazy_param_id = temp->get_Template()->get_temporary_id(); + // the id of the instance of Lazy_Fuzzy_Expr which will be used as the actual parameter + const string& param_id = temp->get_Template()->get_temporary_id(); if (tmpl_expr.preamble) { expr->preamble = mputstr(expr->preamble, tmpl_expr.preamble); } - expr->preamble = mputprintf(expr->preamble, "Lazy_Param<%s> %s(Lazy_Param<%s>::EXPR_EVALED, %s);\n", - temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), lazy_param_id.c_str(), - temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), tmpl_expr.expr); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", + temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), param_id.c_str(), + lazy ? "FALSE" : "TRUE", temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), tmpl_expr.expr); Code::free_expr(&tmpl_expr); - expr->expr = mputstr(expr->expr, lazy_param_id.c_str()); + expr->expr = mputstr(expr->expr, param_id.c_str()); return; } // only if the formal parameter is *not* used as lvalue if (!used_as_lvalue && temp->get_Template()->get_templatetype()==Template::TEMPLATE_REFD && temp->get_Template()->get_reference()->get_subrefs()==NULL) { Assignment* refd_ass = temp->get_Template()->get_reference()->get_refd_assignment(); if (refd_ass) { - bool refd_ass_is_lazy_fpar = false; + bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (refd_ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: - refd_ass_is_lazy_fpar = refd_ass->get_lazy_eval(); + refd_ass_is_lazy_or_fuzzy_fpar = refd_ass->get_eval_type() != NORMAL_EVAL; break; default: break; } - if (refd_ass_is_lazy_fpar) { - expr->expr = mputprintf(expr->expr, "%s", refd_ass->get_genname_from_scope(scope,"").c_str()); + if (refd_ass_is_lazy_or_fuzzy_fpar) { + string refd_str = refd_ass->get_genname_from_scope(scope, ""); + if ((refd_ass->get_eval_type() == LAZY_EVAL && !lazy) || + (refd_ass->get_eval_type() == FUZZY_EVAL && lazy)) { + expr->preamble = mputprintf(expr->preamble, "%s.change();\n", refd_str.c_str()); + expr->postamble = mputprintf(expr->postamble, "%s.revert();\n", refd_str.c_str()); + } + expr->expr = mputprintf(expr->expr, "%s", refd_str.c_str()); return; } } @@ -14676,33 +14689,32 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expression_struct tmpl_expr; Code::init_expr(&tmpl_expr); generate_code_for_template(&tmpl_expr, temp, gen_restriction_check, scope); - // the id of the instance of Lazy_Param which will be used as the actual parameter - string lazy_param_id = temp->get_Template()->get_temporary_id(); + // the id of the instance of Lazy_Fuzzy_Expr which will be used as the actual parameter + string param_id = temp->get_Template()->get_temporary_id(); string type_name = temp->get_Template()->get_my_governor()->get_genname_template(scope); - generate_code_lazyparam_class(expr, tmpl_expr, lazy_param_id, type_name); + generate_code_param_class(expr, tmpl_expr, param_id, type_name, lazy); } - void LazyParamData::generate_code_lazyparam_class(expression_struct *expr, expression_struct& param_expr, const string& lazy_param_id, const string& type_name) { - expr->preamble = mputprintf(expr->preamble, "class Lazy_Param_%s : public Lazy_Param<%s> {\n", lazy_param_id.c_str(), type_name.c_str()); - if (type_vec->size()>0) { - // private members of the local class will be const references to the objects referenced by the expression - for (size_t i=0; i<type_vec->size(); i++) { - expr->preamble = mputprintf(expr->preamble, "%s& %s;\n", (*type_vec)[i]->c_str(), get_member_name(i).c_str()); - } - expr->preamble = mputstr(expr->preamble, "public:\n"); - expr->preamble = mputprintf(expr->preamble, "Lazy_Param_%s(", lazy_param_id.c_str()); - for (size_t i=0; i<type_vec->size(); i++) { + void LazyFuzzyParamData::generate_code_param_class(expression_struct *expr, expression_struct& param_expr, const string& param_id, const string& type_name, boolean lazy) { + expr->preamble = mputprintf(expr->preamble, + "class Lazy_Fuzzy_Expr_%s : public Lazy_Fuzzy_Expr<%s> {\n", + param_id.c_str(), type_name.c_str()); + // private members of the local class will be const references to the objects referenced by the expression + for (size_t i=0; i<type_vec->size(); i++) { + expr->preamble = mputprintf(expr->preamble, "%s& %s;\n", (*type_vec)[i]->c_str(), get_member_name(i).c_str()); + } + expr->preamble = mputstr(expr->preamble, "public:\n"); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr_%s(", param_id.c_str()); + for (size_t i=0; i<type_vec->size(); i++) { if (i>0) expr->preamble = mputstr(expr->preamble, ", "); expr->preamble = mputprintf(expr->preamble, "%s& %s", (*type_vec)[i]->c_str(), get_constr_param_name(i).c_str()); - } - expr->preamble = mputstr(expr->preamble, "): "); - for (size_t i=0; i<type_vec->size(); i++) { - if (i>0) expr->preamble = mputstr(expr->preamble, ", "); - expr->preamble = mputprintf(expr->preamble, "%s(%s)", get_member_name(i).c_str(), get_constr_param_name(i).c_str()); - } - expr->preamble = mputstr(expr->preamble, " {}\n"); - expr->preamble = mputstr(expr->preamble, "private:\n"); } + expr->preamble = mputprintf(expr->preamble, "): Lazy_Fuzzy_Expr(%s)", lazy ? "FALSE" : "TRUE"); + for (size_t i=0; i<type_vec->size(); i++) { + expr->preamble = mputprintf(expr->preamble, ", %s(%s)", get_member_name(i).c_str(), get_constr_param_name(i).c_str()); + } + expr->preamble = mputstr(expr->preamble, " {}\n"); + expr->preamble = mputstr(expr->preamble, "private:\n"); expr->preamble = mputstr(expr->preamble, "virtual void eval_expr() {\n"); // use the temporary expr structure to fill the body of the eval_expr() function if (param_expr.preamble) { @@ -14716,7 +14728,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expr->preamble = mputstr(expr->preamble, "}\n" "};\n" // end of local class definition ); - expr->preamble = mputprintf(expr->preamble, "Lazy_Param_%s %s", lazy_param_id.c_str(), lazy_param_id.c_str()); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr_%s %s", param_id.c_str(), param_id.c_str()); if (type_vec->size()>0) { expr->preamble = mputc(expr->preamble, '('); // paramteres of the constructor are references to the objects used in the expression @@ -14727,15 +14739,15 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expr->preamble = mputc(expr->preamble, ')'); } expr->preamble = mputstr(expr->preamble, ";\n"); - // the instance of the local class Lazy_Param_tmp_xxx is used as the actual parameter - expr->expr = mputprintf(expr->expr, "%s", lazy_param_id.c_str()); + // the instance of the local class Lazy_Fuzzy_Expr_tmp_xxx is used as the actual parameter + expr->expr = mputprintf(expr->expr, "%s", param_id.c_str()); } - void LazyParamData::generate_code_ap_default_ref(expression_struct *expr, Ttcn::Ref_base* ref, Scope* scope) { + void LazyFuzzyParamData::generate_code_ap_default_ref(expression_struct *expr, Ttcn::Ref_base* ref, Scope* scope, boolean lazy) { expression_struct ref_expr; Code::init_expr(&ref_expr); ref->generate_code(&ref_expr); - const string& lazy_param_id = scope->get_scope_mod_gen()->get_temporary_id(); + const string& param_id = scope->get_scope_mod_gen()->get_temporary_id(); if (ref_expr.preamble) { expr->preamble = mputstr(expr->preamble, ref_expr.preamble); } @@ -14754,29 +14766,31 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) default: type_str = ass->get_Type()->get_genname_value(scope); } - expr->preamble = mputprintf(expr->preamble, "Lazy_Param<%s> %s(Lazy_Param<%s>::EXPR_EVALED, %s);\n", - type_str.c_str(), lazy_param_id.c_str(), type_str.c_str(), ref_expr.expr); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", + type_str.c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", type_str.c_str(), ref_expr.expr); if (ref_expr.postamble) { expr->postamble = mputstr(expr->postamble, ref_expr.postamble); } Code::free_expr(&ref_expr); - expr->expr = mputstr(expr->expr, lazy_param_id.c_str()); + expr->expr = mputstr(expr->expr, param_id.c_str()); } - void LazyParamData::generate_code_ap_default_value(expression_struct *expr, Value* value, Scope* scope) { - const string& lazy_param_id = value->get_temporary_id(); - expr->preamble = mputprintf(expr->preamble, "Lazy_Param<%s> %s(Lazy_Param<%s>::EXPR_EVALED, %s);\n", - value->get_my_governor()->get_genname_value(scope).c_str(), lazy_param_id.c_str(), - value->get_my_governor()->get_genname_value(scope).c_str(), value->get_genname_own(scope).c_str()); - expr->expr = mputstr(expr->expr, lazy_param_id.c_str()); + void LazyFuzzyParamData::generate_code_ap_default_value(expression_struct *expr, Value* value, Scope* scope, boolean lazy) { + const string& param_id = value->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", + value->get_my_governor()->get_genname_value(scope).c_str(), param_id.c_str(), + lazy ? "FALSE" : "TRUE", value->get_my_governor()->get_genname_value(scope).c_str(), + value->get_genname_own(scope).c_str()); + expr->expr = mputstr(expr->expr, param_id.c_str()); } - void LazyParamData::generate_code_ap_default_ti(expression_struct *expr, TemplateInstance* ti, Scope* scope) { - const string& lazy_param_id = ti->get_Template()->get_temporary_id(); - expr->preamble = mputprintf(expr->preamble, "Lazy_Param<%s> %s(Lazy_Param<%s>::EXPR_EVALED, %s);\n", - ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), lazy_param_id.c_str(), - ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), ti->get_Template()->get_genname_own(scope).c_str()); - expr->expr = mputstr(expr->expr, lazy_param_id.c_str()); + void LazyFuzzyParamData::generate_code_ap_default_ti(expression_struct *expr, TemplateInstance* ti, Scope* scope, boolean lazy) { + const string& param_id = ti->get_Template()->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", + ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), param_id.c_str(), + lazy ? "FALSE" : "TRUE", ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), + ti->get_Template()->get_genname_own(scope).c_str()); + expr->expr = mputstr(expr->expr, param_id.c_str()); } } // namespace Common diff --git a/compiler2/Value.hh b/compiler2/Value.hh index ba32dd28e34a2779829313b276e62afe4a99e6f9..e34c93ec7286352f1242ffd001fb1e0371818c8c 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -1027,13 +1027,13 @@ namespace Common { /** @} end of AST_Value group */ - class LazyParamData { - static int depth; // recursive code generation: calling a func. with lazy param inside a lazy param + class LazyFuzzyParamData { + static int depth; // recursive code generation: calling a func. with lazy/fuzzy param inside a lazy/fuzzy param static bool used_as_lvalue; static vector<string>* type_vec; static vector<string>* refd_vec; public: - static bool in_lazy(); + static bool in_lazy_or_fuzzy(); static void init(bool p_used_as_lvalue); static void clean(); static string add_ref_genname(Assignment* ass, Scope* scope); @@ -1041,12 +1041,12 @@ namespace Common { static string get_constr_param_name(size_t idx); static void generate_code_for_value(expression_struct* expr, Value* val, Scope* my_scope); static void generate_code_for_template(expression_struct* expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* my_scope); - static void generate_code(expression_struct *expr, Value* value, Scope* scope); - static void generate_code(expression_struct *expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* scope); - static void generate_code_lazyparam_class(expression_struct *expr, expression_struct& param_expr, const string& lazy_param_id, const string& type_name); - static void generate_code_ap_default_ref(expression_struct *expr, Ttcn::Ref_base* ref, Scope* scope); - static void generate_code_ap_default_value(expression_struct *expr, Value* value, Scope* scope); - static void generate_code_ap_default_ti(expression_struct *expr, TemplateInstance* ti, Scope* scope); + static void generate_code(expression_struct *expr, Value* value, Scope* scope, boolean lazy); + static void generate_code(expression_struct *expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* scope, boolean lazy); + static void generate_code_param_class(expression_struct *expr, expression_struct& param_expr, const string& param_id, const string& type_name, boolean lazy); + static void generate_code_ap_default_ref(expression_struct *expr, Ttcn::Ref_base* ref, Scope* scope, boolean lazy); + static void generate_code_ap_default_value(expression_struct *expr, Value* value, Scope* scope, boolean lazy); + static void generate_code_ap_default_ti(expression_struct *expr, TemplateInstance* ti, Scope* scope, boolean lazy); }; } // namespace Common diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 30393a8fd17ae4b963238cf7b77c3d0b94a7a2b8..e664433f7530cee11fe29a735e2732720b843682 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -692,8 +692,8 @@ namespace Ttcn { expr->expr = mputc(expr->expr, ')'); } else { expr->expr = mputstr(expr->expr, - LazyParamData::in_lazy() ? - LazyParamData::add_ref_genname(ass, my_scope).c_str() : + LazyFuzzyParamData::in_lazy_or_fuzzy() ? + LazyFuzzyParamData::add_ref_genname(ass, my_scope).c_str() : ass->get_genname_from_scope(my_scope).c_str()); } if (subrefs.get_nof_refs() > 0) subrefs.generate_code(expr, ass); @@ -755,8 +755,8 @@ namespace Ttcn { expr->expr = mputc(expr->expr, ')'); } else { expr->expr = mputstr(expr->expr, - LazyParamData::in_lazy() ? - LazyParamData::add_ref_genname(ass, my_scope).c_str() : + LazyFuzzyParamData::in_lazy_or_fuzzy() ? + LazyFuzzyParamData::add_ref_genname(ass, my_scope).c_str() : ass->get_genname_from_scope(my_scope).c_str()); } expr->expr = mputstr(expr->expr, ")"); @@ -996,7 +996,7 @@ namespace Ttcn { if (!Ref_base::has_single_expr()) return false; for (size_t i = 0; i < parlist.get_nof_pars(); i++) if (!parlist.get_par(i)->has_single_expr()) return false; - // if any formal parameter has lazy evaluation + // if any formal parameter has lazy or fuzzy evaluation Common::Assignment *ass = get_refd_assignment(); if (ass) { const FormalParList *fplist = ass->get_FormalParList(); @@ -1004,7 +1004,7 @@ namespace Ttcn { size_t num_formal = fplist->get_nof_fps(); for (size_t i=0; i<num_formal; ++i) { const FormalPar *fp = fplist->get_fp_byIndex(i); - if (fp->get_lazy_eval()) return false; + if (fp->get_eval_type() != NORMAL_EVAL) return false; } } } @@ -6409,7 +6409,7 @@ namespace Ttcn { body = mprintf("if (!strcmp(function_name, \"%s\")) {\n", dispname_str); if (nof_fps > 0) { - body = fp_list->generate_code_object(body, "", ' '); + body = fp_list->generate_code_object(body, "", ' ', true); for (size_t i = 0; i < nof_fps; i++) { body = mputprintf(body, "%s.decode_text(function_arguments);\n", fp_list->get_fp_byIndex(i)->get_reference_name(my_scope).c_str()); @@ -7914,10 +7914,10 @@ namespace Ttcn { // ================================= FormalPar::FormalPar(asstype_t p_asstype, Type *p_type, Identifier* p_name, - TemplateInstance *p_defval, bool p_lazy_eval) + TemplateInstance *p_defval, param_eval_t p_eval) : Definition(p_asstype, p_name), type(p_type), my_parlist(0), used_as_lvalue(false), template_restriction(TR_NONE), - lazy_eval(p_lazy_eval), defval_generated(false), usage_found(false) + eval(p_eval), defval_generated(false), usage_found(false) { switch (p_asstype) { case A_PAR_VAL: @@ -7940,10 +7940,10 @@ namespace Ttcn { FormalPar::FormalPar(asstype_t p_asstype, template_restriction_t p_template_restriction, Type *p_type, - Identifier* p_name, TemplateInstance *p_defval, bool p_lazy_eval) + Identifier* p_name, TemplateInstance *p_defval, param_eval_t p_eval) : Definition(p_asstype, p_name), type(p_type), my_parlist(0), used_as_lvalue(false), template_restriction(p_template_restriction), - lazy_eval(p_lazy_eval), defval_generated(false), usage_found(false) + eval(p_eval), defval_generated(false), usage_found(false) { switch (p_asstype) { case A_PAR_TEMPL_IN: @@ -7962,7 +7962,7 @@ namespace Ttcn { FormalPar::FormalPar(asstype_t p_asstype, Identifier* p_name, TemplateInstance *p_defval) : Definition(p_asstype, p_name), type(0), my_parlist(0), - used_as_lvalue(false), template_restriction(TR_NONE), lazy_eval(false), + used_as_lvalue(false), template_restriction(TR_NONE), eval(NORMAL_EVAL), defval_generated(false), usage_found(false) { if (p_asstype != A_PAR_TIMER) @@ -8667,9 +8667,9 @@ namespace Ttcn { else { // update the genname so that all references in the generated code // will point to the shadow object - if (!lazy_eval) { + if (eval == NORMAL_EVAL) { set_genname(id->get_name() + "_shadow"); - } + } used_as_lvalue = true; } } @@ -8756,8 +8756,8 @@ namespace Ttcn { const char *name_str = display_name ? id->get_name().c_str() : ""; switch (asstype) { case A_PAR_VAL_IN: - if (lazy_eval) { - str = mputprintf(str, "Lazy_Param<%s>& %s", type->get_genname_value(my_scope).c_str(), name_str); + if (eval != NORMAL_EVAL) { + str = mputprintf(str, "Lazy_Fuzzy_Expr<%s>& %s", type->get_genname_value(my_scope).c_str(), name_str); } else { str = mputprintf(str, "const %s& %s", type->get_genname_value(my_scope).c_str(), name_str); } @@ -8769,8 +8769,8 @@ namespace Ttcn { name_str); break; case A_PAR_TEMPL_IN: - if (lazy_eval) { - str = mputprintf(str, "Lazy_Param<%s>& %s", type->get_genname_template(my_scope).c_str(), name_str); + if (eval != NORMAL_EVAL) { + str = mputprintf(str, "Lazy_Fuzzy_Expr<%s>& %s", type->get_genname_template(my_scope).c_str(), name_str); } else { str = mputprintf(str, "const %s& %s", type->get_genname_template(my_scope).c_str(), name_str); } @@ -8792,7 +8792,7 @@ namespace Ttcn { string FormalPar::get_reference_name(Scope* scope) const { string ret_val; - if (lazy_eval) { + if (eval != NORMAL_EVAL) { ret_val += "(("; switch (asstype) { case A_PAR_TEMPL_IN: @@ -8805,19 +8805,24 @@ namespace Ttcn { ret_val += "&)"; } ret_val += get_id().get_name(); - if (lazy_eval) { + if (eval != NORMAL_EVAL) { ret_val += ")"; } return ret_val; } - char *FormalPar::generate_code_object(char *str, const char *p_prefix, char refch) + char *FormalPar::generate_code_object(char *str, const char *p_prefix, char refch, bool gen_init) { const char *name_str = id->get_name().c_str(); switch (asstype) { case A_PAR_VAL_IN: - if (lazy_eval) { - str = mputprintf(str, "Lazy_Param<%s> %s%s;\n", type->get_genname_value(my_scope).c_str(), p_prefix, name_str); + if (eval != NORMAL_EVAL) { + str = mputprintf(str, "Lazy_Fuzzy_Expr<%s> %s%s", + type->get_genname_value(my_scope).c_str(), p_prefix, name_str); + if (gen_init) { + str = mputprintf(str, "(%s)", eval == LAZY_EVAL ? "FALSE" : "TRUE"); + } + str = mputstr(str, ";\n"); } else { str = mputprintf(str, "%s %s%s;\n", type->get_genname_value(my_scope).c_str(), p_prefix, name_str); } @@ -8829,8 +8834,13 @@ namespace Ttcn { type->get_genname_value(my_scope).c_str(), refch, p_prefix, name_str); break; case A_PAR_TEMPL_IN: - if (lazy_eval) { - str = mputprintf(str, "Lazy_Param<%s> %s%s;\n", type->get_genname_template(my_scope).c_str(), p_prefix, name_str); + if (eval != NORMAL_EVAL) { + str = mputprintf(str, "Lazy_Fuzzy_Expr<%s> %s%s", + type->get_genname_template(my_scope).c_str(), p_prefix, name_str); + if (gen_init) { + str = mputprintf(str, "(%s)", eval == LAZY_EVAL ? "FALSE" : "TRUE"); + } + str = mputstr(str, ";\n"); } else { str = mputprintf(str, "%s %s%s;\n", type->get_genname_template(my_scope).c_str(), p_prefix, name_str); } @@ -8853,7 +8863,7 @@ namespace Ttcn { { if ((used_as_lvalue || (use_runtime_2 && usage_found && my_parlist->get_my_def()->get_asstype() == Definition::A_ALTSTEP)) - && !lazy_eval) { + && eval == NORMAL_EVAL) { const string& t_genname = get_genname(); const char *genname_str = t_genname.c_str(); const char *name_str = id->get_name().c_str(); @@ -9108,14 +9118,15 @@ namespace Ttcn { } } - // check that @lazy paramterization not used in cases currently unsupported - void FormalParList::chk_noLazyParams() { + // check that @lazy and @fuzzy paramterization are not used in cases currently unsupported + void FormalParList::chk_noLazyFuzzyParams() { Error_Context cntxt(this, "In formal parameter list"); for (size_t i = 0; i < pars_v.size(); i++) { FormalPar *par = pars_v[i]; - if (par->get_lazy_eval()) { - par->error("Formal parameter `%s' cannot be @lazy, not supported in this case.", - par->get_id().get_dispname().c_str()); + if (par->get_eval_type() != NORMAL_EVAL) { + par->error("Formal parameter `%s' cannot be @%s, not supported in this case.", + par->get_id().get_dispname().c_str(), + par->get_eval_type() == LAZY_EVAL ? "lazy" : "fuzzy"); } } } @@ -9208,8 +9219,8 @@ namespace Ttcn { get_template_restriction())); } // check for @lazy equivalence - if (type_par->get_lazy_eval()!=function_par->get_lazy_eval()) { - function_par->error("Parameter @lazy-ness mismatch"); + if (type_par->get_eval_type()!=function_par->get_eval_type()) { + function_par->error("Parameter evaluation type (normal, @lazy or @fuzzy) mismatch"); } // check for name equivalence const Identifier& type_par_id = type_par->get_id(); @@ -9520,10 +9531,10 @@ namespace Ttcn { return str; } - char *FormalParList::generate_code_object(char *str, const char *p_prefix, char refch) + char *FormalParList::generate_code_object(char *str, const char *p_prefix, char refch, bool gen_init) { for (size_t i = 0; i < pars_v.size(); i++) - str = pars_v[i]->generate_code_object(str, p_prefix, refch); + str = pars_v[i]->generate_code_object(str, p_prefix, refch, gen_init); return str; } @@ -9775,14 +9786,14 @@ namespace Ttcn { void ActualPar::generate_code(expression_struct *expr, bool copy_needed, FormalPar* formal_par) const { - bool lazy_param = formal_par != NULL ? formal_par->get_lazy_eval() : false; + param_eval_t param_eval = formal_par != NULL ? formal_par->get_eval_type() : NORMAL_EVAL; bool used_as_lvalue = formal_par != NULL ? formal_par->get_used_as_lvalue() : false; switch (selection) { case AP_VALUE: - if (lazy_param) { // copy_needed doesn't matter in this case - LazyParamData::init(used_as_lvalue); - LazyParamData::generate_code(expr, val, my_scope); - LazyParamData::clean(); + if (param_eval != NORMAL_EVAL) { // copy_needed doesn't matter in this case + LazyFuzzyParamData::init(used_as_lvalue); + LazyFuzzyParamData::generate_code(expr, val, my_scope, param_eval == LAZY_EVAL); + LazyFuzzyParamData::clean(); if (val->get_valuetype() == Value::V_REFD) { // check if the reference is a parameter, mark it as used if it is Reference* r = dynamic_cast<Reference*>(val->get_reference()); @@ -9791,8 +9802,7 @@ namespace Ttcn { } } } else { - if (copy_needed) expr->expr = mputprintf(expr->expr, "%s(", - val->get_my_governor()->get_genname_value(my_scope).c_str()); + char* expr_expr = NULL; if (use_runtime_2 && TypeConv::needs_conv_refd(val)) { // Generate everything to preamble to be able to tackle the wrapper // constructor call. TODO: Reduce the number of temporaries created. @@ -9803,16 +9813,44 @@ namespace Ttcn { tmp_id_str); expr->preamble = TypeConv::gen_conv_code_refd(expr->preamble, tmp_id_str, val); - expr->expr = mputstr(expr->expr, tmp_id_str); - } else val->generate_code_expr(expr); + expr_expr = mputstr(expr_expr, tmp_id_str); + } else { + expression_struct val_expr; + Code::init_expr(&val_expr); + val->generate_code_expr(&val_expr); + if (val_expr.preamble != NULL) { + expr->preamble = mputstr(expr->preamble, val_expr.preamble); + } + if (val_expr.postamble == NULL) { + expr_expr = mputstr(expr_expr, val_expr.expr); + } + else { + // make sure the postambles of the parameters are executed before the + // function call itself (needed if the value contains function calls + // with lazy or fuzzy parameters) + const string& tmp_id = val->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, "%s %s(%s);\n", + val->get_my_governor()->get_genname_value(my_scope).c_str(), + tmp_id.c_str(), val_expr.expr); + expr->preamble = mputstr(expr->preamble, val_expr.postamble); + expr_expr = mputstr(expr_expr, tmp_id.c_str()); + copy_needed = false; // already copied + } + Code::free_expr(&val_expr); + } + if (copy_needed) expr->expr = mputprintf(expr->expr, "%s(", + val->get_my_governor()->get_genname_value(my_scope).c_str()); + expr->expr = mputstr(expr->expr, expr_expr); + Free(expr_expr); if (copy_needed) expr->expr = mputc(expr->expr, ')'); } break; case AP_TEMPLATE: - if (lazy_param) { // copy_needed doesn't matter in this case - LazyParamData::init(used_as_lvalue); - LazyParamData::generate_code(expr, temp, gen_restriction_check, my_scope); - LazyParamData::clean(); + if (param_eval != NORMAL_EVAL) { // copy_needed doesn't matter in this case + LazyFuzzyParamData::init(used_as_lvalue); + LazyFuzzyParamData::generate_code(expr, temp, gen_restriction_check, my_scope, + param_eval == LAZY_EVAL); + LazyFuzzyParamData::clean(); if (temp->get_DerivedRef() != NULL || temp->get_Template()->get_templatetype() == Template::TEMPLATE_REFD) { // check if the reference is a parameter, mark it as used if it is @@ -9823,9 +9861,7 @@ namespace Ttcn { } } } else { - if (copy_needed) - expr->expr = mputprintf(expr->expr, "%s(", temp->get_Template() - ->get_my_governor()->get_genname_template(my_scope).c_str()); + char* expr_expr = NULL; if (use_runtime_2 && TypeConv::needs_conv_refd(temp->get_Template())) { const string& tmp_id = temp->get_Template()->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); @@ -9838,13 +9874,41 @@ namespace Ttcn { if (gen_restriction_check != TR_NONE) expr->preamble = Template::generate_restriction_check_code( expr->preamble, tmp_id_str, gen_restriction_check); - expr->expr = mputstr(expr->expr, tmp_id_str); - } else temp->generate_code(expr, gen_restriction_check); + expr_expr = mputstr(expr_expr, tmp_id_str); + } else { + expression_struct temp_expr; + Code::init_expr(&temp_expr); + temp->generate_code(&temp_expr, gen_restriction_check); + if (temp_expr.preamble != NULL) { + expr->preamble = mputstr(expr->preamble, temp_expr.preamble); + } + if (temp_expr.postamble == NULL) { + expr_expr = mputstr(expr_expr, temp_expr.expr); + } + else { + // make sure the postambles of the parameters are executed before the + // function call itself (needed if the template contains function calls + // with lazy or fuzzy parameters) + const string& tmp_id = val->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, "%s %s(%s);\n", + temp->get_Template()->get_my_governor()->get_genname_template(my_scope).c_str(), + tmp_id.c_str(), temp_expr.expr); + expr->preamble = mputstr(expr->preamble, temp_expr.postamble); + expr_expr = mputstr(expr_expr, tmp_id.c_str()); + copy_needed = false; // already copied + } + Code::free_expr(&temp_expr); + } + if (copy_needed) + expr->expr = mputprintf(expr->expr, "%s(", temp->get_Template() + ->get_my_governor()->get_genname_template(my_scope).c_str()); + expr->expr = mputstr(expr->expr, expr_expr); + Free(expr_expr); if (copy_needed) expr->expr = mputc(expr->expr, ')'); } break; case AP_REF: { - if (lazy_param) FATAL_ERROR("ActualPar::generate_code()"); // syntax error should have already happened + if (param_eval != NORMAL_EVAL) FATAL_ERROR("ActualPar::generate_code()"); // syntax error should have already happened if (copy_needed) FATAL_ERROR("ActualPar::generate_code()"); bool is_restricted_template = gen_restriction_check != TR_NONE || gen_post_restriction_check != TR_NONE; @@ -9925,22 +9989,25 @@ namespace Ttcn { if (copy_needed) FATAL_ERROR("ActualPar::generate_code()"); switch (act->selection) { case AP_REF: - if (lazy_param) { - LazyParamData::generate_code_ap_default_ref(expr, act->ref, my_scope); + if (param_eval != NORMAL_EVAL) { + LazyFuzzyParamData::generate_code_ap_default_ref(expr, act->ref, my_scope, + param_eval == LAZY_EVAL); } else { act->ref->generate_code(expr); } break; case AP_VALUE: - if (lazy_param) { - LazyParamData::generate_code_ap_default_value(expr, act->val, my_scope); + if (param_eval != NORMAL_EVAL) { + LazyFuzzyParamData::generate_code_ap_default_value(expr, act->val, my_scope, + param_eval == LAZY_EVAL); } else { expr->expr = mputstr(expr->expr, act->val->get_genname_own(my_scope).c_str()); } break; case AP_TEMPLATE: - if (lazy_param) { - LazyParamData::generate_code_ap_default_ti(expr, act->temp, my_scope); + if (param_eval != NORMAL_EVAL) { + LazyFuzzyParamData::generate_code_ap_default_ti(expr, act->temp, my_scope, + param_eval == LAZY_EVAL); } else { expr->expr = mputstr(expr->expr, act->temp->get_Template()->get_genname_own(my_scope).c_str()); } @@ -10241,8 +10308,8 @@ namespace Ttcn { Code::init_expr(&array_expr); // the array object's name contains the reference, followed by // the subrefs before the current array ref - array_expr.expr = mcopystr(LazyParamData::in_lazy() ? - LazyParamData::add_ref_genname(ass, ref->get_my_scope()).c_str() : + array_expr.expr = mcopystr(LazyFuzzyParamData::in_lazy_or_fuzzy() ? + LazyFuzzyParamData::add_ref_genname(ass, ref->get_my_scope()).c_str() : ass->get_genname_from_scope(ref->get_my_scope()).c_str()); if (ref_i > 0) { subrefs->generate_code(&array_expr, ass, ref_i); diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index dd1cda7c3f05063d9d489e90bfe63e9e4acf42f0..00ee997815500b427fa078f73aa781483912eeec 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -1634,8 +1634,8 @@ namespace Ttcn { bool used_as_lvalue; /** restriction on template value */ template_restriction_t template_restriction; - /** normal or lazy evaluation parametrization should be used */ - bool lazy_eval; + /** normal, lazy or fuzzy evaluation parametrization should be used */ + param_eval_t eval; /** Flag that indicates whether the C++ code for the parameter's default * value has been generated or not. */ bool defval_generated; @@ -1649,11 +1649,11 @@ namespace Ttcn { FormalPar& operator=(const FormalPar& p); public: FormalPar(asstype_t p_asstype, Type *p_type, Identifier* p_name, - TemplateInstance *p_defval, bool p_lazy_eval=false); + TemplateInstance *p_defval, param_eval_t p_eval = NORMAL_EVAL); FormalPar(asstype_t p_asstype, template_restriction_t p_template_restriction, Type *p_type, Identifier* p_name, TemplateInstance *p_defval, - bool p_lazy_eval=false); + param_eval_t p_eval = NORMAL_EVAL); FormalPar(asstype_t p_asstype, Identifier* p_name, TemplateInstance *p_defval); ~FormalPar(); @@ -1716,7 +1716,7 @@ namespace Ttcn { * The \a refch parameter is needed when the code for start_ptc_function is * generated, because reference is generated in case of inout parameters. */ char *generate_code_object(char *str, const char *p_prefix, - char refch = '&'); + char refch = '&', bool gen_init = false); /** Generates a C++ statement that instantiates a shadow object for the * parameter when necessary. It is used when the value of an 'in' value or * template parameter is overwritten within the function body. */ @@ -1727,7 +1727,7 @@ namespace Ttcn { virtual void dump_internal(unsigned level) const; template_restriction_t get_template_restriction() { return template_restriction; } - virtual bool get_lazy_eval() const { return lazy_eval; } + virtual param_eval_t get_eval_type() const { return eval; } // code generation: get the C++ string that refers to the formal parameter // adds a casting to data type if wrapped into a lazy param string get_reference_name(Scope* scope) const; @@ -1779,7 +1779,7 @@ namespace Ttcn { /** Checks the parameter list, which belongs to definition of type * \a deftype. */ void chk(Definition::asstype_t deftype); - void chk_noLazyParams(); + void chk_noLazyFuzzyParams(); /** Checks the parameter list for startability: reports error if the owner * function cannot be started on a PTC. Used by functions and function * types. Parameter \a p_what shall contain "Function" or "Function type", @@ -1834,7 +1834,7 @@ namespace Ttcn { * The \a refch parameter is needed when the code for start_ptc_function is * generated, because reference is generated in case of inout parameters. */ char *generate_code_object(char *str, const char *p_prefix, - char refch = '&'); + char refch = '&', bool gen_init = false); /** Generates the C++ shadow objects for all parameters. */ char *generate_shadow_objects(char *str) const; char *generate_code_set_unbound(char *str) const; diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 46cc545358dbad238b6a9b3fabf7374afbcf9b76..e5a379b790cb31d03e38b61ec7a29512fed50ee8 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -215,6 +215,7 @@ static const string anyname("anytype"); template_restriction_t template_restriction; ValueRedirect* value_redirect; SingleValueRedirect* single_value_redirect; + param_eval_t eval; struct { bool is_raw; @@ -897,7 +898,7 @@ static const string anyname("anytype"); *********************************************************************/ %type <bool_val> optAliveKeyword optOptionalKeyword optOverrideKeyword - optErrValueRaw optAllKeyword optLazyOrFuzzyModifier + optErrValueRaw optAllKeyword %type <str> FreeText optLanguageSpec PatternChunk PatternChunkList %type <uchar_val> Group Plane Row Cell %type <id> FieldIdentifier FieldReference GlobalModuleId @@ -1027,6 +1028,7 @@ static const string anyname("anytype"); %type <variableentries> VariableList %type <variableentry> VariableEntry %type <subtypeparses> seqValueOrRange AllowedValues optSubTypeSpec +%type <eval> optLazyOrFuzzyModifier %type <arraydimension_list> optArrayDef %type <fieldorarrayref_list> optExtendedFieldReference @@ -7690,14 +7692,9 @@ Reference: // 490 ValueReference /* A.1.6.5 Parameterization */ optLazyOrFuzzyModifier: - /* empty */ { $$ = false; } -| LazyKeyword { $$ = true; } -| FuzzyKeyword - { - $$ = false; - Location loc(infile, @1); - loc.error("Modifier '@fuzzy' is not currently supported."); - } + /* empty */ { $$ = NORMAL_EVAL; } +| LazyKeyword { $$ = LAZY_EVAL; } +| FuzzyKeyword { $$ = FUZZY_EVAL; } ; FormalValuePar: // 516 diff --git a/core/Basetype.hh b/core/Basetype.hh index 71d2d8213421e66fe86cf50059f04971309e77b3..7b86f6dbf0962f12c241c386142f651aa781ffa1 100644 --- a/core/Basetype.hh +++ b/core/Basetype.hh @@ -29,6 +29,7 @@ #include "RInt.hh" #include "JSON_Tokenizer.hh" #include "Logger.hh" +#include "Error.hh" #ifdef TITAN_RUNTIME_2 #include "Struct_of.hh" #include "XER.hh" @@ -1062,21 +1063,64 @@ extern boolean operator!=(null_type null_value, const Empty_Record_Type& other_v #undef VIRTUAL_IF_RUNTIME_2 #endif +/** Base class for values and templates with fuzzy or lazy evaluation + * + * When inheriting, override the virtual function eval_expr() to evaluate + * the desired expression. Add new members and a new constructor if the + * expression contains references to variables. + * The class is also used by itself (without inheriting) to store the static + * values/templates of fuzzy or lazy parameters (the ones that are known at + * compile-time). */ template <class EXPR_TYPE> -class Lazy_Param { +class Lazy_Fuzzy_Expr { protected: + /** Evaluation type. True for fuzzy evaluation, false for lazy evaluation. */ + boolean fuzzy; + /** Indicates whether a lazy expression has been evaluated. This flag is + * updated in case of fuzzy evaluation, too, in case the evaluation type is + * later changed to lazy. */ boolean expr_evaluated; - EXPR_TYPE expr_cache; + /** The previous value of expr_evaluated is stored here when it is reset. + * (This is only needed if an evaluated lazy expression is changed to fuzzy, + * then to lazy, and isn't evaluated until it is reverted back to the initial + * lazy evaluation. Changing from fuzzy to lazy resets the evaluation flag, + * and the information, that the initial lazy expression was evaluated, would + * otherwise be lost.) */ + boolean old_expr_evaluated; + /** Stores the value of the evaluated expression (in which case it is unbound + * until the first evaluation) or a static value/template, if it is known at + * compile-time. */ + EXPR_TYPE expr_cache; + /** Evaluates the expression. Empty by default. Should be overridden by the + * inheriting class. */ virtual void eval_expr() {} public: - Lazy_Param(): expr_evaluated(FALSE) {} + /** Constructor called by the inheriting class. */ + Lazy_Fuzzy_Expr(boolean p_fuzzy): fuzzy(p_fuzzy), expr_evaluated(FALSE), old_expr_evaluated(FALSE) {} + /** Dummy type used by the static value/template constructor, since the + * inheriting class' constructor may have parameters of any type. */ enum evaluated_state_t { EXPR_EVALED }; - Lazy_Param(evaluated_state_t /*p_es*/, EXPR_TYPE p_cache): expr_evaluated(TRUE), expr_cache(p_cache) {} + /** Constructor for static values and templates. */ + Lazy_Fuzzy_Expr(boolean p_fuzzy, evaluated_state_t /*p_es*/, EXPR_TYPE p_cache) + : fuzzy(p_fuzzy), expr_evaluated(TRUE), old_expr_evaluated(TRUE), expr_cache(p_cache) {} + /** Copy constructor (can't set it to private, since it is currently used by + * the generated default altstep classes). */ + Lazy_Fuzzy_Expr(const Lazy_Fuzzy_Expr&) { + TTCN_error("Internal error: Copying a fuzzy or lazy parameter."); + } + /** Casting operator. This function is called whenever the fuzzy or lazy + * expression is referenced. */ operator EXPR_TYPE&() { - if (!expr_evaluated) { eval_expr(); expr_evaluated=TRUE; } + if (fuzzy || !expr_evaluated) { + eval_expr(); + expr_evaluated = TRUE; + } return expr_cache; } - virtual ~Lazy_Param() {} + /** Virtual destructor. */ + virtual ~Lazy_Fuzzy_Expr() {} + /** Logging function. Used by the TTCN-3 Debugger for printing the values of + * lazy parameters. */ void log() const { if (!expr_evaluated) { TTCN_Logger::log_event_str("<not evaluated>"); @@ -1085,6 +1129,21 @@ public: expr_cache.log(); } } + /** Changes the evaluation type (from lazy to fuzzy or from fuzzy to lazy). */ + void change() { + fuzzy = !fuzzy; + if (!fuzzy) { + old_expr_evaluated = expr_evaluated; + expr_evaluated = FALSE; + } + } + /** Reverts the evaluation type back to its previous state. */ + void revert() { + fuzzy = !fuzzy; + if (fuzzy) { + expr_evaluated = expr_evaluated || old_expr_evaluated; + } + } }; /** Interface/base class for decoded content matching diff --git a/core/Debugger.hh b/core/Debugger.hh index 23f90ca8cbc782ae35ffec329808bd783015f6a2..387f9c72d7bb1d6630ad353fa6abf451ff3dcd51 100644 --- a/core/Debugger.hh +++ b/core/Debugger.hh @@ -510,10 +510,15 @@ public: { const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue; TTCN_Logger::begin_event_log2str(); - ((Lazy_Param<EXPR_TYPE>*)ptr)->log(); + ((Lazy_Fuzzy_Expr<EXPR_TYPE>*)ptr)->log(); return TTCN_Logger::end_event_log2str(); } + static CHARSTRING print_fuzzy_param(const variable_t&) + { + return CHARSTRING("<fuzzy value>"); + } + ////////////////////////////////////////////////////// ////// methods called by other debugger classes ////// ////////////////////////////////////////////////////// diff --git a/regression_test/Makefile b/regression_test/Makefile index d3eb4c2432ed2b0c24fe12add1f0d14e127927bd..9c60c32c6fb888f901d515521856b547f08e71fe 100644 --- a/regression_test/Makefile +++ b/regression_test/Makefile @@ -48,7 +48,7 @@ XML ipv6 implicitOmit testcase_defparam transparent HQ16404 cfgFile \ all_from lazyEval tryCatch text2ttcn json junitlogger ttcn2json profiler templateOmit \ customEncoding makefilegen uidChars checkstate hostid templateIstemplatekind \ selectUnion templateExclusiveRange any_from templatePatternRef indexWithRecofArray \ -connectMapOperTest +connectMapOperTest fuzzy ifdef DYN DIRS += loggerplugin diff --git a/regression_test/fuzzy/FuzzyFunctions.ttcn b/regression_test/fuzzy/FuzzyFunctions.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..f08ab24bd3b9e241503467d9fe7006cf3a94df62 --- /dev/null +++ b/regression_test/fuzzy/FuzzyFunctions.ttcn @@ -0,0 +1,261 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +// This module contains functions and altsteps for testing fuzzy parameters +module FuzzyFunctions { + +import from FuzzyTypes all; + +// Functions with fuzzy parameters +// ------------------------------- +// +// These functions add, multiply or concatenate their fuzzy parameter +// with itself a specified amount of times, and return the result. +// Functions with fuzzy parameters of structured types perform these +// operations on their elements or fields. +// Functions with fuzzy template parameters perform matching on a +// list of values. +// +// Some of the functions are multi-leveled, testing the use of fuzzy +// parameters passed as another function's fuzzy parameter. +// Some of the multi-leveled functions have a lazy parameter instead of +// a fuzzy one, to test the conversions between fuzzy and lazy parameters. + +function f_fuzzy_usage_int(in @fuzzy integer p_fuzzy, in integer p_usages) return integer { + var integer v_sum := 0; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_sum := v_sum + p_fuzzy; + } + return v_sum; +} + +function f_fuzzy_usage_float(in @fuzzy float p_fuzzy, in integer p_usages) return float { + var float v_sum := 0.0; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_sum := v_sum + p_fuzzy; + } + return v_sum; +} + +function f_wrapped_fuzzy_usage_float(in @fuzzy float p_fuzzy, in integer p_outer_usages, in integer p_inner_usages) return float { + var float v_prod := 1.0; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + v_prod := v_prod * f_fuzzy_usage_float(p_fuzzy, p_inner_usages); + } + return v_prod; +} + +function f_fuzzy_usage_cstr(in @fuzzy charstring p_fuzzy, in integer p_usages) return charstring { + var charstring v_res := ""; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_res := v_res & p_fuzzy; + } + return v_res; +} + +function f_lazy_usage_bstr(in @lazy bitstring p_lazy, in integer p_usages) return bitstring { + var bitstring v_res := ''B; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_res := v_res & p_lazy; + } + return v_res; +} + +function f_wrapped_fuzzy_usage_bstr(in @fuzzy bitstring p_fuzzy, in integer p_outer_usages, in integer p_inner_usages) return bitstring { + var bitstring v_res := ''B; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_fuzzy would be treated as lazy) + v_res := v_res & p_fuzzy; + v_res := v_res & f_lazy_usage_bstr(p_fuzzy, p_inner_usages); + } + return v_res; +} + +function f_fuzzy_usage_hstr(in @fuzzy hexstring p_fuzzy, in integer p_usages) return hexstring { + var hexstring v_res := ''H; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_res := v_res & p_fuzzy; + } + return v_res; +} + +function f_wrapped_lazy_usage_hstr(in @lazy hexstring p_lazy, in integer p_outer_usages, in integer p_inner_usages) return hexstring { + var hexstring v_res := ''H; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_lazy would be treated as fuzzy) + v_res := v_res & p_lazy; + v_res := v_res & f_fuzzy_usage_hstr(p_lazy, p_inner_usages); + } + return v_res; +} + +function f_fuzzy_usage_ostr(in @fuzzy octetstring p_fuzzy, in integer p_usages) return octetstring { + var octetstring v_res := ''O; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_res := v_res & p_fuzzy; + } + return v_res; +} + +function f_wrapped_lazy_usage_ostr(in @lazy octetstring p_lazy, in integer p_outer_usages, in integer p_inner_usages) return octetstring { + var octetstring v_res := ''O; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_lazy would be treated as fuzzy) + v_res := v_res & p_lazy; + v_res := v_res & f_fuzzy_usage_ostr(p_lazy, p_inner_usages); + } + return v_res; +} + +function f_double_wrapped_fuzzy_usage_ostr(in @fuzzy octetstring p_fuzzy, in integer p_outer_usages, in integer p_middle_usages, in integer p_inner_usages) return octetstring { + var octetstring v_res := ''O; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_fuzzy would be treated as lazy) + v_res := v_res & p_fuzzy; + v_res := v_res & f_wrapped_lazy_usage_ostr(p_fuzzy, p_middle_usages, p_inner_usages); + } + return v_res; +} + +function f_lazy_usage_ustr(in @lazy universal charstring p_lazy, in integer p_usages) return universal charstring { + var universal charstring v_res := ""; + for (var integer i := 0; i < p_usages; i := i + 1) { + v_res := v_res & p_lazy; + } + return v_res; +} + +function f_wrapped_fuzzy_usage_ustr(in @fuzzy universal charstring p_fuzzy, in integer p_outer_usages, in integer p_inner_usages) return universal charstring { + var universal charstring v_res := ""; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_fuzzy would be treated as lazy) + v_res := v_res & p_fuzzy; + v_res := v_res & f_lazy_usage_ustr(p_fuzzy, p_inner_usages); + } + return v_res; +} + +function f_double_wrapped_lazy_usage_ustr(in @lazy universal charstring p_lazy, in integer p_outer_usages, in integer p_middle_usages, in integer p_inner_usages) return universal charstring { + var universal charstring v_res := ""; + for (var integer i := 0; i < p_outer_usages; i := i + 1) { + // chaining these concatenations does not currently work (p_lazy would be treated as fuzzy) + v_res := v_res & p_lazy; + v_res := v_res & f_wrapped_fuzzy_usage_ustr(p_lazy, p_middle_usages, p_inner_usages); + } + return v_res; +} + +function f_wrapped_fuzzy_usage_rec(in @fuzzy Rec p_fuzzy, in integer p_rec_usages, in integer p_int_usages, in integer p_str_usages) return Rec { + var Rec v_res := { num := 0, str := "" }; + for (var integer i := 0; i < p_rec_usages; i := i + 1) { + v_res.num := v_res.num + f_fuzzy_usage_int(p_fuzzy.num, p_int_usages); + v_res.str := v_res.str & f_fuzzy_usage_cstr(p_fuzzy.str, p_str_usages); + } + return v_res; +} + +function f_fuzzy_usage_int_temp(in template @fuzzy integer pt_fuzzy, in IntList p_values) return integer { + var integer v_nof_matches := 0; + for (var integer i := 0; i < lengthof(p_values); i := i + 1) { + if (match(p_values[i], pt_fuzzy)) { + v_nof_matches := v_nof_matches + 1; + } + } + return v_nof_matches; +} + +function f_wrapped_fuzzy_usage_list_temp(in template @fuzzy IntList pt_fuzzy, in IntList p_values) return integer { + var integer v_nof_matches := 0; + for (var integer i := 0; i < lengthof(pt_fuzzy); i := i + 1) { + v_nof_matches := v_nof_matches + f_fuzzy_usage_int_temp(pt_fuzzy[i], p_values); + } + return v_nof_matches; +} + +// Altstep with fuzzy parameters +altstep as_fuzzy_bool(in @fuzzy boolean p_fuzzy) runs on CT { + var template integer vt_msg := (1..10); + [p_fuzzy] pt.receive(vt_msg) { } + [not p_fuzzy] pt.receive(vt_msg) { } + [p_fuzzy] pt.receive { } + [not p_fuzzy] pt.receive { } +} + +// Functions used as fuzzy parameters +// ---------------------------------- +// +// These functions are used as the expressions of fuzzy parameters. +// Each function returns its value or template parameter, and +// increases a counter, to help test how many times a fuzzy +// parameter's expression was evaluated. + +function f_fuzzy_return_int(in integer p_ret) runs on CT return integer { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_float(in float p_ret) runs on CT return float { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_cstr(in charstring p_ret) runs on CT return charstring { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_bstr(in bitstring p_ret) runs on CT return bitstring { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_hstr(in hexstring p_ret) runs on CT return hexstring { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_ostr(in octetstring p_ret) runs on CT return octetstring { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_ustr(in universal charstring p_ret) runs on CT return universal charstring { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_bool(in boolean p_ret) runs on CT return boolean { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_rec(in Rec p_ret) runs on CT return Rec { + ct_calls := ct_calls + 1; + return p_ret; +} + +function f_fuzzy_return_int_temp(in template integer pt_ret) runs on CT return template integer { + ct_calls := ct_calls + 1; + return pt_ret; +} + +function f_fuzzy_return_list_temp(in template IntList pt_ret) runs on CT return template IntList { + ct_calls := ct_calls + 1; + return pt_ret; +} + +function f_fuzzy_return_uni_temp(in template Uni pt_ret) runs on CT return template Uni { + ct_calls := ct_calls + 1; + return pt_ret; +} + +} // end of module diff --git a/regression_test/fuzzy/FuzzyTestcases.ttcn b/regression_test/fuzzy/FuzzyTestcases.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..944a829aca3531f2bd48e9ad7f52a394e87f4f8e --- /dev/null +++ b/regression_test/fuzzy/FuzzyTestcases.ttcn @@ -0,0 +1,347 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +// This module contains test cases for fuzzy parameters +module FuzzyTestcases { + +import from FuzzyTypes all; +import from FuzzyFunctions all; + +testcase tc_fuzzy_int() runs on CT { + var integer v_usages := 0; + var integer v_exp_res := 0; + var integer v_res := f_fuzzy_usage_int(f_fuzzy_return_int(1), v_usages); + if (ct_calls != v_usages) { + setverdict(fail, "Expected ", v_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_usages := 3; + v_exp_res := 6; + v_res := f_fuzzy_usage_int(f_fuzzy_return_int(2), v_usages); + if (ct_calls != v_usages) { + setverdict(fail, "Expected ", v_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + setverdict(pass); +} + +testcase tc_fuzzy_wrapped_float() runs on CT { + var integer v_outer_usages := 0; + var integer v_inner_usages := 0; + var float v_exp_res := 1.0; + var float v_res := f_wrapped_fuzzy_usage_float(f_fuzzy_return_float(0.6), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_inner_usages) { + setverdict(fail, "Expected ", v_outer_usages * v_inner_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 3; + v_inner_usages := 4; + v_exp_res := 1000.0; + v_res := f_wrapped_fuzzy_usage_float(f_fuzzy_return_float(2.5), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_inner_usages) { + setverdict(fail, "Expected ", v_outer_usages * v_inner_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +// non-standard +testcase tc_fuzzy_in_fuzzy_cstr() runs on CT { + var integer v_outer_usages := 0; + var integer v_inner_usages := 0; + var charstring v_exp_res := ""; + var charstring v_res := f_fuzzy_usage_cstr(f_fuzzy_usage_cstr(f_fuzzy_return_cstr("ab"), v_inner_usages), v_outer_usages); + if (ct_calls != v_outer_usages) { + setverdict(fail, "Expected ", v_outer_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 2; + v_inner_usages := 3; + v_exp_res := "abababababab"; // "ab" x 6 + v_res := f_fuzzy_usage_cstr(f_fuzzy_usage_cstr(f_fuzzy_return_cstr("ab"), v_inner_usages), v_outer_usages); + if (ct_calls != v_outer_usages) { + setverdict(fail, "Expected ", v_outer_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_lazy_wrapped_in_fuzzy_bstr() runs on CT { + var integer v_outer_usages := 0; + var integer v_inner_usages := 0; + var bitstring v_exp_res := ''B; + var bitstring v_res := f_wrapped_fuzzy_usage_bstr(f_fuzzy_return_bstr('10'B), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * 2) { + setverdict(fail, "Expected ", v_outer_usages * 2, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 3; + v_inner_usages := 4; + v_exp_res := '101010101010101010101010101010'B; // '10'B x 15 + v_res := f_wrapped_fuzzy_usage_bstr(f_fuzzy_return_bstr('10'B), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * 2) { + setverdict(fail, "Expected ", v_outer_usages * 2, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_wrapped_in_lazy_hstr() runs on CT { + var integer v_outer_usages := 0; + var integer v_inner_usages := 0; + var hexstring v_exp_res := ''H; + var hexstring v_res := f_wrapped_lazy_usage_hstr(f_fuzzy_return_hstr('12EF'H), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_inner_usages) { + setverdict(fail, "Expected ", v_outer_usages * v_inner_usages, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 3; + v_inner_usages := 2; + v_exp_res := 'AC3AC3AC3AC3AC3AC3AC3AC3AC3'H; // 'AC3'H x 9 + v_res := f_wrapped_lazy_usage_hstr(f_fuzzy_return_hstr('AC3'H), v_outer_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_inner_usages + 1) { + setverdict(fail, "Expected ", v_outer_usages * v_inner_usages + 1, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_wrapped_in_lazy_wrapped_in_fuzzy_ostr() runs on CT { + var integer v_outer_usages := 0; + var integer v_middle_usages := 0; + var integer v_inner_usages := 0; + var octetstring v_exp_res := ''O; + var octetstring v_res := f_double_wrapped_fuzzy_usage_ostr(f_fuzzy_return_ostr('12EF'O), v_outer_usages, v_middle_usages, v_inner_usages); + if (ct_calls != v_outer_usages * (v_middle_usages * v_inner_usages + 1)) { + setverdict(fail, "Expected ", v_outer_usages * (v_middle_usages * v_inner_usages + 1), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 2; + v_middle_usages := 2; + v_inner_usages := 3; + v_exp_res := 'DADADADADADADADADADADADADADADADADADA'O; // 'DE'O x 18 + v_res := f_double_wrapped_fuzzy_usage_ostr(f_fuzzy_return_ostr('DA'O), v_outer_usages, v_middle_usages, v_inner_usages); + if (ct_calls != v_outer_usages * (v_middle_usages * v_inner_usages + 2)) { + setverdict(fail, "Expected ", v_outer_usages * (v_middle_usages * v_inner_usages + 2), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_lazy_wrapped_in_fuzzy_wrapped_in_lazy_ustr() runs on CT { + var integer v_outer_usages := 0; + var integer v_middle_usages := 0; + var integer v_inner_usages := 0; + var universal charstring v_exp_res := ""; + var universal charstring v_res := f_double_wrapped_lazy_usage_ustr(f_fuzzy_return_ustr(char(0, 1, 2, 3)), v_outer_usages, v_middle_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_middle_usages * 2) { + setverdict(fail, "Expected ", v_outer_usages * v_middle_usages * 2, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_outer_usages := 2; + v_middle_usages := 3; + v_inner_usages := 2; + v_exp_res := "áááááááááááááááááááá"; // "á" x 20 + v_res := f_double_wrapped_lazy_usage_ustr(f_fuzzy_return_ustr("á"), v_outer_usages, v_middle_usages, v_inner_usages); + if (ct_calls != v_outer_usages * v_middle_usages * 2 + 1) { + setverdict(fail, "Expected ", v_outer_usages * v_middle_usages * 2 + 1, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_wrapped_rec() runs on CT { + var integer v_rec_usages := 0; + var integer v_int_usages := 0; + var integer v_str_usages := 0; + var Rec v_rec := { num := 5, str := "xy" }; + var Rec v_exp_res := { num := 0, str := "" }; + var Rec v_res := f_wrapped_fuzzy_usage_rec(f_fuzzy_return_rec(v_rec), v_rec_usages, v_int_usages, v_str_usages); + if (ct_calls != v_rec_usages * (v_int_usages + v_str_usages)) { + setverdict(fail, "Expected ", v_rec_usages * (v_int_usages + v_str_usages), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_rec_usages := 2; + v_int_usages := 4; + v_str_usages := 3; + v_exp_res := { num := 40, str := "xyxyxyxyxyxy" }; + v_res := f_wrapped_fuzzy_usage_rec(f_fuzzy_return_rec(v_rec), v_rec_usages, v_int_usages, v_str_usages); + if (ct_calls != v_rec_usages * (v_int_usages + v_str_usages)) { + setverdict(fail, "Expected ", v_rec_usages * (v_int_usages + v_str_usages), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_int_temp() runs on CT { + var template integer vt_int := (0..infinity); + var IntList v_values := { }; + var integer v_exp_res := 0; + var integer v_res := f_fuzzy_usage_int_temp(f_fuzzy_return_int_temp(vt_int), v_values); + if (ct_calls != lengthof(v_values)) { + setverdict(fail, "Expected ", lengthof(v_values), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + v_values := { 1, -6, 199, 0, -3000 }; + v_exp_res := 3; + v_res := f_fuzzy_usage_int_temp(f_fuzzy_return_int_temp(vt_int), v_values); + if (ct_calls != lengthof(v_values)) { + setverdict(fail, "Expected ", lengthof(v_values), " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_wrapped_list_temp() runs on CT { + var template IntList vt_list := { }; + var IntList v_values := { }; + var integer v_exp_res := 0; + var integer v_res := f_wrapped_fuzzy_usage_list_temp(f_fuzzy_return_list_temp(vt_list), v_values); + if (ct_calls != (lengthof(v_values) + 1) * lengthof(vt_list) + 1) { + setverdict(fail, "Expected ", (lengthof(v_values) + 1) * lengthof(vt_list) + 1, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + + ct_calls := 0; + vt_list := { ?, (1, (100..200)), (-infinity..0), -2 }; + v_values := { 1, -6, 199, 0, -3000 }; + v_exp_res := 10; + v_res := f_wrapped_fuzzy_usage_list_temp(f_fuzzy_return_list_temp(vt_list), v_values); + if (ct_calls != (lengthof(v_values) + 1) * lengthof(vt_list) + 1) { + setverdict(fail, "Expected ", (lengthof(v_values) + 1) * lengthof(vt_list) + 1, " calls, got ", ct_calls); + } + if (v_res != v_exp_res) { + setverdict(fail, "Expected result: ", v_exp_res, ", got: ", v_res); + } + setverdict(pass); +} + +testcase tc_fuzzy_altstep_bool() runs on CT { + connect(self:pt, self:pt); + pt.send(3); + timer tmr; + tmr.start(0.5); + alt { + [] tmr.timeout { + setverdict(fail, "First test timed out."); + } + [] as_fuzzy_bool(f_fuzzy_return_bool(false)); + } + if (ct_calls != 2) { + setverdict(fail, "Expected 2 calls, got ", ct_calls); + } + + ct_calls := 0; + pt.send(-6); + tmr.stop; + tmr.start(0.5); + alt { + [] tmr.timeout { + setverdict(fail, "Second test timed out."); + } + [] as_fuzzy_bool(f_fuzzy_return_bool(true)); + } + if (ct_calls != 3) { + setverdict(fail, "Expected 3 calls, got ", ct_calls); + } + setverdict(pass); +} + +// Testcase with fuzzy parameters +testcase tc_fuzzy_testcase_uni(in template @fuzzy Uni pt_fuzzy) runs on CT { + var Uni v_values[4] := { + { i := 10 }, + { os := 'AB12F9'O }, + { i := -991 }, + { ucs := "eeeeee" } + }; + var integer v_nof_matches := 0; + for (var integer i := 0; i < lengthof(v_values); i := i + 1) { + if (match(v_values[i], pt_fuzzy)) { + v_nof_matches := v_nof_matches + 1; + } + } + if (ct_calls != lengthof(v_values)) { + setverdict(fail, "Expected ", lengthof(v_values), " calls, got ", ct_calls); + } + if (v_nof_matches != 2) { + setverdict(fail, "Expected 2 matches, got ", v_nof_matches); + } + setverdict(pass); +} + +control { + execute(tc_fuzzy_int()); + execute(tc_fuzzy_wrapped_float()); + execute(tc_fuzzy_in_fuzzy_cstr()); + execute(tc_lazy_wrapped_in_fuzzy_bstr()); + execute(tc_fuzzy_wrapped_in_lazy_hstr()); + execute(tc_fuzzy_wrapped_in_lazy_wrapped_in_fuzzy_ostr()); + execute(tc_lazy_wrapped_in_fuzzy_wrapped_in_lazy_ustr()); + execute(tc_fuzzy_wrapped_rec()); + execute(tc_fuzzy_int_temp()); + execute(tc_fuzzy_wrapped_list_temp()); + execute(tc_fuzzy_altstep_bool()); + + var template Uni vt_uni := { i := ? }; + execute(tc_fuzzy_testcase_uni(f_fuzzy_return_uni_temp(vt_uni))); +} + +} // end of module diff --git a/regression_test/fuzzy/FuzzyTypes.ttcn b/regression_test/fuzzy/FuzzyTypes.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..7e321e9d36086499a3156bd894f09cfa8b56e189 --- /dev/null +++ b/regression_test/fuzzy/FuzzyTypes.ttcn @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +// This module contains types for testing fuzzy parameters +module FuzzyTypes { + +type port PT message { + inout integer +} +with { + extension "internal"; +} + +type component CT { + var integer ct_calls := 0; + port PT pt; +} + +type record Rec { + integer num, + charstring str +} + +type record of integer IntList; + +type union Uni { + integer i, + octetstring os, + universal charstring ucs +} + +} // end of module diff --git a/regression_test/fuzzy/Makefile b/regression_test/fuzzy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b012c91086200ab11c42372a4e56553cab10ba1d --- /dev/null +++ b/regression_test/fuzzy/Makefile @@ -0,0 +1,63 @@ +############################################################################## +# Copyright (c) 2000-2016 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################## +TOPDIR := ../ +include $(TOPDIR)/Makefile.regression + +MAKE_PROG := $(MAKE) + +TTCN_FILES := FuzzyTypes.ttcn FuzzyFunctions.ttcn FuzzyTestcases.ttcn +CFG := fuzzy.cfg + +FILES := $(TTCN_FILES) $(CFG) + +RUNNABLE := fuzzy$(EXE_SUFFIX) + +COVERAGE_FLAG := +ifeq ($(COVERAGE), yes) + COVERAGE_FLAG += -C +endif + +DIR_SINGLE := dir_single_mode +DIR_PARALLEL := dir_parallel_mode +GENERATED_DIRS := $(DIR_SINGLE) $(DIR_PARALLEL) + +# List of fake targets: +.PHONY: all clean run run_single run_parallel runall + +all: $(GENERATED_DIRS) + +$(DIR_SINGLE): + mkdir $@ + cd $@ && for file in $(FILES); do ln -s ../$$file || exit; done + cd $@ && $(TTCN3_DIR)/bin/ttcn3_makefilegen $(COVERAGE_FLAG) $(SPLIT_FLAG) -s -e $(RUNNABLE) ./* && $(MAKE_PROG) + +$(DIR_PARALLEL): + mkdir $@ + cd $@ && for file in $(FILES); do ln -s ../$$file || exit; done + cd $@ && $(TTCN3_DIR)/bin/ttcn3_makefilegen $(COVERAGE_FLAG) $(SPLIT_FLAG) -e $(RUNNABLE) ./* && $(MAKE_PROG) + +run: $(GENERATED_DIRS) + cd $(DIR_SINGLE) && ./$(RUNNABLE) $(CFG) && grep "Overall verdict: pass" *.log + cd $(DIR_PARALLEL) && $(TTCN3_DIR)/bin/ttcn3_start $(RUNNABLE) $(CFG) && grep "Overall verdict: pass" *.log + +# To run all tests, possibly in parallel +run_single: $(DIR_SINGLE) + cd $(DIR_SINGLE) && ./$(RUNNABLE) $(CFG) && grep "Overall verdict: pass" *.log + +run_parallel: $(DIR_PARALLEL) + cd $(DIR_PARALLEL) && $(TTCN3_DIR)/bin/ttcn3_start $(RUNNABLE) $(CFG) && grep "Overall verdict: pass" *.log + +runall: run_single run_parallel + +clean distclean: + rm -rf $(GENERATED_DIRS) + diff --git a/regression_test/fuzzy/fuzzy.cfg b/regression_test/fuzzy/fuzzy.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9a0f3a9e1d1a86451bdfe5597a6782a9ea0e91e5 --- /dev/null +++ b/regression_test/fuzzy/fuzzy.cfg @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2000-2016 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################### +[MODULE_PARAMETERS] +[LOGGING] +Logfile := "fuzzy_%r.log" +FileMask := LOG_ALL +ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS + +[EXECUTE] +FuzzyTestcases + +