Sync with 5.4.1
[deliverable/titan.core.git] / core2 / Basetype2.cc
index 189fa743f54e78132097a53377bd4c384c638389..2bffe70a5d5cbbd86d2e6ee6909257c5bf1e42b2 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Copyright (c) 2000-2014 Ericsson Telecom AB
+// Copyright (c) 2000-2015 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
@@ -255,7 +255,8 @@ Record_Of_Type::Record_Of_Type(null_type /*other_value*/)
 }
 
 Record_Of_Type::Record_Of_Type(const Record_Of_Type& other_value)
-: Base_Type(other_value), val_ptr(NULL), err_descr(other_value.err_descr), refd_ind_ptr(NULL)
+: Base_Type(other_value), RefdIndexInterface(other_value)
+, val_ptr(NULL), err_descr(other_value.err_descr), refd_ind_ptr(NULL)
 {
   if (!other_value.is_bound())
     TTCN_error("Copying an unbound record of/set of value.");
@@ -2269,6 +2270,10 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td,
       } /* next read */
     } /* if not empty element */
   } /* if not LIST */
+  if (!own_tag && exer && (p_td.xer_bits & XER_OPTIONAL) && get_nof_elements() == 0) {
+    // set it to unbound, so the OPTIONAL class sets it to omit
+    clean_up();
+  }
   return 1; // decode successful
 }
 
@@ -2289,25 +2294,31 @@ void Record_Of_Type::set_param(Module_Param& param) {
   }
   
   param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, is_set()?"set of value":"record of value");
