From fc90a90edec4313908c1813854e2c19ec100d535 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 1 Sep 2021 18:28:48 +0200
Subject: [PATCH] Implemented conjunction, implication and dynamic templates,
 part 3 (issues #548, #549 and #550)

Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/Type_chk.cc                         |  16 +-
 compiler2/enum.c                              |  27 +++-
 compiler2/record.c                            |  30 +++-
 compiler2/record_of.c                         |  16 +-
 compiler2/ttcn3/AST_ttcn3.cc                  |  14 +-
 compiler2/ttcn3/Statement.cc                  |   4 +
 compiler2/ttcn3/TtcnTemplate.cc               |  18 ++-
 compiler2/ttcn3/compiler.y                    |   2 +-
 compiler2/union.c                             |  16 +-
 core/Array.hh                                 |  26 +++-
 core/Bitstring.cc                             |  24 ++-
 core/Boolean.cc                               |  24 ++-
 core/Charstring.cc                            |  24 ++-
 core/Component.cc                             |  24 ++-
 core/Default.cc                               |  24 ++-
 core/Float.cc                                 |  24 ++-
 core/Hexstring.cc                             |  24 ++-
 core/Integer.cc                               |  24 ++-
 core/Objid.cc                                 |  24 ++-
 core/Octetstring.cc                           |  24 ++-
 core/Param_Types.cc                           |   6 +
 core/Param_Types.hh                           |  17 +++
 core/Template.cc                              | 108 ++++++++++++--
 core/Universal_charstring.cc                  |  24 ++-
 core/Verdicttype.cc                           |  24 ++-
 core/config_process.l                         |   2 +
 core/config_process.y                         |  25 +++-
 .../ErroneousAttributes_SE.ttcn               |   5 +
 .../template/TempDynamic_SE.ttcn              |  52 +++++++
 .../template/TempImplication_SE.ttcn          |  39 +++++
 .../references/references.cfg                 |   1 +
 .../references/references.ttcn                |   5 +
 regression_test/templateInt/TtemplateInt.ttcn | 141 ++++++++++++++++++
 regression_test/templateInt/config.cfg        |   3 +
 .../templateRecof/TtemplateRecof.ttcn         |  30 ++++
 regression_test/templateRecof/config.cfg      |   2 +
 36 files changed, 814 insertions(+), 79 deletions(-)
 create mode 100644 function_test/Semantic_Analyser/template/TempDynamic_SE.ttcn
 create mode 100644 function_test/Semantic_Analyser/template/TempImplication_SE.ttcn

diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index 4d6720656..06d791a99 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -6642,8 +6642,20 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed,
     matching_fp_list->set_fullname(t->get_fullname() + ".<@dynamic_formalpar>");
     matching_fp_list->set_my_scope(t->get_my_scope());
     t->set_dynamic_fplist(matching_fp_list);
-    t->get_dynamic_sb()->chk();
-    // todo
+    matching_fp->chk();
+    Ttcn::StatementBlock* block = t->get_dynamic_sb();
+    block->chk();
+    switch (block->has_return()) {
+    case Ttcn::StatementBlock::RS_NO:
+      t->error("The dynamic template's statement block does not have a return statement");
+      break;
+    case Ttcn::StatementBlock::RS_MAYBE:
+      t->error("Control might leave the dynamic template's statement block without reaching "
+        "a return statement");
+      break;
+    default:
+      break;
+    }
     break; }
   default:
     self_ref = chk_this_template(t, incomplete_allowed, allow_omit, allow_any_or_omit,
diff --git a/compiler2/enum.c b/compiler2/enum.c
index fd3a8d8ce..0390e9731 100644
--- a/compiler2/enum.c
+++ b/compiler2/enum.c
@@ -1593,10 +1593,12 @@ void defEnumTemplate(const enum_def *edef, output_struct *output)
     "    *this = ANY_OR_OMIT;\n"
     "    break;\n"
     "  case Module_Param::MP_List_Template:\n"
-    "  case Module_Param::MP_ComplementList_Template: {\n"
+    "  case Module_Param::MP_ComplementList_Template:\n"
+    "  case Module_Param::MP_ConjunctList_Template: {\n"
     "    %s_template new_temp;\n"
     "    new_temp.set_type(m_p->get_type()==Module_Param::MP_List_Template ? "
-    "VALUE_LIST : COMPLEMENTED_LIST, m_p->get_size());\n"
+    "VALUE_LIST : (m_p->get_type() == Module_Param::MP_ConjunctList_Template ? "
+    "CONJUNCTION_MATCH : COMPLEMENTED_LIST), m_p->get_size());\n"
     "    for (size_t p_i=0; p_i<m_p->get_size(); p_i++) {\n"
     "      new_temp.list_item(p_i).set_param(*m_p->get_elem(p_i));\n"
     "    }\n"
@@ -1609,11 +1611,19 @@ void defEnumTemplate(const enum_def *edef, output_struct *output)
     "    }\n"
     "    *this = enum_val;\n"
     "  } break;\n"
+    "  case Module_Param::MP_Implication_Template: {\n"
+    "    %s_template* precondition = new %s_template;\n"
+    "    precondition->set_param(*m_p->get_elem(0));\n"
+    "    %s_template* implied_template = new %s_template;\n"
+    "    implied_template->set_param(*m_p->get_elem(1));\n"
+    "    *this = %s_template(precondition, implied_template);\n"
+    "  } break;\n"
     "  default:\n"
     "    param.type_error(\"enumerated template\", \"%s\");\n"
     "  }\n"
     "  is_ifpresent = param.get_ifpresent()%s;\n"
-    "}\n\n", name, enum_type, name, name, dispname, dispname,
+    "}\n\n", name, enum_type, name, name, dispname,
+    name, name, name, name, name, dispname,
     use_runtime_2 ? " || m_p->get_ifpresent()" : "");
 
   /* get_param(), RT2 only */
@@ -1641,10 +1651,14 @@ void defEnumTemplate(const enum_def *edef, output_struct *output)
       "    m_p = new Module_Param_Enumerated(mcopystr(%s::enum_to_str(single_value)));\n"
       "    break;\n"
       "  case VALUE_LIST:\n"
-      "  case COMPLEMENTED_LIST: {\n"
+      "  case COMPLEMENTED_LIST:\n"
+      "  case CONJUNCTION_MATCH: {\n"
       "    if (template_selection == VALUE_LIST) {\n"
       "      m_p = new Module_Param_List_Template();\n"
       "    }\n"
+      "    else if (template_selection == CONJUNCTION_MATCH) {\n"
+      "      m_p = new Module_Param_ConjunctList_Template();\n"
+      "    }\n"
       "    else {\n"
       "      m_p = new Module_Param_ComplementList_Template();\n"
       "    }\n"
@@ -1652,6 +1666,11 @@ void defEnumTemplate(const enum_def *edef, output_struct *output)
       "      m_p->add_elem(value_list.list_value[i_i].get_param(param_name));\n"
       "    }\n"
       "    break; }\n"
+      "  case IMPLICATION_MATCH:\n"
+      "    m_p = new Module_Param_Implication_Template();\n"
+      "    m_p->add_elem(implication_.precondition->get_param(param_name));\n"
+      "    m_p->add_elem(implication_.implied_template->get_param(param_name));\n"
+      "    break;\n"
       "  default:\n"
       "    break;\n"
       "  }\n"
diff --git a/compiler2/record.c b/compiler2/record.c
index b1ed52183..956522295 100644
--- a/compiler2/record.c
+++ b/compiler2/record.c
@@ -6547,10 +6547,12 @@ void defRecordTemplate1(const struct_def *sdef, output_struct *output)
     "    *this = ANY_OR_OMIT;\n"
     "    break;\n"
     "  case Module_Param::MP_List_Template:\n"
-    "  case Module_Param::MP_ComplementList_Template: {\n"
+    "  case Module_Param::MP_ComplementList_Template:\n"
+    "  case Module_Param::MP_ConjunctList_Template: {\n"
     "    %s_template new_temp;\n"
     "    new_temp.set_type(param.get_type()==Module_Param::MP_List_Template ? "
-    "VALUE_LIST : COMPLEMENTED_LIST, param.get_size());\n"
+    "VALUE_LIST : (param.get_type() == Module_Param::MP_ConjunctList_Template ? "
+    "CONJUNCTION_MATCH : COMPLEMENTED_LIST), param.get_size());\n"
     "    for (size_t p_i=0; p_i<param.get_size(); p_i++) {\n"
     "      new_temp.list_item(p_i).set_param(*param.get_elem(p_i));\n"
     "    }\n"
