Example #1
0
/*
~In~ function to create a record instance through a nested list.

According to the assigned type and value list the record is created.
Before that the lists are checked regarding there correctness in
the following order:

  1 check whether the given type list is a record type list at all

  2 check if in case of a non empty value list the two lists
  have the same number of elements.

  3 If the value list is empty an empty record with only the given
  element types is created

In all other cases an appropriate error message is populated and
the creation aborts.

After preliminary research both lists will be run through parallel
in order to create the single elements. To simplify the parallel
run through a list iterator ~ListIterator~ class has been created.
More information about the iterator can be found in ~ListIterator.h~
document.

At the run through the following cases have to be differentiated:

First of all the current type list has to contain 2 elements. Example:

  * case 1: (string (int int))

    1 element name

    1 element type list, with two integer values

      1.1 algebraId

      1.2 typeId

or

  * case 2: (string ((int int) ...))

    2 element name

    2 element type as list, first list item contains
    two integer values (see above)

The first possibility reflects a simple Secondo type whereas the second
illustrates a complex type likewise a ~record~.

The element name has to start with a capital letter.

The list elements have to conform these guidelines otherwise an error is
detected.

Once the list item is correct the new element is created. Therefore the
belonging algebraId and typeId is read out from the
Secondo catalogue.

Elements that are marked with NULL are created as well but are ~undefined~.

After the successful element creation this element is appended to the
record by AppendElement method.

The whole procedure is repeated as long as element information is
available in the given ~typeInfo~ list.

*/
Word
Record::In(const ListExpr typeInfo, const ListExpr instance,
           const int errorPos, ListExpr& errorInfo, bool& correct)
{
#ifdef RECORD_DEBUG
  cerr << "Record::In(" << nl->ToString(typeInfo) << ", "
       << nl->ToString(instance) << ", ..., ..., " << correct << ")" << endl;
#endif

  Word w = SetWord(Address(0));
  correct = false;
  const string nullSymbol = "NULL";

  if (Record::IsRecordTypeList(typeInfo)) {
    // create an empty record instance
    Record* record = new Record(0);

    bool hasValueList;

    if(listutils::isSymbolUndefined(instance)){ // an undefined record:
      record->SetDefined(false);
      correct = true;
      return w;
    }
    // in case of a not empty value list:
    // case 1: value list has to be a list
    // case 2: type list and value list have to be of the same length
    if (nl->ListLength(instance) == 0) {
      hasValueList = false;
    } else {
      hasValueList = true;

      // case 1
      if (nl->IsAtom(instance)){
#ifdef RECORD_DEBUG
        cerr << "Record::In: value list is of kind atom but "
                "a list is expected!" << endl;
#endif
        cmsg.inFunError("Record::In: Value list is of kind atom but "
                        "a list is expected!  ");
        return w;
      }

      // case 2
      if (nl->ListLength(instance) != nl->ListLength(nl->Rest(typeInfo))) {
#ifdef RECORD_DEBUG
        cerr << "Record::In: different number of elements in "
                "type list and value list " << endl;
#endif
        cmsg.inFunError("Record::In: different number of elements in "
                        "type list and Value list ");
        return w;
      }
    }

    // create type and value list iteratoren
    ListIterator typeIter = nl->Rest(typeInfo);
    ListIterator valueIter = instance;

    // variables used inside the iteration loop
    string elemName;
    string elemTypeName;
    int elemAlgebraId;
    int elemTypeId;
    Word elemWord;
    Attribute* elem;

    // iterate synchrone through the type and value list elements
    while(typeIter.HasNext() && valueIter.HasNext()) {
      // assign the current type list element
      NList curType = typeIter.NextNList();

      // assign the current value list element
      ListExpr curValue;
      if (hasValueList) {
        curValue = valueIter.NextListExpr();
      } else {
        curValue = nl->OneElemList(nl->SymbolAtom(nullSymbol));
      }

#ifdef RECORD_DEBUG
      cerr << "Record::In: curType=" << curType.convertToString() << endl;
      cerr << "Record::In: curValue=" << nl->ToString(curValue) << endl;
#endif

      // the current type list has to contain 2 elements
      // case 1: (string (int int))
      //         1. element name
      //         2. element type list with two integer values
      //           2.1 algebraId
      //           2.2 typeId
      // case 2: (string ((int int) ...))
      //         1. element name
      //         2. element type as list, first list item contains
      //            two integer values
      if (   !(   curType.length() == 2
               && curType.second().length() == 2
               && curType.second().first().isInt()
               && curType.second().second().isInt())
          && !(  curType.length() == 2
               && curType.second().length() > 0
               && curType.second().first().length() == 2
               && curType.second().first().first().isInt()
               && curType.second().first().second().isInt()))
      {
#ifdef RECORD_DEBUG
        cerr << "Record::In: wrong subtype info" << endl;
#endif
        cmsg.inFunError("Record::In: wrong subtype info: " +
                        curType.convertToString());
        return w;
      }

      // extraxt the element name from current type list element
      elemName = curType.first().convertToString();

      // extraxt the element type ids from current type list element
      if (curType.second().first().isAtom()) {
        // case 1
        elemAlgebraId = curType.second().first().intval();
        elemTypeId = curType.second().second().intval();
      } else {
        // case 2
        elemAlgebraId = curType.second().first().first().intval();
        elemTypeId = curType.second().first().second().intval();
      }

      // retrieve the type name of the ids from secondo catalog
      SecondoCatalog* sc = SecondoSystem::GetCatalog();
      elemTypeName = sc->GetTypeName(elemAlgebraId, elemTypeId);


      // the element name has to start with a capital letter
      if (isupper(elemName[0]) == 0) {
        cmsg.inFunError("Record::In: element name has to start with a "
                        "capital letter: " + elemName);
        return w;
      }

      // check if curValue is a Atom of value NULL (TEXT or Symbol)
      // if true -> create a default object
     if (nullSymbol.compare(nl->ToString(curValue)) == 0) {
       elemWord = (am->CreateObj(elemAlgebraId, elemTypeId))
                  (curType.second().listExpr());

       // cast the read type instance to an attribute
       elem = static_cast<Attribute*>(elemWord.addr);

       // make elem as undefined
       elem->SetDefined(false);
     } else {
       // read element by registered IN function of the current type
       elemWord = (am->InObj(elemAlgebraId, elemTypeId))
                  (curType.second().listExpr(),
                   curValue,
                   errorPos,
                   errorInfo,
                   correct);

       // cast the read type instance to an attribute
       elem = static_cast<Attribute*>(elemWord.addr);
      }

      // check of existing object elem
      if (elem == NULL) {
        cmsg.inFunError("Record::In: In function of type "
                        + elemTypeName
                        +" for element "
                        + elemName
                        + " has delivered a NULL pointer for value "
                        + nl->ToString(curValue));
        return w;
      }

      // append the read attribute to the record and check the result
      if (record->AppendElement(elem, elemTypeName, elemName) == false) {
        cmsg.inFunError("Record::In: Cannot append element "
                        + elemName
                        + " of type "
                        + elemTypeName);
        elem->DeleteIfAllowed();
        return w;
      }
      elem->DeleteIfAllowed();
      elem=0;
    } // End of: iterate synchrone through the type and value list elements


    // set the created record as return value
    w = SetWord(record);
    correct = true;
  } //IsRecordTypeList

#ifdef RECORD_DEBUG
  cerr << "Record::In: correct=" << correct
       << ", w.addr=" << w.addr << endl;
#endif

  return w;
}