+  
+  Module_Param_Ptr mp = &param;
+  if (param.get_type() == Module_Param::MP_Reference) {
+    mp = param.get_referenced_param();
+  }
+  
   switch (param.get_operation_type()) {
   case Module_Param::OT_ASSIGN:
-    if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) {
+    if (mp->get_type()==Module_Param::MP_Value_List && mp->get_size()==0) {
       set_val(NULL_VALUE);
       return;
     }
-    switch (param.get_type()) {
+    switch (mp->get_type()) {
     case Module_Param::MP_Value_List:
-      set_size(param.get_size());
-      for (size_t i=0; i<param.get_size(); ++i) {
-        Module_Param* const curr = param.get_elem(i);
+      set_size(mp->get_size());
+      for (size_t i=0; i<mp->get_size(); ++i) {
+        Module_Param* const curr = mp->get_elem(i);
         if (curr->get_type()!=Module_Param::MP_NotUsed) {
           get_at(i)->set_param(*curr);
         }
       }
       break;
     case Module_Param::MP_Indexed_List:
-      for (size_t i=0; i<param.get_size(); ++i) {
-        Module_Param* const current = param.get_elem(i);
+      for (size_t i=0; i<mp->get_size(); ++i) {
+        Module_Param* const current = mp->get_elem(i);
         get_at(current->get_id()->get_index())->set_param(*current);
       }
       break;
@@ -2316,12 +2327,12 @@ void Record_Of_Type::set_param(Module_Param& param) {
     }
     break;
   case Module_Param::OT_CONCAT:
-    switch (param.get_type()) {
+    switch (mp->get_type()) {
     case Module_Param::MP_Value_List: {
       if (!is_bound()) set_val(NULL_VALUE);
       int start_idx = lengthof();
-      for (size_t i=0; i<param.get_size(); ++i) {
-        Module_Param* const curr = param.get_elem(i);
+      for (size_t i=0; i<mp->get_size(); ++i) {
+        Module_Param* const curr = mp->get_elem(i);
         if ((curr->get_type()!=Module_Param::MP_NotUsed)) {
           get_at(start_idx+(int)i)->set_param(*curr);
         }
@@ -2339,6 +2350,34 @@ void Record_Of_Type::set_param(Module_Param& param) {
   }
 }
 
+Module_Param* Record_Of_Type::get_param(Module_Param_Name& param_name) const
+{
+  if (!is_bound()) {
+    return new Module_Param_Unbound();
+  }
+  if (param_name.next_name()) {
+    // Haven't reached the end of the module parameter name
+    // => the name refers to one of the elements, not to the whole record of
+    char* param_field = param_name.get_current_name();
+    if (param_field[0] < '0' || param_field[0] > '9') {
+      TTCN_error("Unexpected record field name in module parameter reference, "
+        "expected a valid index for %s type `%s'",
+        is_set() ? "set of" : "record of", get_descriptor()->name);
+    }
+    int param_index = -1;
+    sscanf(param_field, "%d", &param_index);
+    return get_at(param_index)->get_param(param_name);
+  }
+  Vector<Module_Param*> values;
+  for (int i = 0; i < val_ptr->n_elements; ++i) {
+    values.push_back(val_ptr->value_elements[i]->get_param(param_name));
+  }
+  Module_Param_Value_List* mp = new Module_Param_Value_List();
+  mp->add_list_with_implicit_ids(&values);
+  values.clear();
+  return mp;
+}
+
 void Record_Of_Type::set_implicit_omit()
 {
   for (int i = 0; i < get_nof_elements(); ++i) {
@@ -2474,21 +2513,27 @@ void Record_Type::set_param(Module_Param& param) {
   }
 
   param.basic_check(Module_Param::BC_VALUE, is_set()?"set value":"record value");
-  switch (param.get_type()) {
+  
+  Module_Param_Ptr mp = &param;
+  if (param.get_type() == Module_Param::MP_Reference) {
+    mp = param.get_referenced_param();
+  }
+  
+  switch (mp->get_type()) {
   case Module_Param::MP_Value_List:
-    if (get_count()<(int)param.get_size()) {
-      param.error("%s value of type %s has %d fields but list value has %d fields", is_set()?"Set":"Record", get_descriptor()->name, get_count(), (int)param.get_size());
+    if (get_count()<(int)mp->get_size()) {
+      param.error("%s value of type %s has %d fields but list value has %d fields", is_set()?"Set":"Record", get_descriptor()->name, get_count(), (int)mp->get_size());
     }
-    for (size_t i=0; i<param.get_size(); i++) {
-      Module_Param* mp = param.get_elem(i);
-      if (mp->get_type()!=Module_Param::MP_NotUsed) {
-        get_at((int)i)->set_param(*mp);
+    for (size_t i=0; i<mp->get_size(); i++) {
+      Module_Param* mp_elem = mp->get_elem(i);
+      if (mp_elem->get_type()!=Module_Param::MP_NotUsed) {
+        get_at((int)i)->set_param(*mp_elem);
       }
     }
     break;
   case Module_Param::MP_Assignment_List:
-    for (size_t i=0; i<param.get_size(); ++i) {
-      Module_Param* const current = param.get_elem(i);
+    for (size_t i=0; i<mp->get_size(); ++i) {
+      Module_Param* const current = mp->get_elem(i);
       bool found = false;
       for (int j=0; j<get_count(); ++j) {
         if (!strcmp(fld_name(j), current->get_id()->get_name())) {
@@ -2509,6 +2554,38 @@ void Record_Type::set_param(Module_Param& param) {
   }
 }
 
+Module_Param* Record_Type::get_param(Module_Param_Name& param_name) const
+{
+  if (!is_bound()) {
+    return new Module_Param_Unbound();
+  }
+  if (param_name.next_name()) {
+    // Haven't reached the end of the module parameter name
+    // => the name refers to one of the fields, not to the whole record
+    char* param_field = param_name.get_current_name();
+    if (param_field[0] >= '0' && param_field[0] <= '9') {
+      TTCN_error("Unexpected array index in module parameter reference, "
+        "expected a valid field name for %s type `%s'",
+        is_set() ? "set" : "record", get_descriptor()->name);
+    }
+    int field_cnt = get_count();
+    for (int field_idx = 0; field_idx < field_cnt; field_idx++) {
+      if (strcmp(fld_name(field_idx), param_field) == 0) {
+        return get_at(field_idx)->get_param(param_name);
+      }
+    }
+    TTCN_error("Field `%s' not found in %s type `%s'",
+      param_field, is_set() ? "set" : "record", get_descriptor()->name);
+  }
+  Module_Param_Assignment_List* mp = new Module_Param_Assignment_List();
+  for (int i = 0; i < get_count(); ++i) {
+    Module_Param* mp_field = get_at(i)->get_param(param_name);
+    mp_field->set_id(new Module_Param_FieldName(mcopystr(fld_name(i))));
+    mp->add_elem(mp_field);
+  }
+  return mp;
+}
+
 void Record_Type::set_implicit_omit()
 {
   int field_cnt = get_count();
@@ -5167,98 +5244,79 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
         get_at(oi)->set_to_omit();
         ++n_optionals;
       }
+
       Record_Of_Type *use_order = static_cast<Record_Of_Type*>(get_at(uo_index));
       // Initialize the use_order field to empty. Let it grow on demand.
       // (setting it to the minimum acceptable size may leave unbound elements
       // if the XML was incomplete).
       use_order->set_size(0);
 
-      Record_Type *jumbled = this; // the record affected by USE_ORDER
-      int begin = first_nonattr;
-      int end   = field_cnt; // "one past"
-      if (p_td.xer_bits & USE_NIL) {
-        Base_Type *last_optional = get_at(field_cnt-1);
-        if (!usenil_attribute) { // exer known true
-          last_optional->set_to_present();
-          jumbled = static_cast<Record_Type*>(last_optional->get_opt_value());
-          // We will operate on the members of last_optional,
-          // effectively bypassing last_optional->XER_decode() itself.
-          begin = 0;
-          end   = jumbled->get_count();
-          ec_1.set_msg("%s': ", fld_name(field_cnt-1));
-        }
-      }
-      if (num_attributes > 0
-        && first_nonattr != field_cnt
-        && i == first_nonattr - 1) { // exer known true
-        // If there were attributes and their processing just finished,
-        // the reader is positioned on the start tag of the record.
-        // Move ahead, unless there are no non-attribute fields.
-        reader.Read();
-      }
-      // Then, the non-attributes
-
-      // The index runs over the members affected by USE-ORDER.
-      // This is [first_nonattr,field_cnt) unless USE-NIL is involved,
-      // in which case it's [0,optional_sequence::field_cnt)
-      int *seen = new int[end-begin];
-      int num_seen = 0;
-      int last_any_elem = begin - 1;
-      // The index of the latest embedded value can change outside of this function
-      // (if the field is a untagged record of), in this case the next value should
-      // be ignored, as it's already been handled by the record of
-      int last_embval_index = 0;
-      for (i = begin; i < end; i++) {
-        for (success = reader.Ok(); success == 1; success = reader.Read()) {
-          type = reader.NodeType();
-          if (0 != emb_val && reader.NodeType()==XML_READER_TYPE_TEXT) {
-            UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
-            emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+      // Nothing to order if there are no child elements
+      if (!tag_closed) {
+        Record_Type *jumbled = this; // the record affected by USE_ORDER
+        int begin = first_nonattr;
+        int end   = field_cnt; // "one past"
+        if (p_td.xer_bits & USE_NIL) {
+          Base_Type *last_optional = get_at(field_cnt-1);
+          if (!usenil_attribute) { // exer known true
+            last_optional->set_to_present();
+            jumbled = static_cast<Record_Type*>(last_optional->get_opt_value());
+            // We will operate on the members of last_optional,
+            // effectively bypassing last_optional->XER_decode() itself.
+            begin = 0;
+            end   = jumbled->get_count();
+            ec_1.set_msg("%s': ", fld_name(field_cnt-1));
           }
-          // The non-attribute components must not be UNTAGGED
-          if (type == XML_READER_TYPE_ELEMENT) break;
-          // else if (type==XML_READER_TYPE_END_ELEMENT) panic?
         }
-        if (0 != emb_val) {
-          if (last_embval_index == emb_val->embval_index) {
-            ++emb_val->embval_index;
-          }
-          last_embval_index = emb_val->embval_index;
+        if (num_attributes > 0
+          && first_nonattr != field_cnt
+          && i == first_nonattr - 1) { // exer known true
+          // If there were attributes and their processing just finished,
+          // the reader is positioned on the start tag of the record.
+          // Move ahead, unless there are no non-attribute fields.
+          reader.Read();
         }
-        if (success != 1) break;
-        const char *name = (const char *)reader.LocalName();
-        boolean field_name_found = false;
-        // Find out which member it is.
-        // FIXME some hashing should be implemented
-        for (int k = begin; k < end; k++) {
-          if (!(jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) &&
-              check_name(name, *jumbled->xer_descr(k), 1)) {
-            ec_1.set_msg("%s': ", jumbled->fld_name(k));
-
-            // Check for the same field being decoded twice.
-            // We can't use the field's is_bound()/is_present(),
-            // because the field may be bound on input, e.g. for
-            // prototype(fast) or prototype(backtrack).
-            int in_dex = k - begin;
-            for (int o = 0; o < num_seen ;++o) {
-              if (in_dex == seen[o]) TTCN_EncDec_ErrorContext::error(
-                TTCN_EncDec::ET_INVAL_MSG, "Duplicate element");
+        // Then, the non-attributes
+
+        // The index runs over the members affected by USE-ORDER.
+        // This is [first_nonattr,field_cnt) unless USE-NIL is involved,
+        // in which case it's [0,optional_sequence::field_cnt)
+        int *seen = new int[end-begin];
+        int num_seen = 0;
+        int last_any_elem = begin - 1;
+        // The index of the latest embedded value can change outside of this function
+        // (if the field is an untagged record of), in this case the next value should
+        // be ignored, as it's already been handled by the record of
+        int last_embval_index = 0;
+        bool early_exit = false;
+        for (i = begin; i < end; i++) {
+          for (success = reader.Ok(); success == 1; success = reader.Read()) {
+            type = reader.NodeType();
+            if (0 != emb_val && reader.NodeType()==XML_READER_TYPE_TEXT) {
+              UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
+              emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+            }
+            // The non-attribute components must not be UNTAGGED
+            if (type == XML_READER_TYPE_ELEMENT) break;
+            if (type == XML_READER_TYPE_END_ELEMENT) {
+              early_exit = true;
+              break;
             }
-            seen[num_seen++] = in_dex;
-            // Set the next use-order member.
-            // Non-const get_at creates the object in the record-of.
-            static_cast<Enum_Type*>(use_order->get_at(i - begin))
-            ->from_int(in_dex);
-            Base_Type *b = jumbled->get_at(k);
-            b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
-            field_name_found = true;
-            break;
           }
-        }
-        if (!field_name_found) {
-          // Check the anyElement fields
-          for (int k = last_any_elem + 1; k < end; k++) {
-            if (jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) {
+          if (0 != emb_val) {
+            if (last_embval_index == emb_val->embval_index) {
+              ++emb_val->embval_index;
+            }
+            last_embval_index = emb_val->embval_index;
+          }
+          if (success != 1 || early_exit) break;
+          const char *name = (const char *)reader.LocalName();
+          bool field_name_found = false;
+          // Find out which member it is.
+          // FIXME some hashing should be implemented
+          for (int k = begin; k < end; k++) {
+            if (!(jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) &&
+                check_name(name, *jumbled->xer_descr(k), 1)) {
               ec_1.set_msg("%s': ", jumbled->fld_name(k));
 
               // Check for the same field being decoded twice.
@@ -5277,44 +5335,77 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
               ->from_int(in_dex);
               Base_Type *b = jumbled->get_at(k);
               b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
-              last_any_elem = k;
+              field_name_found = true;
               break;
             }
           }
+          if (!field_name_found) {
+            // Check the anyElement fields
+            for (int k = last_any_elem + 1; k < end; k++) {
+              if (jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) {
+                ec_1.set_msg("%s': ", jumbled->fld_name(k));
+
+                // Check for the same field being decoded twice.
+                // We can't use the field's is_bound()/is_present(),
+                // because the field may be bound on input, e.g. for
+                // prototype(fast) or prototype(backtrack).
+                int in_dex = k - begin;
+                for (int o = 0; o < num_seen ;++o) {
+                  if (in_dex == seen[o]) TTCN_EncDec_ErrorContext::error(
+                    TTCN_EncDec::ET_INVAL_MSG, "Duplicate element");
+                }
+                seen[num_seen++] = in_dex;
+                // Set the next use-order member.
+                // Non-const get_at creates the object in the record-of.
+                static_cast<Enum_Type*>(use_order->get_at(i - begin))
+                ->from_int(in_dex);
+                Base_Type *b = jumbled->get_at(k);
+                b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
+                last_any_elem = k;
+                field_name_found = true;
+                break;
+              }
+            }
+          }
+          if (!field_name_found) {
+            TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG,
+              "Bad XML tag '%s' instead of a valid field", name);
+            break;
+          }
+        } // next field
+        if (0 != emb_val) {
+          if (reader.NodeType()==XML_READER_TYPE_TEXT) {
+            UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
+            emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+          }
+          if (last_embval_index == emb_val->embval_index) {
+            ++emb_val->embval_index;
+          }
         }
-      } // next field
-      if (0 != emb_val) {
-        if (reader.NodeType()==XML_READER_TYPE_TEXT) {
-          UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
-          emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
-        }
-        if (last_embval_index == emb_val->embval_index) {
-          ++emb_val->embval_index;
-        }
-      }
-      delete [] seen;
-      ec_1.set_msg(" "); // no active component
-      ec_0.set_msg(" ");
-
-      // Check that we collected the required number of children
-      int num_collected = use_order->size_of();
-      if (p_td.xer_bits & USE_NIL) {
-        int expected = usenil_attribute ? 0 : jumbled->get_count();
-        if (num_collected != expected) {
-          TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
-            "Incorrect number of fields %d, expected %d",
-            num_collected, expected);
+        delete [] seen;
+        ec_1.set_msg(" "); // no active component
+        ec_0.set_msg(" ");
+
+        // Check that we collected the required number of children
+        int num_collected = use_order->size_of();
+        if (p_td.xer_bits & USE_NIL) {
+          int expected = usenil_attribute ? 0 : jumbled->get_count();
+          if (num_collected != expected) {
+            TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+              "Incorrect number of fields %d, expected %d",
+              num_collected, expected);
+          }
         }
-      }
-      else {
-        if (num_collected < field_cnt - first_nonattr - n_optionals
-          ||num_collected > field_cnt - first_nonattr) {
-          TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
-            "Wrong number of fields! size = %d, expected %d..%d",
-            use_order->size_of(), field_cnt - first_nonattr - n_optionals,
-            field_cnt - first_nonattr);
+        else {
+          if (num_collected < field_cnt - first_nonattr - n_optionals
+            ||num_collected > field_cnt - first_nonattr) {
+            TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+              "Wrong number of fields! size = %d, expected %d..%d",
+              use_order->size_of(), field_cnt - first_nonattr - n_optionals,
+              field_cnt - first_nonattr);
+          }
         }
-      }
+      } // not empty element
     }
     else { // not USE-ORDER, simpler code      
       if (usenil_attribute) {
@@ -5391,7 +5482,15 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
     } // if embed-values
 
   } // if use-qname
-
+  
+  // Check if every non-optional field has been set
+  for (i = 0; i < field_cnt; ++i) {
+    if (!get_at(i)->is_optional() && !get_at(i)->is_bound()) {
+      TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+        "No data found for non-optional field '%s'", fld_name(i));
+    }
+  }
+  
   if (own_tag) {
     // We had our start tag. Then our fields did their thing.
     // Now we expect the end tag. And it better be our end tag!
@@ -5450,14 +5549,22 @@ int Record_Type::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok
   
   int field_count = get_count();
   for(int i = 0; i < field_count; ++i) {
+    boolean metainfo_unbound = NULL != fld_descr(i)->json && fld_descr(i)->json->metainfo_unbound;
     if ((NULL != fld_descr(i)->json && fld_descr(i)->json->omit_as_null) || 
-        !get_at(i)->is_optional() || get_at(i)->is_present()) {
-      if (NULL != fld_descr(i)->json && NULL != fld_descr(i)->json->alias) {
-        enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, fld_descr(i)->json->alias);
-      } else {
-        enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, fld_name(i));
+        get_at(i)->is_present() || metainfo_unbound) {
+      const char* field_name = (NULL != fld_descr(i)->json && NULL != fld_descr(i)->json->alias) ?
+        fld_descr(i)->json->alias : fld_name(i);
+      enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, field_name);
+      if (metainfo_unbound && !get_at(i)->is_bound()) {
+        enc_len += p_tok.put_next_token(JSON_TOKEN_LITERAL_NULL);
+        char* metainfo_str = mprintf("metainfo %s", field_name);
+        enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, metainfo_str);
+        Free(metainfo_str);
+        enc_len += p_tok.put_next_token(JSON_TOKEN_STRING, "\"unbound\"");
+      }
+      else {
+        enc_len += get_at(i)->JSON_encode(*fld_descr(i), p_tok);
       }
-      enc_len += get_at(i)->JSON_encode(*fld_descr(i), p_tok);
     }
   }
   
@@ -5480,6 +5587,13 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
   
   const int field_count = get_count();
   
+  // initialize meta info states
+  int* metainfo = new int[field_count];
+  for (int i = 0; i < field_count; ++i) {
+    metainfo[i] = (NULL != fld_descr(i)->json && fld_descr(i)->json->metainfo_unbound) ?
+      JSON_METAINFO_NONE : JSON_METAINFO_NOT_APPLICABLE;
+  }
+  
   while (true) {
     // Read name - value token pairs until we reach some other token
     char* name = 0;
@@ -5496,6 +5610,14 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
       break;
     }
     else {
+      // check for meta info
+      boolean is_metainfo = FALSE;
+      if (name_len > 9 && 0 == strncmp(name, "metainfo ", 9)) {
+        name += 9;
+        name_len -= 9;
+        is_metainfo = TRUE;
+      }
+      
       // check field name
       int field_idx;
       for (field_idx = 0; field_idx < field_count; ++field_idx) {
@@ -5513,7 +5635,8 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
       if (field_count == field_idx) {
         // invalid field name
         char* name2 = mcopystrn(name, name_len);
-        JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_INVALID_NAME_ERROR, name2);
+        JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, is_metainfo ?
+          JSON_DEC_METAINFO_NAME_ERROR : JSON_DEC_INVALID_NAME_ERROR, name2);
         // if this is set to a warning, skip the value of the field
         dec_len += p_tok.get_next_token(&token, NULL, NULL);
         if (JSON_TOKEN_NUMBER != token && JSON_TOKEN_STRING != token &&
@@ -5527,14 +5650,53 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
         continue;
       }
       
-      int ret_val = get_at(field_idx)->JSON_decode(*fld_descr(field_idx), p_tok, p_silent);
-      if (0 > ret_val) {
-        if (JSON_ERROR_INVALID_TOKEN) {
-          JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+      if (is_metainfo) {
+        if (JSON_METAINFO_NOT_APPLICABLE != metainfo[field_idx]) {
+          // check meta info
+          char* info_value = 0;
+          size_t info_len = 0;
+          dec_len += p_tok.get_next_token(&token, &info_value, &info_len);
+          if (JSON_TOKEN_STRING == token && 9 == info_len &&
+              0 == strncmp(info_value, "\"unbound\"", 9)) {
+            metainfo[field_idx] = JSON_METAINFO_UNBOUND;
+          }
+          else {
+            JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_METAINFO_VALUE_ERROR,
+              fld_name(field_idx));
+            return JSON_ERROR_FATAL;
+          }
+        }
+        else {
+          JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_METAINFO_NOT_APPLICABLE,
+            fld_name(field_idx));
+          return JSON_ERROR_FATAL;
         }
-        return JSON_ERROR_FATAL;
       }
-      dec_len += ret_val;
+      else {
+        buf_pos = p_tok.get_buf_pos();
+        int ret_val = get_at(field_idx)->JSON_decode(*fld_descr(field_idx), p_tok, p_silent);
+        if (0 > ret_val) {
+          if (JSON_ERROR_INVALID_TOKEN == ret_val) {
+            // undo the last action on the buffer, check if the invalid token was a null token 
+            p_tok.set_buf_pos(buf_pos);
+            p_tok.get_next_token(&token, NULL, NULL);
+            if (JSON_TOKEN_LITERAL_NULL == token) {
+              if (JSON_METAINFO_NONE == metainfo[field_idx]) {
+                // delay reporting an error for now, there might be meta info later
+                metainfo[field_idx] = JSON_METAINFO_NEEDED;
+                continue;
+              }
+              else if (JSON_METAINFO_UNBOUND == metainfo[field_idx]) {
+                // meta info already found
+                continue;
+              }
+            }
+            JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+          }
+          return JSON_ERROR_FATAL;
+        }
+        dec_len += ret_val;
+      }
     }
   }
   
@@ -5544,10 +5706,17 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
     return JSON_ERROR_FATAL;
   }
   
-  // Check if every field has been set
+  // Check if every field has been set and handle meta info
   for (int field_idx = 0; field_idx < field_count; ++field_idx) {
     Base_Type* field = get_at(field_idx);
-    if (!field->is_bound()) {
+    if (JSON_METAINFO_UNBOUND == metainfo[field_idx]) {
+      field->clean_up();
+    }
+    else if (JSON_METAINFO_NEEDED == metainfo[field_idx]) {
+      // no meta info was found for this field, report the delayed error
+      JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+    }
+    else if (!field->is_bound()) {
       if (NULL != fld_descr(field_idx)->json && NULL != fld_descr(field_idx)->json->default_value) {
         get_at(field_idx)->JSON_decode(*fld_descr(field_idx), DUMMY_BUFFER, p_silent);
       }
@@ -5560,6 +5729,8 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
     }
   }
   
+  delete metainfo;
+  
   return dec_len;
 }
 
@@ -5593,12 +5764,24 @@ void Empty_Record_Type::log() const
 
 void Empty_Record_Type::set_param(Module_Param& param) {
   param.basic_check(Module_Param::BC_VALUE, "empty record/set value (i.e. { })");
-  if (param.get_type()!=Module_Param::MP_Value_List || param.get_size()>0) {
+  Module_Param_Ptr mp = &param;
+  if (param.get_type() == Module_Param::MP_Reference) {
+    mp = param.get_referenced_param();
+  }
+  if (mp->get_type()!=Module_Param::MP_Value_List || mp->get_size()>0) {
     param.type_error("empty record/set value (i.e. { })", get_descriptor()->name);
   }
   bound_flag = TRUE;
 }
 
+Module_Param* Empty_Record_Type::get_param(Module_Param_Name& /* param_name */) const
+{
+  if (!is_bound()) {
+    return new Module_Param_Unbound();
+  }
+  return new Module_Param_Value_List();
+}
+
 void Empty_Record_Type::encode_text(Text_Buf& /*text_buf*/) const
 {
   if (!bound_flag)
This page took 0.032024 seconds and 5 git commands to generate.