/* ~IsRecordTypeList~ checks if the given type list is a record type list. This is needed in several places like ~In~, ~Out~, ~Save~, ~Open~.... Three type lists a common nowadays: 1 (72 0) 2 ((72 0)) 3 ((72 0) ...) With this information a crosscheck is done with the Secondo catalogue. */ bool Record::IsRecordTypeList(ListExpr typeInfo) { bool isRecord = false; NList list = typeInfo; #ifdef RECORD_DEBUG cerr << "Record::IsRecordTypeList(" << nl->ToString(typeInfo) << ")" << endl; #endif // check type info list expression, it has to be // "(72 0)" // or "((72 0))" // or "((72 0) ...)" if (list.length() >= 1) { // extact the algebra and type id from the given list int listAlgebraId; int listTypeId; if (list.first().isAtom()) { // case: "(72 0)" listAlgebraId = list.first().intval(); listTypeId = list.second().intval(); } else { // case: "((72 0))" or "((72 0) ...)" listAlgebraId = list.first().first().intval(); listTypeId = list.first().second().intval(); } // retrieve record ids from secondo cataloge int scAlgebraId; int scTypeId; SecondoCatalog* sc = SecondoSystem::GetCatalog(); sc->GetTypeId(Record::BasicType(), scAlgebraId, scTypeId); // compare the list ids with secondo record ids if (listAlgebraId == scAlgebraId && listTypeId == scTypeId) { isRecord = true; } } return isRecord; }
/* ~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; }