Merge "fixed self-ref check to no longer display errors for omit values (bug 498430)"
[deliverable/titan.core.git] / compiler2 / union.c
index c24f22360732af3c2541a63ecf89ef2f353d47e1..72dbbd068468ffe0dc0d02281738ee9fc6a59afe 100644 (file)
@@ -1,10 +1,31 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright (c) 2000-2014 Ericsson Telecom AB
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the Eclipse Public License v1.0
-// which accompanies this distribution, and is available at
-// http://www.eclipse.org/legal/epl-v10.html
-///////////////////////////////////////////////////////////////////////////////
+/******************************************************************************
+ * Copyright (c) 2000-2016 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Baji, Laszlo
+ *   Balasko, Jeno
+ *   Baranyi, Botond
+ *   Beres, Szabolcs
+ *   Cserveni, Akos
+ *   Delic, Adam
+ *   Feher, Csaba
+ *   Forstner, Matyas
+ *   Kovacs, Ferenc
+ *   Kremer, Peter
+ *   Ormandi, Matyas
+ *   Pandi, Krisztian
+ *   Raduly, Csaba
+ *   Szabados, Kristof
+ *   Szabo, Bence Janos
+ *   Szabo, Janos Zoltan – initial implementation
+ *   Szalai, Gabor
+ *   Pandi, Krisztian
+ *
+ ******************************************************************************/
 #include <string.h>
 
 #include "../common/memory.h"
@@ -115,10 +136,22 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
     "{\n"
     "switch (other_value.union_selection) {\n", name, name);
   for (i = 0; i < sdef->nElements; i++) {
-    src = mputprintf(src, "case %s_%s:\n"
-      "field_%s = new %s(*other_value.field_%s);\n"
-      "break;\n", selection_prefix, sdef->elements[i].name,
+    src = mputprintf(src, "case %s_%s:\n", selection_prefix, sdef->elements[i].name);
+    if (legacy_unbound_union_fields) {
+      src = mputprintf(src, "if (other_value.field_%s->is_bound()) ",
+        sdef->elements[i].name);
+    }
+    src = mputprintf(src, "field_%s = new %s(*other_value.field_%s);\n",
       sdef->elements[i].name, sdef->elements[i].type, sdef->elements[i].name);
+    if (legacy_unbound_union_fields) {
+      src = mputprintf(src,
+        "else {\n"
+        "field_%s = new %s;\n"
+        "TTCN_warning(\"Assignment of a union value with an unbound selected "
+        "alternative\");\n"      
+        "}\n", sdef->elements[i].name, sdef->elements[i].type);
+    }
+    src = mputstr(src, "break;\n");
   }
   src = mputprintf(src, "default:\n"
     "TTCN_error(\"Assignment of an unbound union value of type %s.\");\n"
@@ -352,22 +385,88 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
      "param.error(\"Field `%%s' not found in union type `%s'\", param_field);\n"
      "  }\n"
      "  param.basic_check(Module_Param::BC_VALUE, \"union value\");\n"
-     "  if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) return;\n"
-     "  if (param.get_type()!=Module_Param::MP_Assignment_List) {\n"
+     "  Module_Param_Ptr m_p = &param;\n"
+     "  if (param.get_type() == Module_Param::MP_Reference) {\n"
+     "    m_p = param.get_referenced_param();\n"
+     "  }\n"
+     "  if (m_p->get_type()==Module_Param::MP_Value_List && m_p->get_size()==0) return;\n"
+     "  if (m_p->get_type()!=Module_Param::MP_Assignment_List) {\n"
      "    param.error(\"union value with field name was expected\");\n"
      "  }\n"
-     "  Module_Param* mp_last = param.get_elem(param.get_size()-1);\n", dispname);
+     "  Module_Param* mp_last = m_p->get_elem(m_p->get_size()-1);\n", dispname);
 
-    for (i = 0; i < sdef->nElements; i++) {
+  for (i = 0; i < sdef->nElements; i++) {
     src = mputprintf(src, 
       "  if (!strcmp(mp_last->get_id()->get_name(), \"%s\")) {\n"
       "    %s%s().set_param(*mp_last);\n"
-      "    return;\n"
-      "  }\n", sdef->elements[i].dispname, at_field, sdef->elements[i].name);
+      "    if (!%s%s().is_bound()) "
+      , sdef->elements[i].dispname, at_field, sdef->elements[i].name
+      , at_field, sdef->elements[i].name);
+    if (legacy_unbound_union_fields) {
+      src = mputprintf(src,
+        "TTCN_warning(\"Alternative '%s' was selected for union of type '%s', "
+        "but its value is unbound\");\n"
+        , sdef->elements[i].dispname, sdef->dispname);
     }
+    else {
+      // a union's alternative cannot be unbound
+      src = mputstr(src, "clean_up();\n");
+    }
+    src = mputstr(src,
+      "    return;\n"
+      "  }\n");
+  }
   src = mputprintf(src,
     "  mp_last->error(\"Field %%s does not exist in type %s.\", mp_last->get_id()->get_name());\n"
     "}\n\n", dispname);
