Commit 1aa91988 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Changed the evaluation of template default parameters in RT2 (bug 529019)



Change-Id: I2e202544f4bff9c28bf2421610962a19fad8aa93
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent e734e2be
......@@ -504,6 +504,8 @@ public:
bool get_code_generated() const { return code_generated; }
/** Sets the flag \a code_generated to true. */
void set_code_generated() { code_generated = true; }
/** Sets the flag \a code_generated to false. */
virtual void reset_code_generated() { code_generated = false; }
/** Adds an error descriptor to the template or value (for negative testing) */
void add_err_descr(Ttcn::Statement* p_update_statement,
......
......@@ -12207,6 +12207,184 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
return false;
}
}
void Value::reset_code_generated()
{
// this is currently only used for default values of template parameters,
// so it only checks the values that can appear in default values
if (!get_code_generated()) {
return;
}
GovernedSimple::reset_code_generated();
switch (valuetype) {
case V_SEQOF:
case V_SETOF:
case V_ARRAY:
if (is_indexed()) {
for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) {
u.val_vs->get_iv_byIndex(i)->get_value()->reset_code_generated();
}
}
else {
for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) {
u.val_vs->get_v_byIndex(i)->reset_code_generated();
}
}
break;
case V_SEQ:
case V_SET:
for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) {
u.val_nvs->get_nv_byIndex(i)->get_value()->reset_code_generated();
}
break;
case V_CHOICE:
case V_OPENTYPE:
u.choice.alt_value->reset_code_generated();
break;
case V_EXPR:
switch (u.expr.v_optype) {
case OPTYPE_UNARYPLUS: // v1
case OPTYPE_UNARYMINUS:
case OPTYPE_NOT:
case OPTYPE_NOT4B:
case OPTYPE_BIT2HEX:
case OPTYPE_BIT2INT:
case OPTYPE_BIT2OCT:
case OPTYPE_BIT2STR:
case OPTYPE_BSON2JSON:
case OPTYPE_CBOR2JSON:
case OPTYPE_CHAR2INT:
case OPTYPE_CHAR2OCT:
case OPTYPE_FLOAT2INT:
case OPTYPE_FLOAT2STR:
case OPTYPE_HEX2BIT:
case OPTYPE_HEX2INT:
case OPTYPE_HEX2OCT:
case OPTYPE_HEX2STR:
case OPTYPE_INT2CHAR:
case OPTYPE_INT2FLOAT:
case OPTYPE_INT2STR:
case OPTYPE_INT2UNICHAR:
case OPTYPE_JSON2BSON:
case OPTYPE_JSON2CBOR:
case OPTYPE_OCT2BIT:
case OPTYPE_OCT2CHAR:
case OPTYPE_OCT2HEX:
case OPTYPE_OCT2INT:
case OPTYPE_OCT2STR:
case OPTYPE_STR2BIT:
case OPTYPE_STR2FLOAT:
case OPTYPE_STR2HEX:
case OPTYPE_STR2INT:
case OPTYPE_STR2OCT:
case OPTYPE_UNICHAR2INT:
case OPTYPE_UNICHAR2CHAR:
case OPTYPE_ENUM2INT:
case OPTYPE_RNDWITHVAL:
case OPTYPE_REMOVE_BOM:
case OPTYPE_GET_STRINGENCODING:
case OPTYPE_DECODE_BASE64:
case OPTYPE_HOSTID:
u.expr.v1->reset_code_generated();
break;
case OPTYPE_ADD: // v1 v2
case OPTYPE_SUBTRACT:
case OPTYPE_MULTIPLY:
case OPTYPE_DIVIDE:
case OPTYPE_MOD:
case OPTYPE_REM:
case OPTYPE_CONCAT:
case OPTYPE_EQ:
case OPTYPE_LT:
case OPTYPE_GT:
case OPTYPE_NE:
case OPTYPE_GE:
case OPTYPE_LE:
case OPTYPE_AND:
case OPTYPE_OR:
case OPTYPE_XOR:
case OPTYPE_AND4B:
case OPTYPE_OR4B:
case OPTYPE_XOR4B:
case OPTYPE_SHL:
case OPTYPE_SHR:
case OPTYPE_ROTL:
case OPTYPE_ROTR:
case OPTYPE_INT2BIT:
case OPTYPE_INT2HEX:
case OPTYPE_INT2OCT:
case OPTYPE_UNICHAR2OCT:
case OPTYPE_OCT2UNICHAR:
case OPTYPE_ENCODE_BASE64:
u.expr.v1->reset_code_generated();
u.expr.v2->reset_code_generated();
break;
case OPTYPE_DECODE: // r1 r2 [v3] [v4]
u.expr.v3->reset_code_generated();
u.expr.v4->reset_code_generated();
break;
case OPTYPE_SUBSTR:
case OPTYPE_ENCODE:
u.expr.ti1->get_Template()->reset_code_generated();
u.expr.v2->reset_code_generated();
u.expr.v3->reset_code_generated();
break;
case OPTYPE_REGEXP:
u.expr.ti1->get_Template()->reset_code_generated();
u.expr.t2->get_Template()->reset_code_generated();
u.expr.v3->reset_code_generated();
break;
case OPTYPE_DECOMP: // v1 v2 v3
u.expr.v1->reset_code_generated();
u.expr.v2->reset_code_generated();
u.expr.v3->reset_code_generated();
break;
case OPTYPE_REPLACE:
u.expr.ti1->get_Template()->reset_code_generated();
u.expr.v2->reset_code_generated();
u.expr.v3->reset_code_generated();
u.expr.ti4->get_Template()->reset_code_generated();
break;
case OPTYPE_VALUEOF: // ti1 [subrefs2]
case OPTYPE_LENGTHOF: // ti1
case OPTYPE_SIZEOF: // ti1
case OPTYPE_ISVALUE:
case OPTYPE_ISBOUND:
case OPTYPE_ISPRESENT:
case OPTYPE_TTCN2STRING:
u.expr.ti1->get_Template()->reset_code_generated();
break;
case OPTYPE_ISTEMPLATEKIND: // ti1 v2
u.expr.ti1->get_Template()->reset_code_generated();
u.expr.v2->reset_code_generated();
break;
case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4]
u.expr.ti1->get_Template()->reset_code_generated();
u.expr.v2->reset_code_generated();
u.expr.v3->reset_code_generated();
u.expr.v4->reset_code_generated();
break;
case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5]
u.expr.v3->reset_code_generated();
u.expr.v4->reset_code_generated();
u.expr.v5->reset_code_generated();
break;
case OPTYPE_MATCH: // v1 t2
u.expr.v1->reset_code_generated();
u.expr.t2->get_Template()->reset_code_generated();
break;
case OPTYPE_LOG2STR:
case OPTYPE_ANY2UNISTR:
// TODO if needed
break;
default:
break;
}
break;
default:
break;
}
}
 