@@ -6591,11 +6593,18 @@ void defRecordTemplate1(const struct_def *sdef, output_struct *output)
     "      break;\n"
     "    }\n"
     "  } break;\n"
+    "  case Module_Param::MP_Implication_Template: {\n"
+    "    %s_template* precondition = new %s_template;\n"
+    "    precondition->set_param(*param.get_elem(0));\n"
+    "    %s_template* implied_template = new %s_template;\n"
+    "    implied_template->set_param(*param.get_elem(1));\n"
+    "    *this = %s_template(precondition, implied_template);\n"
+    "  } break;\n"
     "  default:\n"
     "    param.type_error(\"%s template\", \"%s\");\n"
     "  }\n"
     "  is_ifpresent = param.get_ifpresent();\n"
-    "}\n\n", dispname, kind_str, dispname);
+    "}\n\n", dispname, name, name, name, name, name, kind_str, dispname);
 
     /* check template restriction */
     def = mputstr(def, "void check_restriction(template_res t_res, "
@@ -7539,10 +7548,12 @@ static void defEmptyRecordTemplate(const char *name, const char *dispname,
     "    *this = ANY_OR_OMIT;\n"
     "    break;\n"
     "  case Module_Param::MP_List_Template:\n"
-    "  case Module_Param::MP_ComplementList_Template: {\n"
+    "  case Module_Param::MP_ComplementList_Template:\n"
+    "  case Module_Param::MP_ConjunctList_Template: {\n"
     "    %s_template temp;\n"
     "    temp.set_type(param.get_type()==Module_Param::MP_List_Template ? "
-    "VALUE_LIST : COMPLEMENTED_LIST, param.get_size());\n"
+    "VALUE_LIST : (param.get_type() == Module_Param::MP_ConjunctList_Template ? "
+    "CONJUNCTION_MATCH : COMPLEMENTED_LIST), param.get_size());\n"
     "    for (size_t p_i=0; p_i<param.get_size(); p_i++) {\n"
     "      temp.list_item(p_i).set_param(*param.get_elem(p_i));\n"
     "    }\n"
@@ -7552,11 +7563,18 @@ static void defEmptyRecordTemplate(const char *name, const char *dispname,
     "    if (param.get_size()>0) param.type_error(\"empty record/set template\", \"%s\");\n"
     "    *this = NULL_VALUE;\n"
     "    break;\n"
+    "  case Module_Param::MP_Implication_Template: {\n"
+    "    %s_template* precondition = new %s_template;\n"
+    "    precondition->set_param(*param.get_elem(0));\n"
+    "    %s_template* implied_template = new %s_template;\n"
+    "    implied_template->set_param(*param.get_elem(1));\n"
+    "    *this = %s_template(precondition, implied_template);\n"
+    "  } break;\n"
     "  default:\n"
     "    param.type_error(\"empty record/set template\", \"%s\");\n"
     "  }\n"
     "  is_ifpresent = param.get_ifpresent();\n"
-    "}\n\n", name, name, dispname, dispname);
+    "}\n\n", name, name, dispname, name, name, name, name, name, dispname);
 
     /* check template restriction */
     def = mputstr(def, "void check_restriction(template_res t_res, "
diff --git a/compiler2/record_of.c b/compiler2/record_of.c
index 68b6978f3..1a8a6fe04 100644
--- a/compiler2/record_of.c
+++ b/compiler2/record_of.c
@@ -4646,10 +4646,12 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
     "    *this = ANY_OR_OMIT;\n"
     "    break;\n"
     "  case Module_Param::MP_List_Template:\n"
-    "  case Module_Param::MP_ComplementList_Template: {\n"
+    "  case Module_Param::MP_ComplementList_Template:\n"
+    "  case Module_Param::MP_ConjunctList_Template: {\n"
     "    %s_template temp;\n"
     "    temp.set_type(param.get_type()==Module_Param::MP_List_Template ? "
-    "VALUE_LIST : COMPLEMENTED_LIST, param.get_size());\n"
+    "VALUE_LIST : (param.get_type() == Module_Param::MP_ConjunctList_Template ? "
+    "CONJUNCTION_MATCH : COMPLEMENTED_LIST), param.get_size());\n"
     "    for (size_t p_i=0; p_i<param.get_size(); p_i++) {\n"
     "      temp.list_item(p_i).set_param(*param.get_elem(p_i));\n"
     "    }\n"
@@ -4707,12 +4709,20 @@ void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output)
     "    break;\n");
   }
   src = mputprintf(src,
+    "  case Module_Param::MP_Implication_Template: {\n"
+    "    %s_template* precondition = new %s_template;\n"
+    "    precondition->set_param(*param.get_elem(0));\n"
+    "    %s_template* implied_template = new %s_template;\n"
+    "    implied_template->set_param(*param.get_elem(1));\n"
+    "    *this = %s_template(precondition, implied_template);\n"
+    "  } break;\n"
     "  default:\n"
     "    param.type_error(\"%s of template\", \"%s\");\n"
     "  }\n"
     "  is_ifpresent = param.get_ifpresent();\n"
     "  set_length_range(param);\n"
-    "}\n\n", sdef->kind==RECORD_OF?"record":"set", dispname);
+    "}\n\n", name, name, name, name, name,
+    sdef->kind==RECORD_OF?"record":"set", dispname);
 
   /* check template restriction */
   def = mputstr(def, "void check_restriction(template_res t_res, "
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 5e85c8af7..29b8dac0c 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -859,7 +859,8 @@ namespace Ttcn {
         ass = sb->get_dynamic_template()->get_dynamic_formalpar();
       }
       else {
-        // error
+        error("Reference to value being matched is only allowed inside a "
+          "dynamic template's statement block");
       }
     }
     else {
@@ -9578,10 +9579,13 @@ namespace Ttcn {
     case Template::VALUE_RANGE: {
       ValueRange *range = body->get_value_range();
       Value *low  = range->get_min_v();
-      Type::typetype_t tt_low = low->get_expr_returntype(exp_val);
+      if (low != NULL) {
+        low->get_expr_returntype(exp_val);
+      }
       Value *high = range->get_max_v();
-      Type::typetype_t tt_high = high->get_expr_returntype(exp_val);
-      if (tt_low == tt_high) break;
+      if (high != NULL) {
+        high->get_expr_returntype(exp_val);
+      }
       break; }
 
     case Template::BSTR_PATTERN:
@@ -9688,7 +9692,7 @@ namespace Ttcn {
       chk_defpar_template(body->get_implied_template()->get_Template(), exp_val);
       break;
     case Template::DYNAMIC_MATCH:
-      break; // todo: can a default value be a dynamic template?
+      break;
     } // switch templatetype
 
   }
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 50eea39ea..830c41368 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -6468,6 +6468,10 @@ error:
         "runtime");
       return;
     }
+    if (my_sb->is_in_dynamic_template()) {
+      error("The @update statement is not allowed in the statement block of a dynamic template");
+      return;
+    }
     Common::Assignment* refd_ass = update_op.ref->get_refd_assignment(false);
     if (refd_ass != NULL) {
       switch (refd_ass->get_asstype()) {
diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc
index 1301fa938..d56c2a1dd 100644
--- a/compiler2/ttcn3/TtcnTemplate.cc
+++ b/compiler2/ttcn3/TtcnTemplate.cc
@@ -2782,7 +2782,9 @@ end:
         u.implication.precondition->chk_immutability();
         u.implication.implied_template->chk_immutability();
         break;
-        // todo: dynamic matching?
+      case DYNAMIC_MATCH:
+        warning("Dynamic template may change the actual snapshot.");
+        break;
       default:
         FATAL_ERROR("Template::chk_immutability()");
     }
@@ -3361,6 +3363,8 @@ end:
     case BSTR_PATTERN: case HSTR_PATTERN: case OSTR_PATTERN:
     case CSTR_PATTERN: case USTR_PATTERN: case DECODE_MATCH:
     case TEMPLATE_CONCAT:
+    case IMPLICATION_MATCH:
+    case DYNAMIC_MATCH:
       break; // NOP
     }
 
@@ -3666,7 +3670,6 @@ end:
         erroneous = true;
         break;
       }