+  
+  /* get param function */
+  def = mputstr(def, "Module_Param* get_param(Module_Param_Name& param_name) const;\n");
+  src = mputprintf(src,
+    "Module_Param* %s::get_param(Module_Param_Name& param_name) const\n"
+    "{\n"
+    "  if (!is_bound()) {\n"
+    "    return new Module_Param_Unbound();\n"
+    "  }\n"
+    "  if (param_name.next_name()) {\n"
+    // Haven't reached the end of the module parameter name
+    // => the name refers to one of the fields, not to the whole union
+    "    char* param_field = param_name.get_current_name();\n"
+    "    if (param_field[0] >= '0' && param_field[0] <= '9') {\n"
+    "      TTCN_error(\"Unexpected array index in module parameter reference, \"\n"
+    "        \"expected a valid field name for union type `%s'\");\n"
+    "    }\n"
+    "    ", name, dispname);
+  for (i = 0; i < sdef->nElements; i++) {
+    src = mputprintf(src,
+     "if (strcmp(\"%s\", param_field) == 0) {\n"
+     "      return %s%s().get_param(param_name);\n"
+     "    } else ",
+     sdef->elements[i].dispname, at_field, sdef->elements[i].name);
+  }
+  src = mputprintf(src,
+    "TTCN_error(\"Field `%%s' not found in union type `%s'\", param_field);\n"
+    "  }\n"
+    "  Module_Param* mp_field = NULL;\n"
+    "  switch(union_selection) {\n"
+    , name);
+    for (i = 0; i < sdef->nElements; ++i) {
+      src = mputprintf(src, 
+        "  case %s_%s:\n"
+        "    mp_field = field_%s->get_param(param_name);\n"
+        "    mp_field->set_id(new Module_Param_FieldName(mcopystr(\"%s\")));\n"
+        "    break;\n"
+        , selection_prefix, sdef->elements[i].name
+        , sdef->elements[i].name, sdef->elements[i].dispname);
+    }
+  src = mputstr(src,
+    "  default:\n"
+    "    break;\n"
+    "  }\n"
+    "  Module_Param_Assignment_List* m_p = new Module_Param_Assignment_List();\n"
+    "  m_p->add_elem(mp_field);\n"
+    "  return m_p;\n"
+    "}\n\n");
 
   /* set implicit omit function, recursive */
   def = mputstr(def, "  void set_implicit_omit();\n");
@@ -751,8 +850,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
     for (i = 0; i < sdef->nElements; i++) {
       if ((tag_type[i] > 0)
         && (sdef->raw.taglist.list + tag_type[i] - 1)->nElements) {
-        src = mputstr(src, "    boolean already_failed = FALSE;\n"
-          "    raw_order_t local_top_order;\n");
+        src = mputstr(src, "    boolean already_failed = FALSE;\n");
         break;
       }
     }