void Value::generate_code_expr(expression_struct *expr)
{
......
......@@ -836,6 +836,11 @@ namespace Common {
public:
/** Returns true if this value is of a string type */
bool is_string_type(Type::expected_value_t exp_val);
/** Sets the flag \a code_generated to false in this value and all of its
* parts. */
virtual void reset_code_generated();
/** Public entry points for code generation. */
/** Generates the equivalent C++ code for the value. It is used
* when the value is part of a complex expression (e.g. as
......
......@@ -793,6 +793,9 @@ namespace Ttcn {
ass->get_RunsOnType(), false);
}
string ass_id2 = ass_id;
if (t.preamble != NULL) {
expr->preamble = mputstr(expr->preamble, t.preamble);
}
if (t.expr != NULL) {
ass_id2 = ass_id2 + "(" + t.expr + ")";
ass_id_str = ass_id2.c_str();
......@@ -9020,6 +9023,33 @@ namespace Ttcn {
}
}
char* FormalPar::generate_code_defval_template(char* str, TemplateInstance* ti,
const string& name,
template_restriction_t temp_res)
{
Template *temp = ti->get_Template();
Ref_base *dref = ti->get_DerivedRef();
if (dref != NULL) {
expression_struct expr;
Code::init_expr(&expr);
expr.expr = mputprintf(expr.expr, "%s = ", name.c_str());
dref->generate_code(&expr);
str = Code::merge_free_expr(str, &expr);
}
if (use_runtime_2 && TypeConv::needs_conv_refd(temp)) {
str = TypeConv::gen_conv_code_refd(str, name.c_str(), temp);
} else {
// force the re-generation of the template's initialization code
// (this is needed in case it contains non-deterministic function calls)
temp->reset_code_generated();
str = temp->generate_code_init(str, name.c_str());
}
if (temp_res != TR_NONE) {
str = Template::generate_restriction_check_code(str, name.c_str(), temp_res);
}
return str;
}
char* FormalPar::generate_code_defval(char* str)
{
if (!defval.ap || defval_generated) return str;
......@@ -9034,25 +9064,11 @@ namespace Ttcn {
}
break; }
case ActualPar::AP_TEMPLATE: {
TemplateInstance *ti = defval.ap->get_TemplateInstance();
Template *temp = ti->get_Template();
Ref_base *dref = ti->get_DerivedRef();
if (dref) {
expression_struct expr;
Code::init_expr(&expr);
expr.expr = mputprintf(expr.expr, "%s = ",
temp->get_lhs_name().c_str());
dref->generate_code(&expr);
str = Code::merge_free_expr(str, &expr);
}
if (use_runtime_2 && TypeConv::needs_conv_refd(temp)) {
str = TypeConv::gen_conv_code_refd(str, temp->get_lhs_name().c_str(), temp);
} else {
str = temp->generate_code_init(str, temp->get_lhs_name().c_str());
}
if (defval.ap->get_gen_restriction_check() != TR_NONE) {
str = Template::generate_restriction_check_code(str,
temp->get_lhs_name().c_str(), defval.ap->get_gen_restriction_check());
if (!use_runtime_2) {
TemplateInstance *ti = defval.ap->get_TemplateInstance();
str = generate_code_defval_template(str,
ti, ti->get_Template()->get_lhs_name(),
defval.ap->get_gen_restriction_check());
}
break; }
case ActualPar::AP_REF:
......@@ -9076,6 +9092,9 @@ namespace Ttcn {
Code::free_cdef(&cdef);
break; }
case ActualPar::AP_TEMPLATE: {
if (use_runtime_2) {
break;
}
TemplateInstance *ti = defval.ap->get_TemplateInstance();
Template *temp = ti->get_Template();
const_def cdef;
......@@ -10118,7 +10137,7 @@ namespace Ttcn {
}
return ref->has_single_expr();
case AP_DEFAULT:
return true;
return !use_runtime_2 || act->selection != AP_TEMPLATE;
default:
FATAL_ERROR("ActualPar::has_single_expr()");
return false;
......@@ -10367,7 +10386,22 @@ namespace Ttcn {
if (param_eval != NORMAL_EVAL) {
LazyFuzzyParamData::generate_code_ap_default_ti(expr, act->temp, my_scope,
param_eval == LAZY_EVAL);
} else {
}
else if (use_runtime_2) {
// for now single expressions are not handled separately, since this
// may change the order of function calls in the default templates
string tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id();
expr->preamble = mputprintf(expr->preamble, "%s %s;\n",
formal_par->get_Type()->get_genname_template(my_scope).c_str(),
tmp_id.c_str());
// use the actual parameter's scope, not the formal parameter's, when
// generating the template's initialization code
act->temp->set_my_scope(my_scope);
expr->preamble = FormalPar::generate_code_defval_template(expr->preamble,
act->temp, tmp_id, act->get_gen_restriction_check());
expr->expr = mputstr(expr->expr, tmp_id.c_str());
}
else {
expr->expr = mputstr(expr->expr, act->temp->get_Template()->get_genname_own(my_scope).c_str());
}
break;
......@@ -10408,6 +10442,9 @@ namespace Ttcn {
}
break;
case AP_TEMPLATE: {
if (use_runtime_2) {
break;
}
str = temp->rearrange_init_code(str, usage_mod);
Template *t = temp->get_Template();
if (t->get_my_scope()->get_scope_mod_gen() == usage_mod) {
......
......@@ -1802,6 +1802,10 @@ namespace Ttcn {
/** Generates the C++ object that represents the default value for the
* parameter (if present). */
virtual void generate_code_defval(output_struct *target, bool clean_up = false);
/** Generates the C++ initialization code of the specified template instance
* (even if it has been generated already). */
static char* generate_code_defval_template(char* str, TemplateInstance* ti,
const string& name, template_restriction_t temp_res);
/** Generates the C++ equivalent of the formal parameter, appends it to
* \a str and returns the resulting string.
* The name of the parameter is not displayed if the parameter is unused
......
......@@ -3395,6 +3395,53 @@ end:
}
return needs_runtime_check;
}
void Template::reset_code_generated()
{
if (!get_code_generated()) {
return;
}
GovernedSimple::reset_code_generated();
switch (templatetype) {
case SPECIFIC_VALUE:
u.specific_value->reset_code_generated();
break;
case TEMPLATE_LIST:
case VALUE_LIST:
case COMPLEMENTED_LIST:
case SUPERSET_MATCH:
case SUBSET_MATCH:
case PERMUTATION_MATCH:
for (size_t i = 0; i < u.templates->get_nof_ts(); ++i) {
u.templates->get_t_byIndex(i)->reset_code_generated();
}
break;
case INDEXED_TEMPLATE_LIST:
for (size_t i = 0; i < u.indexed_templates->get_nof_its(); ++i) {
IndexedTemplate* it = u.indexed_templates->get_it_byIndex(i);
it->get_template()->reset_code_generated();
it->get_index().get_val()->reset_code_generated();
}
break;
case NAMED_TEMPLATE_LIST:
for (size_t i = 0; i < u.named_templates->get_nof_nts(); ++i) {
u.named_templates->get_nt_byIndex(i)->get_template()->reset_code_generated();
}
break;
case ALL_FROM:
u.all_from->reset_code_generated();
break;
case DECODE_MATCH:
u.dec_match.target->get_Template()->reset_code_generated();
break;
case TEMPLATE_CONCAT:
u.concat.op1->reset_code_generated();
u.concat.op2->reset_code_generated();
break;
default: // todo: value range? template refd?
break;
}
}
void Template::generate_code_expr(expression_struct *expr,
template_restriction_t template_restriction)
......
......@@ -412,6 +412,10 @@ namespace Ttcn {
template_restriction_t template_restriction,
const Location* usage_loc);
/** Sets the flag \a code_generated to false in this template and all of its
* parts. */
virtual void reset_code_generated();
/** Public entry points for code generation. */
/** Generates the equivalent C++ code for the template. It is used
* when the template is part of a complex expression
......
......@@ -48,7 +48,8 @@ XML ipv6 implicitOmit testcase_defparam transparent HQ16404 cfgFile \
all_from lazyEval tryCatch text2ttcn json ttcn2json profiler templateOmit \
customEncoding makefilegen uidChars checkstate hostid templateIstemplatekind \
selectUnion templateExclusiveRange any_from templatePatternRef indexWithRecofArray \
connectMapOperTest fuzzy portTranslation ischosen OER functionSubref done
connectMapOperTest fuzzy portTranslation ischosen OER functionSubref done \
nondeterministicDefaultParam
ifdef DYN
DIRS += loggerplugin junitlogger
......
nondeterministicDefaultParam
nondeterministicDefaultParam.exe
Resources*.cc
Resources*.hh
Tests*.cc
Tests*.hh
compile
nondeterministicDefaultParam*.log
/******************************************************************************
* Copyright (c) 2000-2017 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
*
******************************************************************************/
#include "Resources.hh"
namespace Resources {
static INTEGER current_number(0);
INTEGER ef__next__number()
{
return ++current_number;
}
void ef__reset()
{
current_number = 0;
}
}
##############################################################################
# Copyright (c) 2000-2017 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
.SUFFIXES: .ttcn .hh
.PHONY: all clean dep run
TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX)
TTCN3_MODULES = Resources.ttcn
ifdef RT2
TTCN3_MODULES += TestsRT2.ttcn
else
TTCN3_MODULES += TestsRT1.ttcn
endif
USER_SOURCES := ExternalFunctions.cc
GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc)
GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh)
ifdef CODE_SPLIT
GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc))
else ifdef SPLIT_TO_SLICES
POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_))
POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc))
GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES)))
GENERATED_SOURCES += $(GENERATED_SOURCES2)
endif
OBJECTS = $(GENERATED_SOURCES:.cc=.o)
TARGET = nondeterministicDefaultParam$(EXESUFFIX)
all: $(TARGET)
$(TARGET): $(GENERATED_SOURCES) $(USER_SOURCES)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) -L$(OPENSSL_DIR)/lib -lcrypto $($(PLATFORM)_LIBS)
$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile
@if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi
compile: $(TTCN3_MODULES) $(ASN1_MODULES)
$(filter-out -Nold -E, $(TTCN3_COMPILER)) $(COMPILER_FLAGS) $^
touch compile
clean distclean:
-rm -f $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \
$(GENERATED_SOURCES) *.log Makefile.bak compile
dep: $(GENERATED_SOURCES)
makedepend $(CPPFLAGS) $(GENERATED_SOURCES)
run: $(TARGET)
./$^
.NOTPARALLEL:
/******************************************************************************
* Copyright (c) 2000-2017 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 resources for testing non-deterministic external functions as
// default values for parameterized templates.
// Warning: The templates declared in this module depend on each other. Be careful
// when modifying them or adding new ones (only in Runtime 1).
module Resources {
// non-deterministic external function
// (always returns a number greater than the previous number by 1, starting with 1)
external function ef_next_number() return integer;
// resets the counter for ef_next_number
external function ef_reset();
/************* Types *****************/
type record Rec {
boolean b1,
boolean b2,
bitstring bs1,
bitstring bs2
}
type set Set {
set of integer soi1,
set of integer soi2,
record of integer roi
}
type component CT {}
/******************** Templates *********************/
template integer t_int(template integer p := ef_next_number()) := p;
template integer t_int_expr(
template integer p1 := (2 + ef_next_number()) * 5,
template integer p2 := (10 - ef_next_number()) mod 5)
:= valueof(p1) + 1000 * valueof(p2);
template charstring t_str_expr(
template charstring p1 := int2char(ef_next_number() + 64) & "-",
template charstring p2 := int2str(ef_next_number()),
template charstring p3 := log2str(".", ef_next_number()))
:= valueof(p1) & valueof(p2) & valueof(p3);
template Rec t_rec_expr(
template boolean pb1 := not (ef_next_number() < 2),
template boolean pb2 := (ef_next_number() == 6) and true,
template bitstring pbs1 := (int2bit(ef_next_number(), 8) or4b '00010000'B) << 2,
template bitstring pbs2 := (int2bit(ef_next_number() / 2, 4) & '1111'B) @> 3)
:= { pb1, pb2, pbs1, pbs2 };
template integer t_int_value_list(template integer p := ef_next_number()) := (0, p, 25);
template integer t_int_range(template integer p := ef_next_number()) := (0..valueof(p));
template integer t_int_complement_list_and_range(
template integer p1 := ef_next_number(),
template integer p2 := ef_next_number())
:= complement (0, p1, (valueof(p2)..100));
template Set t_set(
template Set.soi1 p1 := subset(0, 1, 2, ef_next_number()),
template Set.soi2 p2 := superset(0, ef_next_number(), 60),
template Set.roi p3 := { 1, permutation(0, ef_next_number(), 100, 200) })
:= { soi1 := p1, soi2 := p2, roi := p3 };