-      // todo: conjunction? implication? dynamic?
       break;
     case TR_PRESENT:
       if (is_ifpresent) {
@@ -3681,6 +3684,7 @@ end:
         needs_runtime_check = needs_runtime_check || nrc;
       } break;
       case VALUE_LIST:
+      case CONJUNCTION_MATCH:
         for (size_t i = 0; i < u.templates->get_nof_ts(); i++) {
           bool nrc = u.templates->get_t_byIndex(i)->
             chk_restriction(definition_name, template_restriction, usage_loc);
@@ -3723,6 +3727,10 @@ end:
         u.concat.op2->chk_restriction(definition_name, template_restriction,
           usage_loc);
         break;
+      case IMPLICATION_MATCH:
+        u.implication.precondition->chk_restriction(definition_name, template_restriction, usage_loc);
+        u.implication.implied_template->chk_restriction(definition_name, template_restriction, usage_loc);
+        break;
       default:
         break; // all others are ok
       }
@@ -4240,6 +4248,8 @@ end:
     case USTR_PATTERN:  /**< universal charstring pattern */
     case TEMPLATE_INVOKE:
     case DECODE_MATCH:
+    case IMPLICATION_MATCH:
+    case DYNAMIC_MATCH:
       // Simple templates can be computed at compile time
       return true;
 
@@ -4250,6 +4260,7 @@ end:
     case SUPERSET_MATCH:
     case SUBSET_MATCH:
     case PERMUTATION_MATCH:
+    case CONJUNCTION_MATCH:
       for (size_t i = 0; i < u.templates->get_nof_ts(); i++)
         if (u.templates->get_t_byIndex(i)->compile_time()) continue;
         else return false;
@@ -5495,7 +5506,8 @@ compile_time:
 
     str = u.dynamic.fp_list->generate_shadow_objects(str);
 
-    // todo: what do we do with @update statements in the dynamic template's block?
+    // just use dummies for the global variable string pointers
+    // only @update statements use these, and they are not allowed in the dynamic template's block
     char* dummy_def_glob_vars = NULL;
     char* dummy_src_glob_vars = NULL;
     str = u.dynamic.sb->generate_code(str, dummy_def_glob_vars, dummy_src_glob_vars);
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index a1f5aa968..833f066b5 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -2123,7 +2123,7 @@ The first 'implies' keyword in this case can be considered as part of the precon
 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').
+the precondition would be 't1' and the implied template 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
diff --git a/compiler2/union.c b/compiler2/union.c
index d02482d87..a397195da 100644
--- a/compiler2/union.c
+++ b/compiler2/union.c
@@ -3489,10 +3489,12 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "    *this = ANY_OR_OMIT;\n"
     "    break;\n"
     "  case Module_Param::MP_List_Template:\n"
-    "  case Module_Param::MP_ComplementList_Template: {\n"
+    "  case Module_Param::MP_ComplementList_Template:\n"
+    "  case Module_Param::MP_ConjunctList_Template: {\n"
     "    %s_template new_temp;\n"
     "    new_temp.set_type(m_p->get_type()==Module_Param::MP_List_Template ? "
-    "VALUE_LIST : COMPLEMENTED_LIST, m_p->get_size());\n"
+    "VALUE_LIST : (m_p->get_type() == Module_Param::MP_ConjunctList_Template ? "
+    "CONJUNCTION_MATCH : COMPLEMENTED_LIST), m_p->get_size());\n"
     "    for (size_t p_i=0; p_i<m_p->get_size(); p_i++) {\n"
     "      new_temp.list_item(p_i).set_param(*m_p->get_elem(p_i));\n"
     "    }\n"
@@ -3516,11 +3518,19 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
   src = mputprintf(src,
     "    mp_last->error(\"Field %%s does not exist in type %s.\", last_name);\n"
     "  } break;\n"
+    "  case Module_Param::MP_Implication_Template: {\n"
+    "    %s_template* precondition = new %s_template;\n"
+    "    precondition->set_param(*m_p->get_elem(0));\n"
+    "    %s_template* implied_template = new %s_template;\n"
+    "    implied_template->set_param(*m_p->get_elem(1));\n"
+    "    *this = %s_template(precondition, implied_template);\n"
+    "  } break;\n"
     "  default:\n"
     "    param.type_error(\"union template\", \"%s\");\n"
     "  }\n"
     "  is_ifpresent = param.get_ifpresent()%s;\n"
-    "}\n\n", dispname, dispname, use_runtime_2 ? " || m_p->get_ifpresent()" : "");
+    "}\n\n", dispname, name, name, name, name, name,
+    dispname, use_runtime_2 ? " || m_p->get_ifpresent()" : "");
   
   /* get_param(), RT2 only */
   if (use_runtime_2) {
diff --git a/core/Array.hh b/core/Array.hh
index 57d690f4c..565354009 100644
--- a/core/Array.hh
+++ b/core/Array.hh
@@ -2464,10 +2464,12 @@ void TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>::set_p
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset> temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -2488,6 +2490,15 @@ void TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>::set_p
       (*this)[curr->get_id()->get_index()].set_param(*curr);
     }
     break;
+  case Module_Param::MP_Implication_Template: {
+    TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>* precondition =
+      new TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>;
+    precondition->set_param(*mp->get_elem(0));
+    TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>* implied_template =
+      new TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offset>(precondition, implied_template);
+  } break;
   default:
     param.type_error("array template");
   }
@@ -2539,10 +2550,14 @@ Module_Param* TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offse
     values.clear();
     break; }
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2550,6 +2565,11 @@ Module_Param* TEMPLATE_ARRAY<T_value_type,T_template_type,array_size,index_offse
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     break;
   }