@@ -833,17 +931,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
             }
             if (temp_variable_list[variable_index].decoded_for_element
               == -1) {
-              src = mputstr(src, "     ");
-              for (k = cur_field_list->nElements - 1; k > 0; k--) {
-                src = mputprintf(src,
-                  " if(%s_descr_.raw->top_bit_order==TOP_BIT_RIGHT)"
-                    "local_top_order=ORDER_MSB;\n"
-                    "      else if(%s_descr_.raw->top_bit_order==TOP_BIT_LEFT)"
-                    "local_top_order=ORDER_LSB;\n"
-                    "      else", cur_field_list->fields[k - 1].typedescr,
-                  cur_field_list->fields[k - 1].typedescr);
-              }
-              src = mputprintf(src, " local_top_order=top_bit_ord;\n"
+              src = mputprintf(src,
                 "      p_buf.set_pos_bit(starting_pos + %d);\n"
                 "      decoded_%lu_length = temporal_%lu.RAW_decode("
                 "%s_descr_, p_buf, limit, top_bit_ord, TRUE);\n",
@@ -1306,7 +1394,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
 
     src = mputprintf(src, /* XERSTUFF XER_encode for union */
       "int %s::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, "
-      "unsigned int p_flavor, int p_indent) const\n"
+      "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n"
       "{\n"
       "%s"
       "  if (%s==union_selection) {\n"
@@ -1318,7 +1406,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       "  int encoded_length=(int)p_buf.get_len();\n"
       , name
       , (use_runtime_2 ? "  if (err_descr) return XER_encode_negtest"
-        "(err_descr, p_td, p_buf, p_flavor, p_indent);\n" : "")
+        "(err_descr, p_td, p_buf, p_flavor, p_indent, 0);\n" : "")
       , unbound_value
     );
 
@@ -1326,9 +1414,8 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       src = mputstr(src,
         "  const boolean e_xer = is_exer(p_flavor);\n"
         "  char *type_atr = NULL;\n"
-        "  unsigned short name_len = 0;\n"
         "  if (e_xer && (p_td.xer_bits & USE_TYPE_ATTR)) {\n"
-        "    const char *type_name = 0;\n"
+        "    char *type_name = 0;\n"
         "    const namespace_t *control_ns;\n"
         "    switch (union_selection) {\n");
       /* In case of USE-TYPE the first field won't need the type attribute */
@@ -1336,24 +1423,34 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       for (i = start_at; i < sdef->nElements; i++) {
         src = mputprintf(src,
           "    case %s_%s:\n"
-          "      type_name = %s_xer_.names[1];\n"
-          "      name_len  = %s_xer_.namelens[1] - 2;\n"
+          "      if (%s_xer_.my_module != 0 && %s_xer_.ns_index != -1 &&\n"
+          "          %s_xer_.namelens[1] > 2) {\n"
+          /* add the namespace prefix to the type attribute (if the name is not empty) */
+          "        const namespace_t *my_ns = %s_xer_.my_module->get_ns(%s_xer_.ns_index);\n"
+          "        if (my_ns->px[0] != 0) {\n"
+          "          type_name = mprintf(\"%%s:\", my_ns->px);\n"
+          "        }\n"
+          "      }\n"
+          "      type_name = mputstrn(type_name, %s_xer_.names[1], %s_xer_.namelens[1] - 2);\n"
           "      %s\n"
           , selection_prefix, sdef->elements[i].name
-          , sdef->elements[i].typegen
+          , sdef->elements[i].typegen, sdef->elements[i].typegen
+          , sdef->elements[i].typegen, sdef->elements[i].typegen
+          , sdef->elements[i].typegen, sdef->elements[i].typegen
           , sdef->elements[i].typegen
           , i < sdef->nElements - 1 ? "goto write_atr;" : "" /* no break */
         );
       }
       src = mputprintf(src,
         "%s" /* label only if more than two elements total */
-        "      if (name_len > 0) {\n" /* 38.3.8, no atr if NAME AS "" */
+        "      if (mstrlen(type_name) > 0) {\n" /* 38.3.8, no atr if NAME AS "" */
         "        control_ns = p_td.my_module->get_controlns();\n"
         "        type_atr = mcopystr(\" \");\n"
-        "        type_atr = mputstr (type_atr, control_ns->px);\n"
-        "        type_atr = mputstr (type_atr, \":type='\");\n"
-        "        type_atr = mputstrn(type_atr, type_name, name_len);\n"
-        "        type_atr = mputc   (type_atr, '\\'');\n"
+        "        type_atr = mputstr(type_atr, control_ns->px);\n"
+        "        type_atr = mputstr(type_atr, \":type='\");\n"
+        "        type_atr = mputstr(type_atr, type_name);\n"
+        "        type_atr = mputc  (type_atr, '\\'');\n"
+        "        Free(type_name);\n"
         "      }\n"
         "      break;\n"
         "    default: break;\n"
@@ -1380,7 +1477,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       src = mputprintf(src, "  case %s_%s:\n"
        "    ec_1.set_msg(\"%s': \");\n"
        "    field_%s->XER_encode(%s_xer_, p_buf, flavor_0, "
-       "p_indent + (!p_indent || !omit_tag));\n"
+       "p_indent + (!p_indent || !omit_tag), 0);\n"
        "    break;\n",
        selection_prefix, sdef->elements[i].name,
        sdef->elements[i].dispname,
@@ -1403,11 +1500,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       def = mputstr(def,
         "int XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, "
         "const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, "
-        "unsigned int p_flavor, int p_indent) const;\n");
+        "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const;\n");
       src = mputprintf(src, /* XERSTUFF XER_encode for union */
         "int %s::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr, "
         "const XERdescriptor_t& p_td, TTCN_Buffer& p_buf, "
-        "unsigned int p_flavor, int p_indent) const\n"
+        "unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n"
         "{\n"
         "  if (%s==union_selection) {\n"
         "    TTCN_error(\"Attempt to XER-encode an unbound union value.\");\n"
@@ -1423,33 +1520,42 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         src = mputstr(src,
           "  const boolean e_xer = is_exer(p_flavor);\n"
           "  char *type_atr = NULL;\n"
-          "  unsigned short name_len = 0;\n"
           "  if (e_xer && (p_td.xer_bits & USE_TYPE_ATTR)) {\n"
-          "    const char *type_name = 0;\n"
+          "    char *type_name = 0;\n"
           "    const namespace_t *control_ns;\n"
           "    switch (union_selection) {\n");
         int start_at = sdef->xerUseUnion ? 0 : 1;
         for (i = start_at; i < sdef->nElements; i++) {
           src = mputprintf(src,
             "    case %s_%s:\n"
-            "      type_name = %s_xer_.names[1];\n"
-            "      name_len  = %s_xer_.namelens[1] - 2;\n"
+            "      if (%s_xer_.my_module != 0 && %s_xer_.ns_index != -1 &&\n"
+            "          %s_xer_.namelens[1] > 2) {\n"
+            /* add the namespace prefix to the type attribute (if the name is not empty) */
+            "        const namespace_t *my_ns = %s_xer_.my_module->get_ns(%s_xer_.ns_index);\n"
+            "        if (my_ns->px[0] != 0) {\n"
+            "          type_name = mprintf(\"%%s:\", my_ns->px);\n"
+            "        }\n"
+            "      }\n"
+            "      type_name = mputstrn(type_name, %s_xer_.names[1], %s_xer_.namelens[1] - 2);\n"
             "      %s\n"
             , selection_prefix, sdef->elements[i].name
-            , sdef->elements[i].typegen
+            , sdef->elements[i].typegen, sdef->elements[i].typegen
+            , sdef->elements[i].typegen, sdef->elements[i].typegen
+            , sdef->elements[i].typegen, sdef->elements[i].typegen
             , sdef->elements[i].typegen
             , i < sdef->nElements - 1 ? "goto write_atr;" : "" /* no break */
           );
         }
         src = mputprintf(src,
           "%s" /* label only if more than two elements total */
-          "      if (name_len > 0) {\n" /* 38.3.8, no atr if NAME AS "" */
+          "      if (mstrlen(type_name) > 0) {\n" /* 38.3.8, no atr if NAME AS "" */
           "        control_ns = p_td.my_module->get_controlns();\n"
           "        type_atr = mcopystr(\" \");\n"
-          "        type_atr = mputstr (type_atr, control_ns->px);\n"
-          "        type_atr = mputstr (type_atr, \":type='\");\n"
-          "        type_atr = mputstrn(type_atr, type_name, name_len);\n"
-          "        type_atr = mputc   (type_atr, '\\'');\n"
+          "        type_atr = mputstr(type_atr, control_ns->px);\n"
+          "        type_atr = mputstr(type_atr, \":type='\");\n"
+          "        type_atr = mputstr(type_atr, type_name);\n"
+          "        type_atr = mputc  (type_atr, '\\'');\n"
+          "        Free(type_name);\n"
           "      }\n"
           "      break;\n"
           "    default: break;\n"
@@ -1486,15 +1592,15 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
           "(\"internal error: erroneous value typedescriptor missing\");\n"
           "          else err_vals->value->errval->XER_encode("
           "*err_vals->value->type_descr->xer, p_buf, flavor_0, "
-          "p_indent + (!p_indent || !omit_tag));\n"
+          "p_indent + (!p_indent || !omit_tag), 0);\n"
           "        }\n"
           "      }\n"
           "    } else {\n"
           "      ec_1.set_msg(\"%s': \");\n"
           "      if (emb_descr) field_%s->XER_encode_negtest(emb_descr, "
-          "%s_xer_, p_buf, flavor_0, p_indent + (!p_indent || !omit_tag));\n"
+          "%s_xer_, p_buf, flavor_0, p_indent + (!p_indent || !omit_tag), 0);\n"
           "      else field_%s->XER_encode(%s_xer_, p_buf, flavor_0, "
-          "p_indent + (!p_indent || !omit_tag));\n"
+          "p_indent + (!p_indent || !omit_tag), 0);\n"
           "    }\n"
           "    break;\n",
           selection_prefix, sdef->elements[i].name, /* case label */
@@ -1533,7 +1639,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
 #endif
     src = mputprintf(src, /* XERSTUFF decoder functions for union */
       "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader,"
-      " unsigned int p_flavor)\n"
+      " unsigned int p_flavor, unsigned int p_flavor2, embed_values_dec_struct_t*)\n"
       "{\n"
       "  int e_xer = is_exer(p_flavor);\n"
       "  int type = 0;\n" /* None */
@@ -1576,8 +1682,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         /* USE-TYPE: No type attribute means the first alternative */
         src = mputprintf(src,
           "        if (typeatr == NULL) {\n"
-          "          typeatr = mcopystr(%s_xer_.names[1]);\n"
-          "          typeatr = mtruncstr(typeatr, %s_xer_.namelens[1] - 2);\n"
+          "          typeatr = mcopystrn(%s_xer_.names[1], %s_xer_.namelens[1] - 2);\n"
           "        }\n"
           , sdef->elements[0].typegen
           , sdef->elements[0].typegen);
@@ -1616,7 +1721,15 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
     if (sdef->xerUseTypeAttr) {
       src = mputstr(src,
         "    if (e_xer) {\n" /* USE-TYPE => no XML element, use typeatr */
-        "      elem_name = typeatr;\n"
+        "      char *token_1 = strtok(typeatr, \":\");\n" /* extract the namespace (if any) */
+        "      char *token_2 = strtok(NULL, \":\");\n"
+        "      if (token_2) {\n" /* namespace found */
+        "        elem_name = token_2;\n"
+        "        ns_uri = get_ns_uri_from_prefix(token_1, p_td);\n"
+        "      }\n"
+        "      else {\n" /* no namespace */
+        "        elem_name = token_1;\n"
+        "      }\n"
         "      flavor_1 |= USE_TYPE_ATTR;\n"
         "    }\n"
         "    else" /* no newline, gobbles up the next {} */);
@@ -1643,7 +1756,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
           "      ec_2.set_msg(\"%s': \");\n"
           "      if (%s==union_selection) {\n"
           "        matched = %d;\n"
-          "        %s().XER_decode(%s_xer_, p_reader, flavor_1);\n"
+          "        %s().XER_decode(%s_xer_, p_reader, flavor_1, p_flavor2, 0);\n"
           "      }\n"
           "      if (field_%s->is_bound()) break; else clean_up();\n"
           "    }\n",
@@ -1696,7 +1809,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
           src = mputprintf(src,
             "    %sif (%s::can_start(elem_name, ns_uri, %s_xer_, flavor_1) || (%s_xer_.xer_bits & ANY_ELEMENT)) {\n"
             "      ec_2.set_msg(\"%s': \");\n"
-            "      %s%s().XER_decode(%s_xer_, p_reader, flavor_1);\n"
+            "      if (e_xer && (%s_xer_.xer_bits & BLOCKED)) {\n"
+            "        TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG,\n"
+            "          \"Attempting to decode blocked or abstract field.\");\n"
+            "      }\n"
+            "      %s%s().XER_decode(%s_xer_, p_reader, flavor_1, p_flavor2, 0);\n"
             "      if (!%s%s().is_bound()) {\n"
             "        TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, \"Failed to decode field.\");\n"
             "      }\n"
@@ -1704,6 +1821,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
             i && !(i==1 && sdef->exerMaybeEmptyIndex==0) ? "else " : "",  /*  print "if(" if generate code for the first field or if the first field is the MaybeEmpty field and we generate the code for the second one*/
             sdef->elements[i].type, sdef->elements[i].typegen, sdef->elements[i].typegen,
             sdef->elements[i].dispname,
+            sdef->elements[i].typegen,
             at_field, sdef->elements[i].name,    sdef->elements[i].typegen,
             at_field, sdef->elements[i].name);
           }
@@ -1713,7 +1831,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         src = mputprintf(src,
           "    %sif ((e_xer && (type==XML_READER_TYPE_END_ELEMENT || !own_tag)) || %s::can_start(elem_name, ns_uri, %s_xer_, flavor_1) || (%s_xer_.xer_bits & ANY_ELEMENT)) {\n"
           "empty_xml:  ec_2.set_msg(\"%s': \");\n"
-          "      %s%s().XER_decode(%s_xer_, p_reader, flavor_1);\n"
+          "      if (e_xer && (%s_xer_.xer_bits & BLOCKED)) {\n"
+          "        TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG,\n"
+          "          \"Attempting to decode blocked or abstract field.\");\n"
+          "      }\n"
+          "      %s%s().XER_decode(%s_xer_, p_reader, flavor_1, p_flavor2, 0);\n"
           "      if (!%s%s().is_bound()) {\n"
           "        TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, \"Failed to decode field.\");\n"
           "      }\n"
@@ -1721,18 +1843,21 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
           sdef->nElements>0 ? "else " : "",
           sdef->elements[i].type, sdef->elements[i].typegen, sdef->elements[i].typegen,
           sdef->elements[i].dispname,
+          sdef->elements[i].typegen,
           at_field, sdef->elements[i].name,    sdef->elements[i].typegen,
           at_field, sdef->elements[i].name);
       }
-      src = mputstr(src,
-        "    else {\n"
-        "      ec_1.set_msg(\" \");\n"
-        "      TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "
-        "\"'%s' does not match any alternative\", elem_name);\n"
-        "      if (xml_depth >= 0) for (; rd_ok == 1 "
-        "&& p_reader.Depth() > xml_depth; rd_ok = p_reader.Read()) ;\n"
-        "    }\n"
-        );
+      if (!sdef->isOptional) {
+        src = mputstr(src,
+          "    else {\n"
+          "      ec_1.set_msg(\" \");\n"
+          "      TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "
+          "\"'%s' does not match any alternative\", elem_name);\n"
+          "      if (xml_depth >= 0) for (; rd_ok == 1 "
+          "&& p_reader.Depth() > xml_depth; rd_ok = p_reader.Read()) ;\n"
+          "    }\n"
+          );
+      }
     }
 
     src = mputprintf(src,
@@ -1754,8 +1879,11 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
   if (json_needed) {
     // JSON encode
     src = mputprintf(src,
-      "int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n"
-      "{\n", name);
+      "int %s::JSON_encode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok) const\n"
+      "{\n", name, use_runtime_2 ? " p_td" : "");
+    if (use_runtime_2) {
+      src = mputstr(src, "  if (err_descr) return JSON_encode_negtest(err_descr, p_td, p_tok);\n");
+    }
     if (!sdef->jsonAsValue) {
       src = mputstr(src, "  int enc_len = p_tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL);\n\n");
     } else {
@@ -1788,18 +1916,90 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       "  return enc_len;\n"
       "}\n\n");
     
+    if (use_runtime_2) {
+      // JSON encode for negative testing
+      def = mputstr(def,
+        "int JSON_encode_negtest(const Erroneous_descriptor_t*, "
+        "const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const;\n");
+      src = mputprintf(src,
+        "int %s::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_descr, "
+        "const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n"
+        "{\n", name);
+      if (!sdef->jsonAsValue) {
+        src = mputstr(src, "  int enc_len = p_tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL);\n\n");
+      } else {
+        src = mputstr(src, "  int enc_len = 0;\n\n");
+      }
+      src = mputstr(src,
+        "  const Erroneous_values_t* err_vals = NULL;\n"
+        "  const Erroneous_descriptor_t* emb_descr = NULL;\n"
+        "  switch(union_selection) {\n");
+        
+      for (i = 0; i < sdef->nElements; ++i) {
+        src = mputprintf(src, 
+          "  case %s_%s:\n"
+          "    err_vals = p_err_descr->get_field_err_values(%d);\n"
+          "    emb_descr = p_err_descr->get_field_emb_descr(%d);\n"
+          "    if (NULL != err_vals && NULL != err_vals->value) {\n"
+          "      if (NULL != err_vals->value->errval) {\n"
+          "        if(err_vals->value->raw){\n"
+          "          enc_len += err_vals->value->errval->JSON_encode_negtest_raw(p_tok);\n"
+          "        } else {\n"
+          "          if (NULL == err_vals->value->type_descr) {\n"
+          "            TTCN_error(\"internal error: erroneous value typedescriptor missing\");\n"
+          "          }\n"
+          , selection_prefix, sdef->elements[i].name, (int)i, (int)i);
+        if (!sdef->jsonAsValue) {
+          src = mputprintf(src, "          enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, \"%s\");\n"
+            , sdef->elements[i].jsonAlias ? sdef->elements[i].jsonAlias : sdef->elements[i].dispname);
+        }
+        src = mputstr(src,
+          "          enc_len += err_vals->value->errval->JSON_encode(*err_vals->value->type_descr, p_tok);\n"
+          "        }\n"
+          "      }\n"
+          "    } else {\n");
+        if (!sdef->jsonAsValue) {
+          src = mputprintf(src, "      enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, \"%s\");\n"
+            , sdef->elements[i].jsonAlias ? sdef->elements[i].jsonAlias : sdef->elements[i].dispname);
+        }
+        src = mputprintf(src,
+          "      if (NULL != emb_descr) {\n"
+          "        enc_len += field_%s->JSON_encode_negtest(emb_descr, %s_descr_, p_tok);\n"
+          "      } else {\n"
+          "        enc_len += field_%s->JSON_encode(%s_descr_, p_tok);\n"
+          "      }\n"
+          "    }\n"
+          "    break;\n"
+          , sdef->elements[i].name, sdef->elements[i].typedescrname
+          , sdef->elements[i].name, sdef->elements[i].typedescrname);
+      }
+      src = mputprintf(src, 
+        "  default:\n"
+        "    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, \n"
+        "      \"Encoding an unbound value of type %s.\");\n"
+        "    return -1;\n"
+        "  }\n\n"
+        , dispname);
+      if (!sdef->jsonAsValue) {
+        src = mputstr(src, "  enc_len += p_tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL);\n");
+      }
+      src = mputstr(src,
+        "  return enc_len;\n"
+        "}\n\n");
+    }
+    
     // JSON decode
     src = mputprintf(src,
-      "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)\n"
+      "int %s::JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean p_silent)\n"
       "{\n"
-      "  json_token_t token = JSON_TOKEN_NONE;\n"
+      "  json_token_t j_token = JSON_TOKEN_NONE;\n"
       , name);
     if (sdef->jsonAsValue) {
       src = mputstr(src,
         "  size_t buf_pos = p_tok.get_buf_pos();\n"
-        "  p_tok.get_next_token(&token, NULL, NULL);\n"
+        "  p_tok.get_next_token(&j_token, NULL, NULL);\n"
         "  int ret_val = 0;\n"
-        "  switch(token) {\n"
+        "  switch(j_token) {\n"
         "  case JSON_TOKEN_NUMBER: {\n");
       for (i = 0; i < sdef->nElements; ++i) {
         if (JSON_NUMBER & sdef->elements[i].jsonValueType) {
@@ -1835,10 +2035,9 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         "    return JSON_ERROR_FATAL;\n"
         "  }\n"
         "  case JSON_TOKEN_LITERAL_TRUE:\n"
-        "  case JSON_TOKEN_LITERAL_FALSE:\n"
-        "  case JSON_TOKEN_LITERAL_NULL: {\n");
+        "  case JSON_TOKEN_LITERAL_FALSE: {\n");
       for (i = 0; i < sdef->nElements; ++i) {
-        if (JSON_LITERAL & sdef->elements[i].jsonValueType) {
+        if (JSON_BOOLEAN & sdef->elements[i].jsonValueType) {
           src = mputprintf(src,
             "    p_tok.set_buf_pos(buf_pos);\n"
             "    ret_val = %s%s().JSON_decode(%s_descr_, p_tok, true);\n"
@@ -1849,11 +2048,10 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         }
       }
       src = mputstr(src,
-        "    char* literal = mprintf(\"literal (%s)\",\n"
-        "      (JSON_TOKEN_LITERAL_TRUE == token) ? \"true\" :\n"
-        "      ((JSON_TOKEN_LITERAL_FALSE == token) ? \"false\" : \"null\"));\n"
-        "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_AS_VALUE_ERROR, literal);\n"
-        "    Free(literal);\n"
+        "    char* literal_str = mprintf(\"literal (%s)\",\n"
+        "      (JSON_TOKEN_LITERAL_TRUE == j_token) ? \"true\" : \"false\");\n"
+        "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_AS_VALUE_ERROR, literal_str);\n"
+        "    Free(literal_str);\n"
         "    clean_up();\n"
         "    return JSON_ERROR_FATAL;\n"
         "  }\n"
@@ -1891,6 +2089,24 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         "    clean_up();\n"
         "    return JSON_ERROR_FATAL;\n"
         "  }\n"
+        "  case JSON_TOKEN_LITERAL_NULL: {\n");
+      for (i = 0; i < sdef->nElements; ++i) {
+        if (JSON_NULL & sdef->elements[i].jsonValueType) {
+          src = mputprintf(src,
+            "    p_tok.set_buf_pos(buf_pos);\n"
+            "    ret_val = %s%s().JSON_decode(%s_descr_, p_tok, true);\n"
+            "    if (0 <= ret_val) {\n"
+            "      return ret_val;\n"
+            "    }\n"
+            , at_field, sdef->elements[i].name, sdef->elements[i].typedescrname);
+        }
+      }
+      src = mputstr(src,
+        "    clean_up();\n"
+        // the caller might be able to decode the null value if it's an optional field
+        // only return an invalid token error, not a fatal error
+        "    return JSON_ERROR_INVALID_TOKEN;\n"
+        "  }\n"
         "  case JSON_TOKEN_ERROR:\n"
         "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
         "    return JSON_ERROR_FATAL;\n"
@@ -1901,18 +2117,18 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         "}\n\n");
     } else { // not "as value"
       src = mputprintf(src,
-        "  int dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
-        "  if (JSON_TOKEN_ERROR == token) {\n"
+        "  int dec_len = p_tok.get_next_token(&j_token, NULL, NULL);\n"
+        "  if (JSON_TOKEN_ERROR == j_token) {\n"
         "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
         "    return JSON_ERROR_FATAL;\n"
         "  }\n"
-        "  else if (JSON_TOKEN_OBJECT_START != token) {\n"
+        "  else if (JSON_TOKEN_OBJECT_START != j_token) {\n"
         "    return JSON_ERROR_INVALID_TOKEN;\n"
         "  }\n\n"
-        "  char* name = 0;\n"
-        "  size_t name_len = 0;"
-        "  dec_len += p_tok.get_next_token(&token, &name, &name_len);\n"
-        "  if (JSON_TOKEN_NAME != token) {\n"
+        "  char* fld_name = 0;\n"
+        "  size_t name_len = 0;\n"
+        "  dec_len += p_tok.get_next_token(&j_token, &fld_name, &name_len);\n"
+        "  if (JSON_TOKEN_NAME != j_token) {\n"
         "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_NAME_TOKEN_ERROR);\n"
         "    return JSON_ERROR_FATAL;\n"
         "  } else {\n"
@@ -1920,7 +2136,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
         , unbound_value);
       for (i = 0; i < sdef->nElements; ++i) {
         src = mputprintf(src,
-          "if (0 == strncmp(name, \"%s\", name_len)) {\n"
+          "if (0 == strncmp(fld_name, \"%s\", name_len)) {\n"
           "      int ret_val = %s%s().JSON_decode(%s_descr_, p_tok, p_silent);\n"
           "      if (0 > ret_val) {\n"
           "        if (JSON_ERROR_INVALID_TOKEN) {\n"
@@ -1937,14 +2153,14 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
       }
       src = mputstr(src,
         "{\n"
-        "      char* name2 = mcopystrn(name, name_len);\n"
-        "      JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_INVALID_NAME_ERROR, name2);\n"
-        "      Free(name2);\n"
+        "      char* fld_name2 = mcopystrn(fld_name, name_len);\n"
+        "      JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_INVALID_NAME_ERROR, fld_name2);\n"
+        "      Free(fld_name2);\n"
         "      return JSON_ERROR_FATAL;\n"
         "    }\n"
         "  }\n\n"
-        "  dec_len += p_tok.get_next_token(&token, NULL, NULL);\n"
-        "  if (JSON_TOKEN_OBJECT_END != token) {\n"
+        "  dec_len += p_tok.get_next_token(&j_token, NULL, NULL);\n"
+        "  if (JSON_TOKEN_OBJECT_END != j_token) {\n"
         "    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_STATIC_OBJECT_END_TOKEN_ERROR, \"\");\n"
         "    return JSON_ERROR_FATAL;\n"
         "  }\n\n"
@@ -2223,9 +2439,10 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "}\n\n", name, name, name);
 
   /* match function */
-  def = mputprintf(def, "boolean match(const %s& other_value) const;\n", name);
-  src = mputprintf(src, "boolean %s_template::match(const %s& other_value) "
-      "const\n"
+  def = mputprintf(def, "boolean match(const %s& other_value, boolean legacy "
+    "= FALSE) const;\n", name);
+  src = mputprintf(src, "boolean %s_template::match(const %s& other_value, "
+    "boolean legacy) const\n"
     "{\n"
     "if (!other_value.is_bound()) return FALSE;\n"
     "switch (template_selection) {\n"
@@ -2242,7 +2459,7 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "switch (value_selection) {\n", name, name, selection_type, unbound_value);
   for (i = 0; i < sdef->nElements; i++) {
     src = mputprintf(src, "case %s_%s:\n"
-      "return single_value.field_%s->match(other_value.%s%s());\n",
+      "return single_value.field_%s->match(other_value.%s%s(), legacy);\n",
       selection_prefix, sdef->elements[i].name, sdef->elements[i].name,
       at_field, sdef->elements[i].name);
   }
@@ -2255,7 +2472,7 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "case COMPLEMENTED_LIST:\n"
     "for (unsigned int list_count = 0; list_count < value_list.n_values; "
       "list_count++)\n"
-    "if (value_list.list_value[list_count].match(other_value)) "
+    "if (value_list.list_value[list_count].match(other_value, legacy)) "
     "return template_selection == VALUE_LIST;\n"
     "return template_selection == COMPLEMENTED_LIST;\n"
     "default:\n"
@@ -2432,8 +2649,8 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
       "void copy_value(const Base_Type* other_value);\n"
       "Base_Template* clone() const;\n"
       "const TTCN_Typedescriptor_t* get_descriptor() const;\n"
-      "boolean matchv(const Base_Type* other_value) const;\n"
-      "void log_matchv(const Base_Type* match_value) const;\n");
+      "boolean matchv(const Base_Type* other_value, boolean legacy) const;\n"
+      "void log_matchv(const Base_Type* match_value, boolean legacy) const;\n");
     src = mputprintf(src,
       "void %s_template::valueofv(Base_Type* value) const "
         "{ *(static_cast<%s*>(value)) = valueof(); }\n"
@@ -2445,10 +2662,12 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
         "{ return new %s_template(*this); }\n"
       "const TTCN_Typedescriptor_t* %s_template::get_descriptor() const "
         "{ return &%s_descr_; }\n"
-      "boolean %s_template::matchv(const Base_Type* other_value) const "
-        "{ return match(*(static_cast<const %s*>(other_value))); }\n"
-      "void %s_template::log_matchv(const Base_Type* match_value) const "
-        " { log_match(*(static_cast<const %s*>(match_value))); }\n",
+      "boolean %s_template::matchv(const Base_Type* other_value, "
+        "boolean legacy) const "
+        "{ return match(*(static_cast<const %s*>(other_value)), legacy); }\n"
+      "void %s_template::log_matchv(const Base_Type* match_value, "
+        "boolean legacy) const "
+        " { log_match(*(static_cast<const %s*>(match_value)), legacy); }\n",
       name, name,
       name,
       name, name,
@@ -2498,12 +2717,13 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     src = mputstr(src, "}\n\n");
 
   /* log_match function */
-  def = mputprintf(def, "void log_match(const %s& match_value) "
-    "const;\n", name);
+  def = mputprintf(def, "void log_match(const %s& match_value, "
+    "boolean legacy = FALSE) const;\n", name);
   src = mputprintf(src,
-    "void %s_template::log_match(const %s& match_value) const\n"
+    "void %s_template::log_match(const %s& match_value, boolean legacy) const\n"
     "{\n"
-    "if(TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity() && match(match_value)){\n"
+    "if(TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity() "
+    "&& match(match_value, legacy)){\n"
     "TTCN_Logger::print_logmatch_buffer();\n"
     "TTCN_Logger::log_event_str(\" matched\");\n"
     "return;\n"
@@ -2515,10 +2735,10 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     src = mputprintf(src, "case %s_%s:\n"
     "if(TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity()){\n"
     "TTCN_Logger::log_logmatch_info(\".%s\");\n"
-    "single_value.field_%s->log_match(match_value.%s%s());\n"
+    "single_value.field_%s->log_match(match_value.%s%s(), legacy);\n"
     "} else {\n"
       "TTCN_Logger::log_event_str(\"{ %s := \");\n"
-      "single_value.field_%s->log_match(match_value.%s%s());\n"
+      "single_value.field_%s->log_match(match_value.%s%s(), legacy);\n"
     "TTCN_Logger::log_event_str(\" }\");\n"
     "}\n"
     "break;\n", selection_prefix, sdef->elements[i].name,
@@ -2536,7 +2756,7 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "match_value.log();\n"
     "TTCN_Logger::log_event_str(\" with \");\n"
     "log();\n"
-    "if (match(match_value)) TTCN_Logger::log_event_str(\" matched\");\n"
+    "if (match(match_value, legacy)) TTCN_Logger::log_event_str(\" matched\");\n"
     "else TTCN_Logger::log_event_str(\" unmatched\");\n"
     "}\n"
     "}\n\n");
@@ -2623,18 +2843,18 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "}\n\n", dispname, name, dispname);
 
   /* TTCN-3 ispresent() function */
-  def = mputstr(def, "boolean is_present() const;\n");
+  def = mputstr(def, "boolean is_present(boolean legacy = FALSE) const;\n");
   src = mputprintf(src,
-    "boolean %s_template::is_present() const\n"
+    "boolean %s_template::is_present(boolean legacy) const\n"
     "{\n"
     "if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE;\n"
-    "return !match_omit();\n"
+    "return !match_omit(legacy);\n"
     "}\n\n", name);
 
   /* match_omit() */
-  def = mputstr(def, "boolean match_omit() const;\n");
+  def = mputstr(def, "boolean match_omit(boolean legacy = FALSE) const;\n");
   src = mputprintf(src,
-    "boolean %s_template::match_omit() const\n"
+    "boolean %s_template::match_omit(boolean legacy) const\n"
     "{\n"
     "if (is_ifpresent) return TRUE;\n"
     "switch (template_selection) {\n"
@@ -2643,10 +2863,12 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "return TRUE;\n"
     "case VALUE_LIST:\n"
     "case COMPLEMENTED_LIST:\n"
+    "if (legacy) {\n"
     "for (unsigned int v_idx=0; v_idx<value_list.n_values; v_idx++)\n"
     "if (value_list.list_value[v_idx].match_omit())\n"
     "return template_selection==VALUE_LIST;\n"
     "return template_selection==COMPLEMENTED_LIST;\n"
+    "} // else fall through\n"
     "default:\n"
     "return FALSE;\n"
     "}\n"
@@ -2680,7 +2902,11 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "param.error(\"Field `%%s' not found in union template type `%s'\", param_field);\n"
     "  }\n"
     "  param.basic_check(Module_Param::BC_TEMPLATE, \"union template\");\n"
-    "  switch (param.get_type()) {\n"
+    "  Module_Param_Ptr m_p = &param;\n"
+    "  if (param.get_type() == Module_Param::MP_Reference) {\n"
+    "    m_p = param.get_referenced_param();\n"
+    "  }\n"
+    "  switch (m_p->get_type()) {\n"
     "  case Module_Param::MP_Omit:\n"
     "    *this = OMIT_VALUE;\n"
     "    break;\n"
@@ -2691,19 +2917,22 @@ 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"
-    "    set_type(param.get_type()==Module_Param::MP_List_Template ? VALUE_LIST : COMPLEMENTED_LIST, param.get_size());\n"
-    "    for (size_t p_i=0; p_i<param.get_size(); p_i++) {\n"
-    "      list_item(p_i).set_param(*param.get_elem(p_i));\n"
+    "  case Module_Param::MP_ComplementList_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"
+    "    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"
-    "    break;\n"
+    "    *this = new_temp;\n"
+    "    break; }\n"
     "  case Module_Param::MP_Value_List:\n"
-    "    if (param.get_size()==0) break;\n" /* for backward compatibility */
+    "    if (m_p->get_size()==0) break;\n" /* for backward compatibility */
     "    param.type_error(\"union template\", \"%s\");\n"
     "    break;\n"
     "  case Module_Param::MP_Assignment_List: {\n"
-    "    Module_Param* mp_last = param.get_elem(param.get_size()-1);\n",
-    dispname, dispname);
+    "    Module_Param* mp_last = m_p->get_elem(m_p->get_size()-1);\n",
+    dispname, name, dispname);
   for (i = 0; i < sdef->nElements; i++) {
     src = mputprintf(src, 
     "    if (!strcmp(mp_last->get_id()->get_name(), \"%s\")) {\n"
@@ -2717,15 +2946,94 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
     "  default:\n"
     "    param.type_error(\"union template\", \"%s\");\n"
     "  }\n"
-    "  is_ifpresent = param.get_ifpresent();\n"
+    "  is_ifpresent = param.get_ifpresent() || m_p->get_ifpresent();\n"
     "}\n\n", dispname, dispname);
+  
+  /* get_param() */
+  def = mputstr(def, "Module_Param* get_param(Module_Param_Name& param_name) const;\n");
+  src = mputprintf(src,
+    "Module_Param* %s_template::get_param(Module_Param_Name& param_name) const\n"
+    "{\n"
+    "  if (param_name.next_name()) {\n"
+    // Haven't reached the end of the module parameter name
+    // => the name refers to one of the fields, not to the whole union
+    "    char* param_field = param_name.get_current_name();\n"
+    "    if (param_field[0] >= '0' && param_field[0] <= '9') {\n"
+    "      TTCN_error(\"Unexpected array index in module parameter reference, \"\n"
+    "        \"expected a valid field name for union template type `%s'\");\n"
+    "    }\n"
+    "    ", name, dispname);
+  for (i = 0; i < sdef->nElements; i++) {
+    src = mputprintf(src,
+     "if (strcmp(\"%s\", param_field) == 0) {\n"
+     "      return %s%s().get_param(param_name);\n"
+     "    } else ",
+     sdef->elements[i].dispname, at_field, sdef->elements[i].name);
+  }
+  src = mputprintf(src,
+    "TTCN_error(\"Field `%%s' not found in union type `%s'\", param_field);\n"
+    "  }\n"
+    "  Module_Param* m_p = NULL;\n"
+    "  switch (template_selection) {\n"
+    "  case UNINITIALIZED_TEMPLATE:\n"
+    "    m_p = new Module_Param_Unbound();\n"
+    "    break;\n"
+    "  case OMIT_VALUE:\n"
+    "    m_p = new Module_Param_Omit();\n"
+    "    break;\n"
+    "  case ANY_VALUE:\n"
+    "    m_p = new Module_Param_Any();\n"
+    "    break;\n"
+    "  case ANY_OR_OMIT:\n"
+    "    m_p = new Module_Param_AnyOrNone();\n"
+    "    break;\n"
+    "  case SPECIFIC_VALUE: {\n"
+    "    Module_Param* mp_field = NULL;\n"
+    "    switch(single_value.union_selection) {\n"
+    , name);
+    for (i = 0; i < sdef->nElements; ++i) {
+      src = mputprintf(src, 
+        "    case %s_%s:\n"
+        "      mp_field = single_value.field_%s->get_param(param_name);\n"
+        "      mp_field->set_id(new Module_Param_FieldName(mcopystr(\"%s\")));\n"
+        "      break;\n"
+        , selection_prefix, sdef->elements[i].name
+        , sdef->elements[i].name, sdef->elements[i].dispname);
+    }
+  src = mputstr(src,
+    "    default:\n"
+    "      break;\n"
+    "    }\n"
+    "    m_p = new Module_Param_Assignment_List();\n"
+    "    m_p->add_elem(mp_field);\n"
+    "    break; }\n"
+    "  case VALUE_LIST:\n"
+    "  case COMPLEMENTED_LIST: {\n"
+    "    if (template_selection == VALUE_LIST) {\n"
+    "      m_p = new Module_Param_List_Template();\n"
+    "    }\n"
+    "    else {\n"
+    "      m_p = new Module_Param_ComplementList_Template();\n"
+    "    }\n"
+    "    for (size_t i_i = 0; i_i < value_list.n_values; ++i_i) {\n"
+    "      m_p->add_elem(value_list.list_value[i_i].get_param(param_name));\n"
+    "    }\n"
+    "    break; }\n"
+    "  default:\n"
+    "    break;\n"
+    "  }\n"
+    "  if (is_ifpresent) {\n"
+    "    m_p->set_ifpresent();\n"
+    "  }\n"
+    "  return m_p;\n"
+    "}\n\n");
 
   /* check template restriction */
   def = mputstr(def, "void check_restriction(template_res t_res, "
-    "const char* t_name=NULL) const;\n");
+    "const char* t_name=NULL, boolean legacy = FALSE) const;\n");
   src = mputprintf(src,
     "void %s_template::check_restriction("
-      "template_res t_res, const char* t_name) const\n"
+      "template_res t_res, const char* t_name, boolean legacy) const\n"
     "{\n"
     "if (template_selection==UNINITIALIZED_TEMPLATE) return;\n"
     "switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) {\n"
@@ -2748,7 +3056,7 @@ void defUnionTemplate(const struct_def *sdef, output_struct *output)
       "performing check_restriction operation on a template of union type %s.\");\n"
     "}\n"
     "case TR_PRESENT:\n"
-    "if (!match_omit()) return;\n"
+    "if (!match_omit(legacy)) return;\n"
     "break;\n"
     "default:\n"
     "return;\n"
This page took 0.036936 seconds and 5 git commands to generate.