Commit 655401aa authored by Botond Baranyi's avatar Botond Baranyi

Implemented conjunction, implication and dynamic templates, part 1 (issues #548, #549 and #550)

Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent fb44a4c0
......@@ -745,9 +745,10 @@ public:
class Ref_simple : public Reference {
public:
enum reftype_t {
REF_BASIC, // basic reference (not class related to any class scope)
REF_BASIC, // basic reference (not related to a class scope or a dynamic template)
REF_SUPER, // reference to the superclass
REF_THIS // reference to the current class object
REF_THIS, // reference to the current class object
REF_VALUE // reference to the value being matched in a dynamic template
};
protected: // Derived classes need access
/** Points to the referred assignment. Used for caching. */
......
......@@ -4587,7 +4587,7 @@ namespace Common {
case Assignment::A_PAR_TEMPL_IN:
case Assignment::A_PAR_TEMPL_OUT:
case Assignment::A_PAR_TEMPL_INOUT:
u.expr.t1=new Template(tmpref); // TEMPLATE_REFD constructor
u.expr.t1=new Template(Template::TEMPLATE_REFD, tmpref); // TEMPLATE_REFD constructor
u.expr.t1->set_location(*tmpref);
u.expr.t1->set_my_scope(get_my_scope());
u.expr.t1->set_fullname(get_fullname()+".<operand>");
......@@ -6704,7 +6704,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case Assignment::A_PAR_TEMPL_IN:
case Assignment::A_PAR_TEMPL_OUT:
case Assignment::A_PAR_TEMPL_INOUT: {
Template* t = new Template(ref->clone());
Template* t = new Template(Template::TEMPLATE_REFD, ref->clone());
t->set_location(*ref);
t->set_my_scope(get_my_scope());
t->set_fullname(get_fullname()+".<operand>");
......@@ -12043,7 +12043,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case Assignment::A_PAR_TEMPL_IN:
case Assignment::A_PAR_TEMPL_OUT:
case Assignment::A_PAR_TEMPL_INOUT: {
Template* t = new Template(ref->clone());
Template* t = new Template(Template::TEMPLATE_REFD, ref->clone());
t->set_location(*ref);
t->set_my_scope(get_my_scope());
t->set_fullname(get_fullname()+".<operand>");
......
......@@ -746,7 +746,7 @@ namespace Ttcn {
: Ref_base(), reftype(p_reftype), parlist(NULL), params(NULL),
gen_const_prefix(false), expr_cache(NULL)
{
if (reftype != REF_THIS) {
if (reftype != REF_THIS && reftype != REF_VALUE) {
FATAL_ERROR("Ttcn::Reference(): basic or 'super' reference with no ID");
}
}
......
......@@ -396,16 +396,26 @@ namespace Ttcn {
}
}
Template::Template(Reference *p_ref)
Template::Template(templatetype_t tt, Reference *p_ref)
: GovernedSimple(S_TEMPLATE),
templatetype(TEMPLATE_REFD), my_governor(0), length_restriction(0),
templatetype(tt), my_governor(0), length_restriction(0),
is_ifpresent(false), specific_value_checked(false),
has_permutation(false), base_template(0)
{
if(!p_ref) FATAL_ERROR("Template::Template()");
u.ref.ref=p_ref;
u.ref.refd=0;
u.ref.refd_last=0;
switch (tt) {
case TEMPLATE_REFD:
u.ref.ref=p_ref;
u.ref.refd=0;
u.ref.refd_last=0;
break;
case DYNAMIC_MATCH:
delete p_ref;
// todo
break;
default:
FATAL_ERROR("Template::Template()");
}
}
Template::Template(templatetype_t tt, Templates *ts)
......@@ -421,6 +431,7 @@ namespace Ttcn {
case SUPERSET_MATCH:
case SUBSET_MATCH:
case PERMUTATION_MATCH:
case CONJUNCTION_MATCH:
break;
default:
FATAL_ERROR("Template::Template()");
......@@ -529,6 +540,33 @@ namespace Ttcn {
u.dec_match.str_enc = v;
u.dec_match.target = ti;
}
Template::Template(Template* prec, TemplateInstance* imp_t)
: GovernedSimple(S_TEMPLATE),
templatetype(IMPLICATION_MATCH), my_governor(0), length_restriction(0),
is_ifpresent(false), specific_value_checked(false),
has_permutation(false), flattened(true), base_template(0)
{
if (prec == NULL || imp_t == NULL) {
FATAL_ERROR("Template::Template()");
}
delete prec;
delete imp_t;
// todo
}
Template::Template(StatementBlock* block)
: GovernedSimple(S_TEMPLATE),
templatetype(DYNAMIC_MATCH), my_governor(0), length_restriction(0),
is_ifpresent(false), specific_value_checked(false),
has_permutation(false), flattened(true), base_template(0)
{
if (block == NULL) {
FATAL_ERROR("Template::Template()");
}
delete block;
// todo
}
Template::~Template()
{
......@@ -5813,7 +5851,7 @@ compile_time:
// check, remove and delete after checked
if (template_body->get_base_template())
FATAL_ERROR("TemplateInstance::chk_restriction()");
template_body->set_base_template(new Template(derived_reference));
template_body->set_base_template(new Template(Template::TEMPLATE_REFD, derived_reference));
needs_runtime_check = template_body->chk_restriction(
definition_name, template_restriction, usage_loc);
delete template_body->get_base_template();
......
......@@ -69,7 +69,10 @@ namespace Ttcn {
CSTR_PATTERN, /**< character string pattern */
USTR_PATTERN, /**< universal charstring pattern */
DECODE_MATCH, /**< decoded content match */
TEMPLATE_CONCAT /**< concatenation of two templates (runtime2 only) */
TEMPLATE_CONCAT, /**< concatenation of two templates (runtime2 only) */
CONJUNCTION_MATCH, /**< conjunction list match */
IMPLICATION_MATCH, /**< implication match */
DYNAMIC_MATCH /**< dynamic match */
};
/** Status codes for the verification of template body completeness. */
......@@ -186,11 +189,11 @@ namespace Ttcn {
* TEMPLATE_CONCAT (in which case it's recursive). */
Template(Value *v);
/** Constructor for TEMPLATE_REFD */
Template(Reference *p_ref);
/** Constructor for TEMPLATE_REFD and DYNAMIC_MATCH */
Template(templatetype_t tt, Reference *p_ref);
/** Constructor for TEMPLATE_LIST, VALUE_LIST, COMPLEMENTED_LIST,
* SUPERSET_MATCH, SUBSET_MATCH and PERMUTATION_MATCH */
* SUPERSET_MATCH, SUBSET_MATCH, PERMUTATION_MATCH and CONJUNCTION_MATCH */
Template(templatetype_t tt, Templates *ts);
/** Constructor for ALL_FROM */
......@@ -214,6 +217,13 @@ namespace Ttcn {
/** Constructor for DECODE_MATCH */
Template(Value* v, TemplateInstance* ti);
/** Constructor for IMPLICATION_MATCH */
Template(Template* prec, TemplateInstance* imp_t);
/** Constructor for DYNAMIC_MATCH */
Template(StatementBlock* block);
virtual ~Template();
virtual Template* clone() const;
......
......@@ -392,6 +392,7 @@ check RETURN_DOT(CheckOpKeyword);
clear RETURN_DOT(ClearOpKeyword);
complement RETURN(ComplementKeyword);
component RETURN(ComponentKeyword);
conjunct RETURN(ConjunctKeyword);
connect RETURN(ConnectKeyword);
const RETURN(ConstKeyword);
continue RETURN(ContinueKeyword);
......@@ -431,6 +432,7 @@ halt RETURN_DOT(HaltKeyword);
hexstring RETURN(HexStringKeyword);
if RETURN(IfKeyword);
ifpresent RETURN(IfPresentKeyword);
implies RETURN(ImpliesKeyword);
import RETURN(ImportKeyword);
in RETURN(InParKeyword);
inconc RETURN(InconcKeyword);
......@@ -637,6 +639,7 @@ object {
"@final" RETURN(FinalKeyword);
"@abstract" RETURN(AbstractKeyword);
"@default" RETURN(DefaultModifier);
"@dynamic" RETURN(DynamicModifier);
/* special TITAN specific keywords */
......
......@@ -613,6 +613,19 @@ static const string anyname("anytype");
size_t nElements;
StatementBlock** elements;
} catch_block_list;
struct {
Template* precondition;
TemplateInstance* implied_template;
} implication_match;
struct {
bool is_ref;
union {
Ttcn::Reference* ref;
StatementBlock* sb;
};
} dynamic_match;
}
/* Tokens of TTCN-3 */
......@@ -679,6 +692,7 @@ static const string anyname("anytype");
%token ClearOpKeyword
%token ComplementKeyword
%token ComponentKeyword
%token ConjunctKeyword
%token ConnectKeyword
%token ConstKeyword
%token ContinueKeyword
......@@ -720,6 +734,7 @@ static const string anyname("anytype");
%token HexStringKeyword
%token IfKeyword
%token IfPresentKeyword
%token ImpliesKeyword
%token ImportKeyword
%token InconcKeyword
%token InfinityKeyword
......@@ -831,6 +846,7 @@ static const string anyname("anytype");
%token FinalKeyword
%token AbstractKeyword
%token DefaultModifier
%token DynamicModifier
/* TITAN specific keywords */
%token TitanSpecificTryKeyword
......@@ -1076,7 +1092,7 @@ static const string anyname("anytype");
%type <templinsts> optTemplateActualParList
seqTemplateActualPar seqTemplateInstance
%type <templs> ValueOrAttribList seqValueOrAttrib ValueList Complement
ArrayElementSpecList SubsetMatch SupersetMatch PermutationMatch
ArrayElementSpecList SubsetMatch SupersetMatch PermutationMatch ConjunctionMatch
%type <ass> Assignment Step
%type <reference> DerivedRefWithParList TemplateRefWithParList DecValueArg
FunctionInstance AltstepInstance optBaseConstructorCall
......@@ -1181,6 +1197,8 @@ AllOrTypeListWithTo TypeListWithFrom TypeListWithTo
%type <reference_list> PortTypeList
%type <string_vector> AttribSpecEncodings
%type <catch_block_list> optCatchBlockList
%type <implication_match> ImplicationMatch
%type <dynamic_match> DynamicMatch
/*********************************************************************
* Destructors
......@@ -1276,6 +1294,7 @@ CompoundExpression
ConditionalConstruct
ConfigurationOps
ConfigurationStatements
ConjunctionMatch
ConnectStatement
ContinueStatement
ControlStatement
......@@ -1957,6 +1976,22 @@ DecodedContentMatch
}
optDecodedModifier
%destructor {
delete $$.precondition;
delete $$.implied_template;
}
ImplicationMatch
%destructor {
if ($$.is_ref) {
delete $$.ref;
}
else {
delete $$.sb;
}
}
DynamicMatch
/*********************************************************************
* Operator precedences (lowest first)
......@@ -1977,20 +2012,20 @@ optDecodedModifier
%left '*' '/' ModKeyword RemKeyword
%left UnarySign
%expect 76
%expect 92
%start GrammarRoot
/*
XXX Source of conflicts (75 S/R):
XXX Source of conflicts (92 S/R):
1.) 12 conflicts in one state
1.) 13 conflicts in one state
The Expression after 'return' keyword is optional in ReturnStatement.
For 12 tokens the parser cannot decide whether the token is a part of
For 13 tokens the parser cannot decide whether the token is a part of
the return expression (shift) or it is the beginning of the next statement
(reduce).
2.) 13 distinct states, each with one conflict caused by token '['
2.) 14 distinct states, each with one conflict caused by token '['
The local definitions in altsteps can be followed immediately by the guard
expression. When the parser sees the '[' token it cannot decide whether it
belongs to the local definition as array dimension or array subreference
......@@ -2009,6 +2044,7 @@ The situations are the following:
- var t v := this.field <here> [
- var t v := this.function(...) <here> [
- var t v := super.function(...) <here> [
- var t v := value<subrefs> <here> [
3.) 1 conflict
The sequence identifier.objid can be either the beginning of a module name
......@@ -2025,9 +2061,9 @@ non-standard language extension.
6.) 1 Conflict due to pattern concatenation
7.) 30 conflicts in one state
7.) 31 conflicts in one state
In the DecodedContentMatch rule a SingleExpression encased in round brackets is
followed by an in-line template. For 30 tokens (after the ')' ) the parser cannot
followed by an in-line template. For 31 tokens (after the ')' ) the parser cannot
decide whether the token is the beginning of the in-line template (shift) or
the brackets are only part of the SingleExpression itself and the conflicting
token is the next segment in the expression (reduce).
......@@ -2070,6 +2106,38 @@ ex.: 'a(1)' is treated as the objid component with name 'a' and number '1' (shif
instead of the component with the number returned by function 'a' with '1' as
its parameter (reduce).
14.) 13 conflicts in 9 states
These are caused by the implication matching template rule (i.e. ImplicationMatch),
specifically because the rule ends in a TemplateInstance, and the rule itself can be
embedded inside another TemplateInstance.
- The 'length' and 'ifpresent' keywords after an implication match template can
be interpreted as attributes of the implied template (i.e. the 2nd operand)
in the implication match template (shift), or as attributes of the entire implication
match template (reduce). This causes 2 conflicts (one for each keyword) in 4 states
(the first 4 options of the TemplateBody rule).
- Similarly, if there is an 'ifpresent' after a length restriction at the end of an
implication match template, then it can be considered as an attribute of the implied
template (shift), or as an attribute of the entire implication match template (reduce).
- Implication matching templates can be chained (e.g. 't1 implies t2 implies t3').
The first 'implies' keyword in this case can be considered as part of the precondition
of the resulting template (whose precondition is 't1 implies t2' and whose implied
template is 't3'). This is the shift case.
It can also be considered as the resulting template's 'implies' keyword (in which case
the precondition would be 't1' and the implied tempalte would be 't2 implies t3').
This is the reduce case.
Semantically both cases mean the same thing.
- Similarly, if a template instance in the middle of an implication match chain has a
type indicator, a derived reference, or both a type indicator and a derived reference,
then the following 'implies' keyword can be considered as part of the result template's
precondition (shift). In this case the type and/or derived reference only affect the
template operand before the mentioned 'implies' keyword.
Or it can be the 'implies' keyword of the resulting template (reduce), in which case
the type and/or derived reference would affect the entire implication match template that
starts before the mentioned 'implies' keyword and ends after the final 'implies' keyword.
(For example in 't1 implies MyType: t2 implies t3'
'MyType:' could indicate the type of 't2' (shift) or the type of 't2 implies t3' (reduce).
Note that the parser implemented by bison always chooses to shift instead of
reduce in case of conflicts.
*/
......@@ -4206,13 +4274,33 @@ MatchingSymbol: // 116 is a Template*
$$ = new Template(Template::SUPERSET_MATCH, $1);
$$->set_location(infile, @$);
}
| ConjunctionMatch
{
$$ = new Template(Template::CONJUNCTION_MATCH, $1);
$$->set_location(infile, @$);
}
| ImplicationMatch
{
$$ = new Template($1.precondition, $1.implied_template);
$$->set_location(infile, @$);
}
| DynamicMatch
{
if ($1.is_ref) {
$$ = new Template(Template::DYNAMIC_MATCH, $1.ref);
}
else {
$$ = new Template($1.sb);
}
$$->set_location(infile, @$);
}
;
optExtraMatchingAttributes: // [117]
/* empty */
{
$$.is_ifpresent = false;
$$.len_restr = NULL;
$$.is_ifpresent = false;
}
| LengthMatch
{
......@@ -4340,6 +4428,33 @@ DecodedContentMatch:
}
;
ConjunctionMatch:
ConjunctKeyword ValueList { $$ = $2; }
;
ImplicationMatch:
TemplateBody ImpliesKeyword TemplateInstance
{
$$.precondition = $1;
$$.implied_template = $3;
}
/*| TemplateBody ImpliesKeyword '(' TemplateInstance ')' --- handled by TemplateListElem */
;
DynamicMatch:
DynamicModifier StatementBlock
{
$$.is_ref = false;
$$.sb = $2;
}
| DynamicModifier FunctionRef
{
$$.is_ref = true;
$$.ref = new Ttcn::Reference($2.modid, $2.id);
$$.ref->set_location(infile, @2);
}
;
AnyValue: // 140
'?'
;
......@@ -8888,6 +9003,14 @@ Reference: // 490 ValueReference
Free($7.elements);
$$.ref->set_location(infile, @$);
}
| ValueKeyword optExtendedFieldReference
{
$$.is_ref = true;
$$.ref = new Ttcn::Reference(Ref_simple::REF_VALUE);
for (size_t i = 0; i < $2.nElements; i++) $$.ref->add($2.elements[i]);
Free($2.elements);
$$.ref->set_location(infile, @$);
}
;
/* A.1.6.5 Parameterization */
......
......@@ -1237,6 +1237,20 @@ public:
virtual ~Dec_Match_Interface() {}
};
template <typename T>
class Dynamic_Match_Interface {
public:
virtual boolean match(const T&) = 0;
virtual ~Dynamic_Match_Interface() {}
};
template <typename T>
struct dynmatch_struct {
unsigned int ref_count;
Dynamic_Match_Interface<T>* ptr;
};
/** Interface/base class for value redirects in RT2
*
* For every value redirect the compiler generates a new class that inherits
......
......@@ -2077,6 +2077,7 @@ void INTEGER_template::clean_up()
break;
case VALUE_LIST:
case COMPLEMENTED_LIST:
case CONJUNCTION_MATCH:
delete [] value_list.list_value;
break;
case VALUE_RANGE:
......@@ -2085,6 +2086,17 @@ void INTEGER_template::clean_up()
if (value_range.max_is_present && unlikely(!value_range.max_value.native_flag))
BN_free(value_range.max_value.val.openssl);
break;
case IMPLICATION_MATCH:
delete implication_.precondition;
delete implication_.implied_template;
break;
case DYNAMIC_MATCH:
dyn_match->ref_count--;
if (dyn_match->ref_count == 0) {
delete dyn_match->ptr;
delete dyn_match;
}
break;
default:
break;
}
......@@ -2106,6 +2118,7 @@ void INTEGER_template::copy_template(const INTEGER_template& other_value)
break;
case VALUE_LIST:
case COMPLEMENTED_LIST:
case CONJUNCTION_MATCH:
value_list.n_values = other_value.value_list.n_values;
value_list.list_value = new INTEGER_template[value_list.n_values];
for (unsigned int i = 0; i < value_list.n_values; i++)
......@@ -2136,6 +2149,14 @@ void INTEGER_template::copy_template(const INTEGER_template& other_value)
BN_dup(other_value.value_range.max_value.val.openssl);
}
break;
case IMPLICATION_MATCH:
implication_.precondition = new INTEGER_template(*other_value.implication_.precondition);
implication_.implied_template = new INTEGER_template(*other_value.implication_.implied_template);
break;
case DYNAMIC_MATCH:
dyn_match = other_value.dyn_match;
dyn_match->ref_count++;
break;
default:
TTCN_error("Copying an uninitialized/unsupported integer template.");
}
......@@ -2196,6 +2217,21 @@ INTEGER_template::INTEGER_template(const INTEGER_template& other_value)
copy_template(other_value);
}
INTEGER_template::INTEGER_template(INTEGER_template* p_precondition, INTEGER_template* p_implied_template)
: Base_Template(IMPLICATION_MATCH)
{
implication_.precondition = p_precondition;
implication_.implied_template = p_implied_template;
}
INTEGER_template::INTEGER_template(Dynamic_Match_Interface<INTEGER>* p_dyn_match)
: Base_Template(DYNAMIC_MATCH)
{
dyn_match = new dynmatch_struct<INTEGER>;
dyn_match->ptr = p_dyn_match;
dyn_match->ref_count = 1;
}
INTEGER_template::~INTEGER_template()
{
clean_up();
......@@ -2310,6 +2346,17 @@ boolean INTEGER_template::match(int other_value, boolean /* legacy */) const
}
}
return lower_boundary && upper_boundary; }
case CONJUNCTION_MATCH:
for (unsigned int i = 0; i < value_list.n_values; i++) {
if (!value_list.list_value[i].match(other_value)) {
return FALSE;
}
}
return TRUE;
case IMPLICATION_MATCH:
return !implication_.precondition->match(other_value) || implication_.implied_template->match(other_value);
case DYNAMIC_MATCH:
return dyn_match->ptr->match(other_value);
default:
TTCN_error("Matching with an uninitialized/unsupported integer "
"template.");
......@@ -2365,6 +2412,17 @@ boolean INTEGER_template::match(const INTEGER& other_value,
}
}
return lower_boundary && upper_boundary; }
case CONJUNCTION_MATCH:
for (unsigned int i = 0; i < value_list.n_values; i++) {
if (!value_list.list_value[i].match(other_value)) {
return FALSE;
}
}
return TRUE;
case IMPLICATION_MATCH:
return !implication_.precondition->match(other_value) || implication_.implied_template->match(other_value);
case DYNAMIC_MATCH:
return dyn_match->ptr->match(other_value);
default:
TTCN_error("Matching with an uninitialized/unsupported integer "
"template.");
......@@ -2388,6 +2446,7 @@ void INTEGER_template::set_type(template_sel template_type,
switch (template_type) {
case VALUE_LIST:
case COMPLEMENTED_LIST:
case CONJUNCTION_MATCH:
set_selection(template_type);
value_list.n_values = list_length;
value_list.list_value = new INTEGER_template[list_length];
......@@ -2407,7 +2466,8 @@ void INTEGER_template::set_type(template_sel template_type,
INTEGER_template& INTEGER_template::list_item(unsigned int list_index)
{
if (template_selection != VALUE_LIST &&
template_selection != COMPLEMENTED_LIST)
template_selection != COMPLEMENTED_LIST &&
template_selection != CONJUNCTION_MATCH)
TTCN_error("Accessing a list element of a non-list integer template.");
if (list_index >= value_list.n_values)
TTCN_error("Index overflow in an integer value list template.");
......@@ -2524,6 +2584,11 @@ void INTEGER_template::log() const
case COMPLEMENTED_LIST:
TTCN_Logger::log_event_str("complement");
// no break
case CONJUNCTION_MATCH:
if (template_selection == CONJUNCTION_MATCH) {
TTCN_Logger::log_event_str("conjunct");
}
// no break
case VALUE_LIST:
TTCN_Logger::log_char('(');
for (unsigned int i = 0; i < value_list.n_values; i++) {
......@@ -2559,6 +2624,14 @@ void INTEGER_template::log() const
}
TTCN_Logger::log_char(')');
break;
case IMPLICATION_MATCH:
implication_.precondition->log();
TTCN_Logger::log_event_str(" implies ");
implication_.implied_template->log();
break;
case DYNAMIC_MATCH:
TTCN_Logger::log_event_str("@dynamic template");
break;
default:
log_generic();
break;
......@@ -2840,6 +2913,8 @@ boolean INTEGER_template::match_omit(boolean legacy /* = FALSE */) const
case OMIT_VALUE:
case ANY_OR_OMIT:
return TRUE;
case IMPLICATION_MATCH:
return !implication_.precondition->match_omit() || implication_.implied_template->match_omit();
case VALUE_LIST:
case COMPLEMENTED_LIST:
if (legacy) {
......
......@@ -264,6 +264,11 @@ private:
} val;
} min_value, max_value;
} value_range;
struct {
INTEGER_template* precondition;
INTEGER_template* implied_template;
} implication_;
dynmatch_struct<INTEGER>* dyn_match;
};