diff --git a/core/Bitstring.cc b/core/Bitstring.cc
index b45d60564..70a2b39ea 100644
--- a/core/Bitstring.cc
+++ b/core/Bitstring.cc
@@ -2303,10 +2303,12 @@ void BITSTRING_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template:  {
     BITSTRING_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -2318,6 +2320,13 @@ void BITSTRING_template::set_param(Module_Param& param) {
   case Module_Param::MP_Bitstring_Template:
     *this = BITSTRING_template(mp->get_string_size(), (unsigned char*)mp->get_string_data());
     break;
+  case Module_Param::MP_Implication_Template: {
+    BITSTRING_template* precondition = new BITSTRING_template;
+    precondition->set_param(*mp->get_elem(0));
+    BITSTRING_template* implied_template = new BITSTRING_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = BITSTRING_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
       BITSTRING operand1, operand2;
@@ -2362,10 +2371,14 @@ Module_Param* BITSTRING_template::get_param(Module_Param_Name& param_name) const
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2378,6 +2391,11 @@ Module_Param* BITSTRING_template::get_param(Module_Param_Name& param_name) const
     memcpy(val_cpy, pattern_value->elements_ptr, pattern_value->n_elements);
     mp = new Module_Param_Bitstring_Template(pattern_value->n_elements, val_cpy);
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   case DECODE_MATCH:
     TTCN_error("Referencing a decoded content matching template is not supported.");
     break;
diff --git a/core/Boolean.cc b/core/Boolean.cc
index d273a2701..52c4a7300 100644
--- a/core/Boolean.cc
+++ b/core/Boolean.cc
@@ -1184,10 +1184,12 @@ void BOOLEAN_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     BOOLEAN_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -1196,6 +1198,13 @@ void BOOLEAN_template::set_param(Module_Param& param) {
   case Module_Param::MP_Boolean:
     *this = mp->get_boolean();
     break;
+  case Module_Param::MP_Implication_Template: {
+    BOOLEAN_template* precondition = new BOOLEAN_template;
+    precondition->set_param(*mp->get_elem(0));
+    BOOLEAN_template* implied_template = new BOOLEAN_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = BOOLEAN_template(precondition, implied_template);
+  } break;
   default:
     param.type_error("boolean template");
   }
@@ -1223,10 +1232,14 @@ Module_Param* BOOLEAN_template::get_param(Module_Param_Name& param_name) const
     mp = new Module_Param_Boolean(single_value);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -1234,6 +1247,11 @@ Module_Param* BOOLEAN_template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported boolean template.");
     break;
diff --git a/core/Charstring.cc b/core/Charstring.cc
index dedbe3efb..ffeb55fcf 100644
--- a/core/Charstring.cc
+++ b/core/Charstring.cc
@@ -3028,10 +3028,12 @@ void CHARSTRING_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     CHARSTRING_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -3061,6 +3063,13 @@ void CHARSTRING_template::set_param(Module_Param& param) {
     pattern_value.nocase = mp->get_nocase();
     set_selection(STRING_PATTERN);
     break;
+  case Module_Param::MP_Implication_Template: {
+    CHARSTRING_template* precondition = new CHARSTRING_template;
+    precondition->set_param(*mp->get_elem(0));
+    CHARSTRING_template* implied_template = new CHARSTRING_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = CHARSTRING_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
       // only allow string patterns for the first operand
@@ -3118,10 +3127,14 @@ Module_Param* CHARSTRING_template::get_param(Module_Param_Name& param_name) cons
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -3137,6 +3150,11 @@ Module_Param* CHARSTRING_template::get_param(Module_Param_Name& param_name) cons
   case STRING_PATTERN:
     mp = new Module_Param_Pattern(mcopystr(single_value), pattern_value.nocase);
     break;
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   case DECODE_MATCH:
     TTCN_error("Referencing a decoded content matching template is not supported.");
     break;
diff --git a/core/Component.cc b/core/Component.cc
index 44a87c17f..a96b63426 100644
--- a/core/Component.cc
+++ b/core/Component.cc
@@ -746,10 +746,12 @@ void COMPONENT_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     COMPONENT_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -767,6 +769,13 @@ void COMPONENT_template::set_param(Module_Param& param) {
   case Module_Param::MP_Ttcn_system:
     *this = SYSTEM_COMPREF;
     break;
+  case Module_Param::MP_Implication_Template: {
+    COMPONENT_template* precondition = new COMPONENT_template;
+    precondition->set_param(*mp->get_elem(0));
+    COMPONENT_template* implied_template = new COMPONENT_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = COMPONENT_template(precondition, implied_template);
+  } break;
   default:
     param.type_error("component reference (integer or null) template");
   }
@@ -807,10 +816,14 @@ Module_Param* COMPONENT_template::get_param(Module_Param_Name& param_name) const
     }    
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -818,6 +831,11 @@ Module_Param* COMPONENT_template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported component reference template.");
     break;
diff --git a/core/Default.cc b/core/Default.cc
index 3e585cf95..5a8ffefd3 100644
--- a/core/Default.cc
+++ b/core/Default.cc
@@ -552,10 +552,12 @@ void DEFAULT_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     DEFAULT_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -564,6 +566,13 @@ void DEFAULT_template::set_param(Module_Param& param) {
   case Module_Param::MP_Ttcn_Null:
     *this = DEFAULT(NULL_COMPREF);
     break;
+  case Module_Param::MP_Implication_Template: {
+    DEFAULT_template* precondition = new DEFAULT_template;
+    precondition->set_param(*mp->get_elem(0));
+    DEFAULT_template* implied_template = new DEFAULT_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = DEFAULT_template(precondition, implied_template);
+  } break;
   default:
     param.type_error("default reference (null) template");
   }
@@ -591,10 +600,14 @@ Module_Param* DEFAULT_template::get_param(Module_Param_Name& param_name) const
     mp = new Module_Param_Ttcn_Null();
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -602,6 +615,11 @@ Module_Param* DEFAULT_template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     break;
   }
diff --git a/core/Float.cc b/core/Float.cc
index c9ee5b25a..6dfaba416 100644
--- a/core/Float.cc
+++ b/core/Float.cc
@@ -1868,10 +1868,12 @@ void FLOAT_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     FLOAT_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -1887,6 +1889,13 @@ void FLOAT_template::set_param(Module_Param& param) {
     set_min_exclusive(mp->get_is_min_exclusive());
     set_max_exclusive(mp->get_is_max_exclusive());
     break;
+  case Module_Param::MP_Implication_Template: {
+    FLOAT_template* precondition = new FLOAT_template;
+    precondition->set_param(*mp->get_elem(0));
+    FLOAT_template* implied_template = new FLOAT_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = FLOAT_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     switch (mp->get_expr_type()) {
     case Module_Param::EXPR_NEGATE: {
@@ -1953,10 +1962,14 @@ Module_Param* FLOAT_template::get_param(Module_Param_Name& param_name) const
     mp = new Module_Param_Float(single_value);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -1969,6 +1982,11 @@ Module_Param* FLOAT_template::get_param(Module_Param_Name& param_name) const
       value_range.min_value, value_range.min_is_present,
       value_range.max_value, value_range.max_is_present, value_range.min_is_exclusive, value_range.max_is_exclusive);
     break;
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported float template.");
     break;
diff --git a/core/Hexstring.cc b/core/Hexstring.cc
index a9d6f9e9d..0828f8adc 100644
--- a/core/Hexstring.cc
+++ b/core/Hexstring.cc
@@ -2125,10 +2125,12 @@ void HEXSTRING_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     HEXSTRING_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -2140,6 +2142,13 @@ void HEXSTRING_template::set_param(Module_Param& param) {
   case Module_Param::MP_Hexstring_Template:
     *this = HEXSTRING_template(mp->get_string_size(), (unsigned char*)mp->get_string_data());
     break;
+  case Module_Param::MP_Implication_Template: {
+    HEXSTRING_template* precondition = new HEXSTRING_template;
+    precondition->set_param(*mp->get_elem(0));
+    HEXSTRING_template* implied_template = new HEXSTRING_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = HEXSTRING_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
       HEXSTRING operand1, operand2;
@@ -2184,10 +2193,14 @@ Module_Param* HEXSTRING_template::get_param(Module_Param_Name& param_name) const
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2200,6 +2213,11 @@ Module_Param* HEXSTRING_template::get_param(Module_Param_Name& param_name) const
     memcpy(val_cpy, pattern_value->elements_ptr, pattern_value->n_elements);
     mp = new Module_Param_Hexstring_Template(pattern_value->n_elements, val_cpy);
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   case DECODE_MATCH:
     TTCN_error("Referencing a decoded content matching template is not supported.");
     break;
diff --git a/core/Integer.cc b/core/Integer.cc
index 1ac0dc593..21d9dd6ac 100644
--- a/core/Integer.cc
+++ b/core/Integer.cc
@@ -2673,10 +2673,12 @@ void INTEGER_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     INTEGER_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -2702,6 +2704,13 @@ void INTEGER_template::set_param(Module_Param& param) {
     }
     set_max_exclusive(mp->get_is_max_exclusive());
   } break;
+  case Module_Param::MP_Implication_Template: {
+    INTEGER_template* precondition = new INTEGER_template;
+    precondition->set_param(*mp->get_elem(0));
+    INTEGER_template* implied_template = new INTEGER_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = INTEGER_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     switch (mp->get_expr_type()) {
     case Module_Param::EXPR_NEGATE: {
@@ -2773,10 +2782,14 @@ Module_Param* INTEGER_template::get_param(Module_Param_Name& param_name) const
     }
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2805,6 +2818,11 @@ Module_Param* INTEGER_template::get_param(Module_Param_Name& param_name) const
     }
     mp = new Module_Param_IntRange(lower_bound, upper_bound, value_range.min_is_exclusive, value_range.max_is_exclusive);
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported integer template.");
     break;
diff --git a/core/Objid.cc b/core/Objid.cc
index 89e243788..1a55e3636 100644
--- a/core/Objid.cc
+++ b/core/Objid.cc
@@ -1100,10 +1100,12 @@ void OBJID_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     OBJID_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -1113,6 +1115,13 @@ void OBJID_template::set_param(Module_Param& param) {
     if (sizeof(OBJID::objid_element)!=sizeof(int)) TTCN_error("Internal error: OBJID_template::set_param()"); 
     *this = OBJID(mp->get_string_size(), (OBJID::objid_element*)mp->get_string_data());
     break;
+  case Module_Param::MP_Implication_Template: {
+    OBJID_template* precondition = new OBJID_template;
+    precondition->set_param(*mp->get_elem(0));
+    OBJID_template* implied_template = new OBJID_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = OBJID_template(precondition, implied_template);
+  } break;
   //case Module_Param::MP_Objid_Template:
   // TODO
   //break;
@@ -1143,10 +1152,14 @@ Module_Param* OBJID_template::get_param(Module_Param_Name& param_name) const
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -1154,6 +1167,11 @@ Module_Param* OBJID_template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported objid template.");
     break;
diff --git a/core/Octetstring.cc b/core/Octetstring.cc
index aaa06388d..49d67a2af 100644
--- a/core/Octetstring.cc
+++ b/core/Octetstring.cc
@@ -2422,10 +2422,12 @@ void OCTETSTRING_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     OCTETSTRING_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -2437,6 +2439,13 @@ void OCTETSTRING_template::set_param(Module_Param& param) {
   case Module_Param::MP_Octetstring_Template:
     *this = OCTETSTRING_template(mp->get_string_size(), (unsigned short*)mp->get_string_data());
     break;
+  case Module_Param::MP_Implication_Template: {
+    OCTETSTRING_template* precondition = new OCTETSTRING_template;
+    precondition->set_param(*mp->get_elem(0));
+    OCTETSTRING_template* implied_template = new OCTETSTRING_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = OCTETSTRING_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
       OCTETSTRING operand1, operand2;
@@ -2481,10 +2490,14 @@ Module_Param* OCTETSTRING_template::get_param(Module_Param_Name& param_name) con
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2499,6 +2512,11 @@ Module_Param* OCTETSTRING_template::get_param(Module_Param_Name& param_name) con
       sizeof(unsigned short));
     mp = new Module_Param_Octetstring_Template(pattern_value->n_elements, val_cpy);
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   case DECODE_MATCH:
     TTCN_error("Referencing a decoded content matching template is not supported.");
     break;
diff --git a/core/Param_Types.cc b/core/Param_Types.cc
index 7628b857a..0eb848984 100644
--- a/core/Param_Types.cc
+++ b/core/Param_Types.cc
@@ -632,6 +632,12 @@ void Module_Param_Compound::add_list_with_implicit_ids(Vector<Module_Param*>* mp
   }
 }
 
+void Module_Param_Implication_Template::log_value() const {
+  values[0]->log();
+  TTCN_Logger::log_event_str(" implies ");
+  values[1]->log();
+}
+
 char* Module_Param::get_param_context() const {
   char* result = NULL;
   if (parent != NULL) {
diff --git a/core/Param_Types.hh b/core/Param_Types.hh
index 4fe72c0cd..753b054cc 100644
--- a/core/Param_Types.hh
+++ b/core/Param_Types.hh
@@ -197,6 +197,8 @@ public:
   MP_Superset_Template,
   MP_Subset_Template,
   MP_Permutation_Template,
+  MP_ConjunctList_Template,
+  MP_Implication_Template,
   MP_Reference,
   MP_Unbound,
   MP_Expression
@@ -629,6 +631,7 @@ public:
 };
 
 class Module_Param_Compound : public Module_Param {
+protected:
   Vector<Module_Param*> values; // Module_Param instances are owned
 public:
   Module_Param_Compound() {}
@@ -698,6 +701,20 @@ public:
   void log_value() const { log_value_vec("permutation(",")"); }
 };
 
+class Module_Param_ConjunctList_Template : public Module_Param_Compound {
+public:
+  type_t get_type() const { return MP_ConjunctList_Template; }
+  const char* get_type_str() const { return "conjunction list template"; }
+  void log_value() const { log_value_vec("conjunct(",")"); }
+};
+
+class Module_Param_Implication_Template : public Module_Param_Compound {
+public:
+  type_t get_type() const { return MP_Implication_Template; }
+  const char* get_type_str() const { return "implication match template"; }
+  void log_value() const;
+};
+
 class Ttcn_String_Parsing {
 private: // only instantiation can set it to true and destruction set it back to false
   static boolean string_parsing;
diff --git a/core/Template.cc b/core/Template.cc
index 6e2fffa98..53a9f3f05 100644
--- a/core/Template.cc
+++ b/core/Template.cc
@@ -1489,7 +1489,8 @@ void Record_Of_Template::set_param(Module_Param& param)
     set_value(ANY_OR_OMIT);
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     Record_Of_Template** list_items = (Record_Of_Template**)
       allocate_pointers(mp->get_size());
     for (size_t i = 0; i < mp->get_size(); i++) {
@@ -1498,7 +1499,8 @@ void Record_Of_Template::set_param(Module_Param& param)
     }
     clean_up();
     template_selection = mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST;
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST);
     value_list.n_values = mp->get_size();
     value_list.list_value = list_items;
     break; }
@@ -1535,6 +1537,16 @@ void Record_Of_Template::set_param(Module_Param& param)
       get_at((int)current->get_id()->get_index())->set_param(*current);
     }
     break;
+  case Module_Param::MP_Implication_Template: {
+    Record_Of_Template* precondition = create();
+    precondition->set_param(*mp->get_elem(0));
+    Record_Of_Template* implied_template = create();
+    implied_template->set_param(*mp->get_elem(1));
+    clean_up();
+    template_selection = IMPLICATION_MATCH;
+    implication_.precondition = precondition;
+    implication_.implied_template = implied_template;
+  } break;
   default:
     param.type_error("record of template", get_descriptor()->name);
   }
@@ -1586,10 +1598,14 @@ Module_Param* Record_Of_Template::get_param(Module_Param_Name& param_name) const
     values.clear();
     break; }
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -1597,6 +1613,11 @@ Module_Param* Record_Of_Template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i]->get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported template of type %s.", get_descriptor()->name);
     break;
@@ -2560,7 +2581,8 @@ void Set_Of_Template::set_param(Module_Param& param)
     set_value(ANY_OR_OMIT);
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     Set_Of_Template** list_items = (Set_Of_Template**)
       allocate_pointers(mp->get_size());
     for (size_t i = 0; i < mp->get_size(); i++) {
@@ -2569,7 +2591,8 @@ void Set_Of_Template::set_param(Module_Param& param)
     }
     clean_up();
     template_selection = mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST;
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST);
     value_list.n_values = mp->get_size();
     value_list.list_value = list_items;
     break; }
@@ -2596,6 +2619,16 @@ void Set_Of_Template::set_param(Module_Param& param)
       get_set_item((int)i)->set_param(*mp->get_elem(i));
     }
     break;
+  case Module_Param::MP_Implication_Template: {
+    Set_Of_Template* precondition = create();
+    precondition->set_param(*mp->get_elem(0));
+    Set_Of_Template* implied_template = create();
+    implied_template->set_param(*mp->get_elem(1));
+    clean_up();
+    template_selection = IMPLICATION_MATCH;
+    implication_.precondition = precondition;
+    implication_.implied_template = implied_template;
+  } break;
   default:
     param.type_error("set of template", get_descriptor()->name);
   }
@@ -2647,10 +2680,14 @@ Module_Param* Set_Of_Template::get_param(Module_Param_Name& param_name) const
     values.clear();
     break; }
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -2658,6 +2695,11 @@ Module_Param* Set_Of_Template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i]->get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported template of type %s.", get_descriptor()->name);
     break;
@@ -3296,7 +3338,8 @@ void Record_Template::set_param(Module_Param& param)
     set_value(ANY_OR_OMIT);
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     Record_Template** list_items = (Record_Template**)
       allocate_pointers(mp->get_size());
     for (size_t i = 0; i < mp->get_size(); i++) {
@@ -3305,7 +3348,8 @@ void Record_Template::set_param(Module_Param& param)
     }
     clean_up();
     template_selection = mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST;
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST);
     value_list.n_values = mp->get_size();
     value_list.list_value = list_items;
     break; }
@@ -3340,6 +3384,16 @@ void Record_Template::set_param(Module_Param& param)
       }
     }
     break;
+  case Module_Param::MP_Implication_Template: {
+    Record_Template* precondition = create();
+    precondition->set_param(*mp->get_elem(0));
+    Record_Template* implied_template = create();
+    implied_template->set_param(*mp->get_elem(1));
+    clean_up();
+    template_selection = IMPLICATION_MATCH;
+    implication_.precondition = precondition;
+    implication_.implied_template = implied_template;
+  } break;
   default:
     param.type_error("record/set template", get_descriptor()->name);
   }
@@ -3388,10 +3442,14 @@ Module_Param* Record_Template::get_param(Module_Param_Name& param_name) const
     }
     break; }
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -3399,6 +3457,11 @@ Module_Param* Record_Template::get_param(Module_Param_Name& param_name) const
       mp->add_elem(value_list.list_value[i]->get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported template of type %s.", get_descriptor()->name);
     break;
@@ -3787,7 +3850,8 @@ void Empty_Record_Template::set_param(Module_Param& param)
     set_value(ANY_OR_OMIT);
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     Empty_Record_Template** list_items = (Empty_Record_Template**)
       allocate_pointers(mp->get_size());
     for (size_t i = 0; i < mp->get_size(); i++) {
@@ -3796,7 +3860,8 @@ void Empty_Record_Template::set_param(Module_Param& param)
     }
     clean_up();
     template_selection = mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST;
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST);
     value_list.n_values = mp->get_size();
     value_list.list_value = list_items;
     break; }
@@ -3806,6 +3871,16 @@ void Empty_Record_Template::set_param(Module_Param& param)
     }
     else param.type_error("empty record/set template", get_descriptor()->name);
     break;
+  case Module_Param::MP_Implication_Template: {
+    Empty_Record_Template* precondition = create();
+    precondition->set_param(*mp->get_elem(0));
+    Empty_Record_Template* implied_template = create();
+    implied_template->set_param(*mp->get_elem(1));
+    clean_up();
+    template_selection = IMPLICATION_MATCH;
+    implication_.precondition = precondition;
+    implication_.implied_template = implied_template;
+  } break;
   default:
     param.type_error("empty record/set template", get_descriptor()->name);
   }
@@ -3832,10 +3907,14 @@ Module_Param* Empty_Record_Template::get_param(Module_Param_Name& param_name) co
     mp = new Module_Param_Value_List();
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -3843,6 +3922,11 @@ Module_Param* Empty_Record_Template::get_param(Module_Param_Name& param_name) co
       mp->add_elem(value_list.list_value[i]->get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported template of type %s.", get_descriptor()->name);
     break;
diff --git a/core/Universal_charstring.cc b/core/Universal_charstring.cc
index 44f2c6804..63e6c095f 100644
--- a/core/Universal_charstring.cc
+++ b/core/Universal_charstring.cc
@@ -4876,10 +4876,12 @@ void UNIVERSAL_CHARSTRING_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     UNIVERSAL_CHARSTRING_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -4912,6 +4914,13 @@ void UNIVERSAL_CHARSTRING_template::set_param(Module_Param& param) {
     pattern_value.nocase = mp->get_nocase();
     set_selection(STRING_PATTERN);
     break;
+  case Module_Param::MP_Implication_Template: {
+    UNIVERSAL_CHARSTRING_template* precondition = new UNIVERSAL_CHARSTRING_template;
+    precondition->set_param(*mp->get_elem(0));
+    UNIVERSAL_CHARSTRING_template* implied_template = new UNIVERSAL_CHARSTRING_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = UNIVERSAL_CHARSTRING_template(precondition, implied_template);
+  } break;
   case Module_Param::MP_Expression:
     if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
       UNIVERSAL_CHARSTRING operand1, operand2, result;
@@ -4973,10 +4982,14 @@ Module_Param* UNIVERSAL_CHARSTRING_template::get_param(Module_Param_Name& param_
     mp = single_value.get_param(param_name);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -4990,6 +5003,11 @@ Module_Param* UNIVERSAL_CHARSTRING_template::get_param(Module_Param_Name& param_
   case STRING_PATTERN:
     mp = new Module_Param_Pattern(mcopystr(*pattern_string), pattern_value.nocase);
     break;
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   case DECODE_MATCH:
     TTCN_error("Referencing a decoded content matching template is not supported.");
     break;
diff --git a/core/Verdicttype.cc b/core/Verdicttype.cc
index 95d9e2f7a..f05e31b57 100644
--- a/core/Verdicttype.cc
+++ b/core/Verdicttype.cc
@@ -789,10 +789,12 @@ void VERDICTTYPE_template::set_param(Module_Param& param) {
     *this = ANY_OR_OMIT;
     break;
   case Module_Param::MP_List_Template:
-  case Module_Param::MP_ComplementList_Template: {
+  case Module_Param::MP_ComplementList_Template:
+  case Module_Param::MP_ConjunctList_Template: {
     VERDICTTYPE_template temp;
     temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
-      VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
+      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
+      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
     for (size_t i=0; i<mp->get_size(); i++) {
       temp.list_item(i).set_param(*mp->get_elem(i));
     }
@@ -801,6 +803,13 @@ void VERDICTTYPE_template::set_param(Module_Param& param) {
   case Module_Param::MP_Verdict:
     *this = mp->get_verdict();
     break;
+  case Module_Param::MP_Implication_Template: {
+    VERDICTTYPE_template* precondition = new VERDICTTYPE_template;
+    precondition->set_param(*mp->get_elem(0));
+    VERDICTTYPE_template* implied_template = new VERDICTTYPE_template;
+    implied_template->set_param(*mp->get_elem(1));
+    *this = VERDICTTYPE_template(precondition, implied_template);
+  } break;
   default:
     param.type_error("verdict template");
   }
@@ -828,10 +837,14 @@ Module_Param* VERDICTTYPE_template::get_param(Module_Param_Name& param_name) con
     mp = new Module_Param_Verdict(single_value);
     break;
   case VALUE_LIST:
-  case COMPLEMENTED_LIST: {
+  case COMPLEMENTED_LIST:
+  case CONJUNCTION_MATCH: {
     if (template_selection == VALUE_LIST) {
       mp = new Module_Param_List_Template();
     }
+    else if (template_selection == CONJUNCTION_MATCH) {
+      mp = new Module_Param_ConjunctList_Template();
+    }
     else {
       mp = new Module_Param_ComplementList_Template();
     }
@@ -839,6 +852,11 @@ Module_Param* VERDICTTYPE_template::get_param(Module_Param_Name& param_name) con
       mp->add_elem(value_list.list_value[i].get_param(param_name));
     }
     break; }
+  case IMPLICATION_MATCH:
+    mp = new Module_Param_Implication_Template();
+    mp->add_elem(implication_.precondition->get_param(param_name));
+    mp->add_elem(implication_.implied_template->get_param(param_name));
+    break;
   default:
     TTCN_error("Referencing an uninitialized/unsupported verdict template.");
     break;
diff --git a/core/config_process.l b/core/config_process.l
index 3b6b425f8..64a12c89f 100644
--- a/core/config_process.l
+++ b/core/config_process.l
@@ -580,6 +580,8 @@ length      return LengthKeyword;
 ifpresent   return IfpresentKeyword;
 infinity    return InfinityKeyword;
 "@nocase"   return NocaseKeyword;
+conjunct    return ConjunctKeyword;
+implies     return ImpliesKeyword;
 }
 
 <SC_MODULE_PARAMETERS,SC_LOGGING,SC_PROFILER>
diff --git a/core/config_process.y b/core/config_process.y
index a971af729..68497c8c5 100644
--- a/core/config_process.y
+++ b/core/config_process.y
@@ -190,6 +190,8 @@ string_map_t *config_defines;
 %token IfpresentKeyword "ifpresent"
 %token InfinityKeyword "infinity"
 %token NocaseKeyword "@nocase"
+%token ConjunctKeyword "conjunct"
+%token ImpliesKeyword "implies"
 %token AssignmentChar ":= or ="
 %token ConcatChar "&="
 %token LogFile "LogFile or FileName"
@@ -393,7 +395,7 @@ ParameterNameSegment
 %left '*' '/'
 %left UnarySign
 
-%expect 2
+%expect 3
 
 /*
 1 conflict:
@@ -403,6 +405,15 @@ all modules in the next module parameter (reduce).
 1 conflict:
 infinity can be a float value in LengthMatch's upper bound (SimpleParameterValue)
 or an infinityKeyword.
+1 conflict:
+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 template would be 't2 implies t3').
+This is the reduce case.
+Semantically both cases mean the same thing.
 */
 %%
 
@@ -503,6 +514,12 @@ ParameterValue:
     $$->set_length_restriction($2);
     $$->set_ifpresent();
   }
+| ParameterValue ImpliesKeyword ParameterValue
+  {
+    $$ = new Module_Param_Implication_Template();
+    $$->add_elem($1);
+    $$->add_elem($3);
+  }
 ;
 
 LengthMatch:
@@ -1263,6 +1280,12 @@ CompoundValue:
     $$->add_list_with_implicit_ids($3);
     delete $3;
   }
+| ConjunctKeyword '(' TemplateItemList ')'
+  {
+    $$ = new Module_Param_ConjunctList_Template();
+    $$->add_list_with_implicit_ids($3);
+    delete $3;
+  }
 ;
 
 ParameterValueOrNotUsedSymbol:
diff --git a/function_test/Semantic_Analyser/erroneous_attributes/ErroneousAttributes_SE.ttcn b/function_test/Semantic_Analyser/erroneous_attributes/ErroneousAttributes_SE.ttcn
index 3e267b860..ac724d75d 100644
--- a/function_test/Semantic_Analyser/erroneous_attributes/ErroneousAttributes_SE.ttcn
+++ b/function_test/Semantic_Analyser/erroneous_attributes/ErroneousAttributes_SE.ttcn
@@ -104,6 +104,11 @@ function f_bad_updates() { //^In function definition//
   @update(PT); //^In @update statement// //Reference to constant or template definition was expected instead of type//
 }
 
+template integer t_dyn := @dynamic { //^In template definition// 
+  @update(c_rec) with { erroneous(str) "after(raw) := \"abc\"" } //^In @update statement// //The @update statement is not allowed in the statement block of a dynamic template//
+  return true;
+}
+
 signature Sig(inout integer p);
 
 type port PT procedure {
diff --git a/function_test/Semantic_Analyser/template/TempDynamic_SE.ttcn b/function_test/Semantic_Analyser/template/TempDynamic_SE.ttcn
new file mode 100644
index 000000000..076d1ff6d
--- /dev/null
+++ b/function_test/Semantic_Analyser/template/TempDynamic_SE.ttcn
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * Copyright (c) 2000-2021 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+ *
+ * Contributors:
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+module TempDynamic_SE { //^In TTCN-3 module//
+
+template integer t1 := @dynamic { return value mod 2 == 0; }
+
+function f_not_a_template() return integer { //^In function definition//
+  return value mod 2 == 0; //^In return statement// //^In the left operand of operation//2 //Reference to value being matched is only allowed inside a dynamic template's statement block//
+}
+
+template integer t2 := @dynamic { } //^In template definition// //The dynamic template's statement block does not have a return statement//
+
+template integer t3 := @dynamic { return; } //^In template definition// //^In return statement// //Missing return value. The dynamic template's statement block should return a boolean value//
+
+template integer t4 := @dynamic { return 1; } //^In template definition// //^In return statement// //boolean value was expected//
+
+template integer t5 := @dynamic { return ?; } //^In template definition// //^In return statement// //A specific value without matching symbols was expected as return value//
+
+template integer t6 := @dynamic { //^In template definition// //Control might leave the dynamic template's statement block without reaching a return statement//
+  if (value > 3) { return true; }
+}
+
+type component CT {
+  var integer cv;
+}
+
+const integer c := 3;
+
+function f() runs on CT {
+  var template integer vt := @dynamic {
+    if (value > c) { return true; }
+    cv := value;
+    return false;
+  }
+}
+
+template (omit) integer t7 := @dynamic { return value mod 2 == 0; } //^In template definition// //^While checking template restriction// //Restriction on template definition does not allow usage of dynamic match//
+
+template (value) integer t8 := @dynamic { return value mod 2 == 0; } //^In template definition// //^While checking template restriction// //Restriction on template definition does not allow usage of dynamic match//
+
+template (present) integer t9 := @dynamic { return value mod 2 == 0; }
+
+}
diff --git a/function_test/Semantic_Analyser/template/TempImplication_SE.ttcn b/function_test/Semantic_Analyser/template/TempImplication_SE.ttcn
new file mode 100644
index 000000000..bbc6d9911
--- /dev/null
+++ b/function_test/Semantic_Analyser/template/TempImplication_SE.ttcn
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Copyright (c) 2000-2021 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+ *
+ * Contributors:
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+module TempImplication_SE { //^In TTCN-3 module//
+
+// OK (the length restriction and ifpresent refer to the 2nd operand, not the resulting template)
+template charstring t1 := ? length (1..4) ifpresent implies ? length (2..3) ifpresent;
+
+// these are not allowed according to the BNF in the standard, but the compiler accepts them
+// (the first length restriction/ifpresent pair refer to the 2nd operand, the second pair refer to the resulting template)
+template charstring t2 := ? length (1..4) ifpresent implies ? length (2..3) ifpresent ifpresent;
+template charstring t3 := ? length (1..4) ifpresent implies ? length (2..3) ifpresent length (3);
+template charstring t4 := ? length (1..4) ifpresent implies ? length (2..3) ifpresent length (3) ifpresent;
+
+// this is the standard's way of adding length restrictions and ifpresent to both the 2nd operand and the resulting template,
+// but the compiler interprets the 2nd operand as a value list match with 1 element, which cannot have ifpresent
+template charstring t5 := ? length (1..4) ifpresent implies (? length (2..3) ifpresent) length (3) ifpresent; //^In template definition// //^In list item// //`ifpresent' is not allowed here//
+
+// same as t4, but more readable (also not allowed according to the BNF in the standard)
+template charstring t6 := (? length (1..4) ifpresent implies ? length (2..3) ifpresent) length (3) ifpresent;
+
+function f() {
+  // OK (the type identifier refers to the first operand, not the resulting template)
+  log(match(3, integer: (1..3) implies integer: 3));
+  
+  // according to the BNF in the standard this should be allowed, 
+  // but the parser cannot handle two type identifiers one after the other
+  //log(match(3, integer: integer: (1..3) implies integer: 3)); parser error
+}
+
+}
diff --git a/regression_test/cfgFile/module_parameters/references/references.cfg b/regression_test/cfgFile/module_parameters/references/references.cfg
index 044ce92a7..e669efc20 100644
--- a/regression_test/cfgFile/module_parameters/references/references.cfg
+++ b/regression_test/cfgFile/module_parameters/references/references.cfg
@@ -99,6 +99,7 @@ mparray2 := mparray1;
 # integer template
 mptint1 := mptint2;
 mptint2 := (mp1 + 6, mp2, - mp3, - ${MACRO_INT, integer});
+mptint4 := mptint3;
 
 # float template
 mptf1 := mptf2 ifpresent;
diff --git a/regression_test/cfgFile/module_parameters/references/references.ttcn b/regression_test/cfgFile/module_parameters/references/references.ttcn
index 73951ae5f..2ecdd66e9 100644
--- a/regression_test/cfgFile/module_parameters/references/references.ttcn
+++ b/regression_test/cfgFile/module_parameters/references/references.ttcn
@@ -99,6 +99,8 @@ modulepar TwoStrings mparray2 := { "xy", "yx" };
 
 modulepar template integer mptint1 := 7;
 modulepar template integer mptint2 := (3..6) ifpresent;
+modulepar template integer mptint3 := conjunct((0..infinity), (10..20) implies (11, 13, 17));
+modulepar template integer mptint4 := -1;
 
 modulepar template float mptf1 := 33.33;
 modulepar template float mptf2 := (33.0..66.0);
@@ -429,6 +431,9 @@ testcase tc_ref_integer_template() runs on CT
   if (log2str(mptint2) != log2str(mptint2_exp)) {
     setverdict(fail, "Expected(mptint2): ", mptint2_exp, ", got: ", mptint2);
   }
+  if (log2str(mptint4) != log2str(mptint3)) {
+    setverdict(fail, "Expected(mptint4): ", mptint3, ", got: ", mptint4);
+  }
   setverdict(pass);
 }
 
diff --git a/regression_test/templateInt/TtemplateInt.ttcn b/regression_test/templateInt/TtemplateInt.ttcn
index 311ba2af8..8463f23b2 100644
--- a/regression_test/templateInt/TtemplateInt.ttcn
+++ b/regression_test/templateInt/TtemplateInt.ttcn
@@ -494,6 +494,140 @@ testcase templateIntDynamic() runs on templateInt_mycomp {
 }
 
 
+function f_defpar_conjunction(in template integer pt_def := conjunct((100..infinity), @dynamic f_is_prime)) {
+  var integer v1 := 179, v2 := 122;
+  if (not match(v1, pt_def)) {
+    setverdict(fail, match(v1, pt_def));
+  }
+  if (match(v2, pt_def)) {
+    setverdict(fail, match(v2, pt_def));
+  }
+  setverdict(pass);
+}
+
+function f_defpar_implication(in template integer pt_def := (0..infinity) implies @dynamic f_is_prime) {
+  var integer v1 := -20, v2 := 4, v3 := 11;
+  if (not match(v1, pt_def)) {
+    setverdict(fail, match(v1, pt_def));
+  }
+  if (match(v2, pt_def)) {
+    setverdict(fail, match(v2, pt_def));
+  }
+  if (not match(v3, pt_def)) {
+    setverdict(fail, match(v3, pt_def));
+  }
+  setverdict(pass);
+}
+
+function f_defpar_dynamic(in template integer pt_def := @dynamic {
+  if (value < 0) { value := -value; }
+  var integer v_num_digits := 0;
+  while (value > 0) {
+    v_num_digits := v_num_digits + 1;
+    value := value / 10;
+  }
+  return v_num_digits == 3;
+}) {
+  var integer v1 := 123, v2 := 67;
+  if (not match(v1, pt_def)) {
+    setverdict(fail, match(v1, pt_def));
+  }
+  if (match(v2, pt_def)) {
+    setverdict(fail, match(v2, pt_def));
+  }
+  setverdict(pass);
+}
+
+testcase templateIntConjunctionDefPar() runs on templateInt_mycomp {
+  f_defpar_conjunction();
+}
+
+testcase templateIntImplicationDefPar() runs on templateInt_mycomp {
+  f_defpar_implication();
+}
+
+testcase templateIntDynamicDefPar() runs on templateInt_mycomp {
+  f_defpar_dynamic();
+}
+
+
+modulepar template integer mpt_conjunction;
+modulepar template integer mpt_implication;
+
+testcase templateIntConjunctionModulepar() runs on templateInt_mycomp {
+  var integer v1 := 179, v2 := 322;
+  if (not match(v1, mpt_conjunction)) {
+    setverdict(fail, match(v1, mpt_conjunction));
+  }
+  if (match(v2, mpt_conjunction)) {
+    setverdict(fail, match(v2, mpt_conjunction));
+  }
+  setverdict(pass);
+}
+
+testcase templateIntImplicationModulepar() runs on templateInt_mycomp {
+  var integer v1 := -20, v2 := 4, v3 := 7;
+  if (not match(v1, mpt_implication)) {
+    setverdict(fail, match(v1, mpt_implication));
+  }
+  if (match(v2, mpt_implication)) {
+    setverdict(fail, match(v2, mpt_implication));
+  }
+  if (not match(v3, mpt_implication)) {
+    setverdict(fail, match(v3, mpt_implication));
+  }
+  setverdict(pass);
+}
+
+type record of integer IntList;
+
+testcase templateIntConjunctionAllFrom() runs on templateInt_mycomp {
+  var IntList v_list := { 1, 2, 3 };
+  // vt_conjunction does not match any value as no value can be 1, 2 and 3 at the same time.
+  var template integer vt_conjunction := conjunct(all from v_list);
+  var integer v1 := 1, v2 := 2, v3 := 3, v4 := 4;
+  if (match(v1, vt_conjunction)) {
+    setverdict(fail, match(v1, vt_conjunction));
+  }
+  if (match(v2, vt_conjunction)) {
+    setverdict(fail, match(v2, vt_conjunction));
+  }
+  if (match(v3, vt_conjunction)) {
+    setverdict(fail, match(v3, vt_conjunction));
+  }
+  if (match(v4, vt_conjunction)) {
+    setverdict(fail, match(v4, vt_conjunction));
+  }
+  
+  // vt_conjunction matches the single value 2
+  var template IntList vt_list := { 2, 2, 2 };
+  vt_conjunction := conjunct(all from vt_list);
+  if (match(v1, vt_conjunction)) {
+    setverdict(fail, match(v1, vt_conjunction));
+  }
+  if (not match(v2, vt_conjunction)) {
+    setverdict(fail, match(v2, vt_conjunction));
+  }
+  setverdict(pass);
+}
+
+testcase templateIntImplicationAllFrom() runs on templateInt_mycomp {
+  var IntList v_list1 := { 1, 2, 3 }, v_list2 := { 2, 3 };
+  var template integer vt_implication := (0, all from v_list1) implies (all from v_list2);
+  var integer v1 := 4, v2 := 1, v3 := 3;
+  if (not match(v1, vt_implication)) {
+    setverdict(fail, match(v1, vt_implication));
+  }
+  if (match(v2, vt_implication)) {
+    setverdict(fail, match(v2, vt_implication));
+  }
+  if (not match(v3, vt_implication)) {
+    setverdict(fail, match(v3, vt_implication));
+  }
+  setverdict(pass);
+}
+
+
 control {
  execute(templateIntSpec());
  execute(templateIntList());
@@ -517,5 +651,12 @@ control {
  execute(templateIntConjunction());
  execute(templateIntImplication());
  execute(templateIntDynamic());
+ execute(templateIntConjunctionDefPar());
+ execute(templateIntImplicationDefPar());
+ execute(templateIntDynamicDefPar());
+ execute(templateIntConjunctionModulepar());
+ execute(templateIntImplicationModulepar());
+ execute(templateIntConjunctionAllFrom());
+ execute(templateIntImplicationAllFrom());
 }
 }
diff --git a/regression_test/templateInt/config.cfg b/regression_test/templateInt/config.cfg
index 25bcac43b..930486477 100644
--- a/regression_test/templateInt/config.cfg
+++ b/regression_test/templateInt/config.cfg
@@ -8,9 +8,12 @@
 # Contributors:
 #   Balasko, Jeno
 #   Szabo, Janos Zoltan – initial implementation
+#   Baranyi, Botond
 #
 ###############################################################################
 [MODULE_PARAMETERS]
+mpt_conjunction := conjunct((100..infinity), (0..200))
+mpt_implication := (0..infinity) implies 10 - 3
 [LOGGING]
 Logfile := "templateInt.log"
 FileMask := LOG_ALL
diff --git a/regression_test/templateRecof/TtemplateRecof.ttcn b/regression_test/templateRecof/TtemplateRecof.ttcn
index e65ad6559..29c33d333 100644
--- a/regression_test/templateRecof/TtemplateRecof.ttcn
+++ b/regression_test/templateRecof/TtemplateRecof.ttcn
@@ -709,6 +709,34 @@ testcase templateRecofDynamic() runs on mycomp {
   setverdict(pass);
 }
 
+modulepar template IntList mpt_conjunction;
+modulepar template IntList mpt_implication;
+
+testcase templateRecofConjunctionModulepar() runs on mycomp {
+  var IntList v1 := { 1, 2, 3 }, v2 := { 1, 0, 2, 2, 1 };
+  if (not match(v1, mpt_conjunction)) {
+    setverdict(fail, match(v1, mpt_conjunction));
+  }
+  if (match(v2, mpt_conjunction)) {
+    setverdict(fail, match(v2, mpt_conjunction));
+  }
+  setverdict(pass);
+}
+
+testcase templateRecofImplicationModulepar() runs on mycomp {
+  var IntList v1 := { -1, -2 }, v2 := { 0, 2, 0, 1 }, v3 := { 1, 0 };
+  if (not match(v1, mpt_implication)) {
+    setverdict(fail, match(v1, mpt_implication));
+  }
+  if (match(v2, mpt_implication)) {
+    setverdict(fail, match(v2, mpt_implication));
+  }
+  if (not match(v3, mpt_implication)) {
+    setverdict(fail, match(v3, mpt_implication));
+  }
+  setverdict(pass);
+}
+
 
 control {
  execute(templateRecofSpec());
@@ -743,5 +771,7 @@ control {
  execute(templateRecofConjunction());
  execute(templateRecofImplication());
  execute(templateRecofDynamic());
+ execute(templateRecofConjunctionModulepar());
+ execute(templateRecofImplicationModulepar());
 }
 }
diff --git a/regression_test/templateRecof/config.cfg b/regression_test/templateRecof/config.cfg
index b492f30c8..350ebf2bd 100644
--- a/regression_test/templateRecof/config.cfg
+++ b/regression_test/templateRecof/config.cfg
@@ -13,6 +13,8 @@
 ###############################################################################
 [MODULE_PARAMETERS]
 mpt_roi := { permutation(1,2,3), 10 }
+mpt_conjunction := conjunct({ 1, * }, ? length (2..4))
+mpt_implication := { *, 0, * } implies ? length (1..3)
 [LOGGING]
 Logfile := "templateRecof.log"
 FileMask := LOG_ALL
-- 
GitLab