libs/EDoc/Type.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003    Copyright (C) 2007 by Brendon Costa
00004 
00005    This library is free software; you can redistribute it and/or modify 
00006    it under the terms of the "LGPL Like" License defined in the file COPYING 
00007    that should have been distributed along with this source.
00008 
00009    This library is distributed in the hope that it will be useful, 
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of 
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013    You should have received a copy of the "LGPL Like" License 
00014    along with this library; see the file COPYING. if not, it can be 
00015    obtained from the EDoc++ website: 
00016    http://edoc.sourceforge.net/license.html
00017 
00018 *******************************************************************************/
00019 #include "config.h"
00020 
00021 #include "EDoc/Type.h"
00022 #include "EDoc/PersistenceIFace.h"
00023 #include "EDoc/Dictionary.h"
00024 #include "EDoc/Function.h"
00025 #include "EDoc/exceptions.h"
00026 #include "EDoc/Logger.h"
00027 #include "EDoc/utils.h"
00028 #include "EDoc/PStack.h"
00029 #include "EDoc/StackRef.h"
00030 
00031 #include "EDoc/persistence_data.h"
00032 #include "IndexedDictionary.h"
00033 
00034 #include <iostream>
00035 
00036 //==============================================================================
00037 /** \brief define a small macro that is called upon a merge error.
00038  */
00039 #define EDOC_MERGE_ERROR(Message) \
00040    EDOC_Error(Message); \
00041    EDOC_THROW_EXCEPTION(MergeException, "Failed merging type.", Message);
00042 
00043 
00044 namespace EDoc
00045 {
00046    //===========================================================================
00047    uint8_t Type::GetRecordType() const
00048    {
00049       return VALUE_RECORD_TYPE_TYPE;
00050    }
00051    //===========================================================================
00052    Type::Type(Dictionary& dict_in, std::string key_name_in) :
00053       StringIdentifiedObject(dict_in, key_name_in),
00054       external_linkage(true),
00055       translation_unit(NULL),
00056       throw_type(NULL),
00057       root_type(NULL),
00058       loc(&dict_in),
00059       visible(true)
00060    {
00061    }
00062    //===========================================================================
00063    Type::Type(Dictionary& dict_in, int32_t index_in) :
00064       StringIdentifiedObject(dict_in, index_in),
00065       external_linkage(true),
00066       translation_unit(NULL),
00067       throw_type(NULL),
00068       root_type(NULL),
00069       loc(&dict_in),
00070       visible(true)
00071    {
00072    }
00073    //===========================================================================
00074    Type& Type::operator=(const Type& right)
00075    {
00076       // @@@Brendon Do i need to assign the StringIdentifiedObject parts too?
00077       if (this == &right)
00078       {
00079          EDOC_Finer("Not assigning as the instances are the same.");
00080          return *this;
00081       }
00082 
00083       name = right.name;
00084       loc = right.loc;
00085       external_linkage = right.external_linkage;
00086       throw_type = dict.types.AlwaysGet(*right.throw_type);
00087       root_type = dict.types.AlwaysGet(*right.root_type);
00088 
00089       if (!external_linkage)
00090       {
00091          // This allows for direct assignment because translation units do not belong to dictionaries but live past them.
00092          translation_unit = right.translation_unit;
00093       }
00094       
00095       // Assing identical to fields.
00096       Erase(identical);
00097       for (size_t i = 0; i < right.identical.size(); i++)
00098       {
00099          identical.push_back(dict.types.AlwaysGet(
00100             *right.identical[i]));
00101       }
00102 
00103       // Merge catchable by fields.
00104       Erase(catchable);
00105       for (size_t i = 0; i < right.catchable.size(); i++)
00106       {
00107          catchable.push_back(dict.types.AlwaysGet(
00108             *right.catchable[i]));
00109       }
00110 
00111       Erase(referenced_in_files);
00112       EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00113       {
00114          referenced_in_files.push_back(
00115             dict.files.AlwaysGet(*(*it)));
00116       }
00117 
00118       populated = right.populated;
00119       visible = right.visible;
00120       return *this;
00121    }
00122    //===========================================================================
00123    void Type::Read(PersistenceIFace& file, IndexedDictionary& idict)
00124    {
00125       name = file.ReadString(KEY_CANONICAL_NAME);
00126       external_linkage = file.ReadBoolean(KEY_EXTERNAL_LINKAGE);
00127       if (!external_linkage)
00128       {
00129          translation_unit = idict.dict->GetIndexedTranslationUnit(
00130             file.ReadUInt32(KEY_TRANSLATION_UNIT));
00131       }
00132       
00133       throw_type = idict.types.AlwaysGet(file.ReadUInt32(KEY_THROW_TYPE));
00134       root_type = idict.types.AlwaysGet(file.ReadUInt32(KEY_ROOT_TYPE));
00135 
00136       loc.Read(file, idict);
00137 
00138       size_t size = file.ReadUInt32(KEY_IDENTICAL_TYPE_LS);
00139       for (size_t i = 0; i < size; i++)
00140       {
00141          identical.push_back(
00142             idict.types.AlwaysGet(file.ReadUInt32(KEY_IDENTICAL_TYPE_LI)));
00143       }
00144 
00145       size = file.ReadUInt32(KEY_CATCHABLE_TYPE_LS);
00146       for (size_t i = 0; i < size; i++)
00147       {
00148          catchable.push_back(
00149             idict.types.AlwaysGet(file.ReadUInt32(KEY_CATCHABLE_TYPE_LI)));
00150       }
00151 
00152       size = file.ReadUInt32(KEY_REFERENCE_FILES_LS);
00153       for (size_t i = 0; i < size; i++)
00154       {
00155          referenced_in_files.push_back(
00156             idict.files.AlwaysGet(file.ReadUInt32(KEY_REFERENCE_FILE)));
00157       }
00158 
00159       populated = true;
00160       SetKeyName(GetNameInternal());
00161    }
00162    //===========================================================================
00163    std::ostream& Type::Print(std::ostream& out, std::string prefix) const
00164    {
00165       out << prefix << "Name: " << name << std::endl;
00166 
00167       out << prefix << "Throw Type: " 
00168          << (throw_type ? throw_type->GetNormalisedName() : "(NULL)") 
00169          << std::endl;
00170 
00171       out << prefix << "Root Type: " 
00172          << (root_type ? root_type->GetNormalisedName() : "(NULL)") 
00173          << std::endl;
00174 
00175       loc.Print(out, prefix) << std::endl;
00176 
00177       for (size_t i = 0; i < identical.size(); i++)
00178       {
00179          out << prefix << "Identical to: " << identical[i]->GetNormalisedName() << std::endl;
00180       }
00181 
00182       for (size_t i = 0; i < catchable.size(); i++)
00183       {
00184          out << prefix << "Catchable by: " << catchable[i]->GetNormalisedName() << std::endl;
00185       }
00186 
00187       return out;
00188    }
00189 
00190    //===========================================================================
00191    bool Type::operator==(const Type& right) const
00192    {
00193       if ((name != right.name) || 
00194           (external_linkage != right.external_linkage) ||
00195           (identical.size() != right.identical.size()) ||
00196           (catchable.size() != right.catchable.size()) ||
00197           (throw_type != right.throw_type) || 
00198           (root_type != right.root_type) ||
00199           (loc != right.loc))
00200       {
00201          return false;
00202       }
00203 
00204       if (!external_linkage)
00205       {
00206          if (translation_unit->GetID() != 
00207             right.translation_unit->GetID())
00208          {
00209             return false;
00210          }
00211       }
00212       
00213       for (size_t i = 0; i < identical.size(); i++)
00214       {
00215          if (identical[i] != right.identical[i])
00216          {
00217             return false;
00218          }
00219       }
00220 
00221       for (size_t i = 0; i < catchable.size(); i++)
00222       {
00223          if (catchable[i] != right.catchable[i])
00224          {
00225             return false;
00226          }
00227       }
00228 
00229       return true;
00230    }
00231    //===========================================================================
00232    void Type::Merge(const StringIdentifiedObject& right_in)
00233    {
00234       const Type& right(dynamic_cast<const Type&>(right_in));
00235       
00236       if (!populated)
00237       {
00238          *this = right;
00239          return;
00240       }
00241       
00242       if (external_linkage != right.external_linkage)
00243       {
00244          EDOC_MERGE_ERROR("");
00245       }
00246       
00247       if (!external_linkage)
00248       {
00249          if (translation_unit->GetID() != 
00250             right.translation_unit->GetID())
00251          {
00252             EDOC_Error("Our translation unit name: " 
00253                << translation_unit->GetName() 
00254                << "\nRight translation unit name: " 
00255                << right.translation_unit->GetName());
00256             EDOC_MERGE_ERROR("Unable to merge two types with internal "
00257                "linkage but of different translation units.");
00258          }
00259       }
00260       
00261       
00262       if (!name.size())
00263       {
00264          EDOC_Finer("Assigning name: " << right.name);
00265          name = right.name;
00266       }
00267       else if (right.name.size() && (name != right.name))
00268       {
00269          EDOC_MERGE_ERROR("Unable to merge two types with different names. "
00270             "Left: " << name << ", right: " << right.name);
00271       
00272       }
00273       else
00274       {
00275          EDOC_Finer("Otherwise we have a name and it is equal to the right "
00276             "name or right has no name.");
00277       }
00278 
00279       // @@@Brendon This is probably not what we want.
00280       if (loc && right.loc && (loc != right.loc))
00281       {
00282          EDOC_MERGE_ERROR("Unable to merge two types declared in "
00283             "different files.");
00284       }
00285       else if (!loc)
00286       {
00287          EDOC_Finer("Merging locations.");
00288          loc.Merge(right.loc);
00289       }
00290 
00291 
00292       // Expect one or the other to have a throw type.
00293       if (!throw_type && !right.throw_type)
00294       {
00295          EDOC_MERGE_ERROR("Unable to merge two incomplete types.");
00296       }
00297       else if (!throw_type)
00298       {
00299          throw_type = dict.types.AlwaysGet(*right.throw_type);
00300       }
00301       else if (!right.throw_type)
00302       {
00303          // Do nothing.
00304          EDOC_ASSERT(throw_type, "");
00305       }
00306       else if (throw_type->GetNormalisedName() != right.throw_type->GetNormalisedName())
00307       {
00308          std::ostringstream ls;
00309          ls << "Referenced in files: ";
00310          EDOC_FOREACH(FilePList, it, referenced_in_files)
00311          {
00312             if (it != referenced_in_files.begin())
00313             {
00314                ls << ", ";
00315             }
00316             ls << (*it)->GetName();
00317          }
00318          ls << std::endl;
00319          Print(ls);
00320          
00321          std::ostringstream rs;
00322          rs << "Referenced in files: ";
00323          EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00324          {
00325             if (it != right.referenced_in_files.begin())
00326             {
00327                rs << ", ";
00328             }
00329             rs << (*it)->GetName();
00330          }
00331          rs << std::endl;
00332          right.Print(rs);
00333          
00334          EDOC_Error("Type: " << GetKeyName() << " is found in two files but has differing throw types. They are"
00335             << "\nLeft: " << throw_type->GetNormalisedName()
00336             << "\nRight: " << right.throw_type->GetNormalisedName()
00337             << "\n\nLeft: " << ls.str()
00338             << "\n\nRight: " << rs.str());
00339          EDOC_MERGE_ERROR("Cant merge types with differing throw types.");
00340       }
00341       else
00342       {
00343          EDOC_Finer("Eithre throw types are the same of both NULL. right: " 
00344             << (right.throw_type ? right.throw_type->GetNormalisedName():"(NULL)"));
00345       }
00346 
00347       // Expect one or the other to have a root_type.
00348       if (!root_type && !right.root_type)
00349       {
00350          EDOC_MERGE_ERROR("Unable to merge two incomplete types.");
00351       }
00352       else if (!root_type)
00353       {
00354          root_type = dict.types.AlwaysGet(*right.root_type);
00355       }
00356       else if (!root_type)
00357       {
00358          // Do nothing.
00359          EDOC_ASSERT(root_type, "");
00360       }
00361       else if (root_type->GetNormalisedName() != right.root_type->GetNormalisedName())
00362       {
00363          EDOC_MERGE_ERROR("Cant merge types with differing root_type types.");
00364       }
00365 
00366 
00367       // Merge identical to fields.
00368       for (size_t i = 0; i < right.identical.size(); i++)
00369       {
00370          // Dont add duplicates.
00371          Type* t = dict.types.AlwaysGet(*right.identical[i]);
00372          for (size_t j = 0; j < identical.size() && t; j++)
00373          {
00374             if (t == identical[j])
00375             {
00376                t = NULL;
00377             }
00378          }
00379 
00380          if (t)
00381          {
00382             identical.push_back(t);
00383          }
00384       }
00385 
00386       // Merge catchable by fields.
00387       for (size_t i = 0; i < right.catchable.size(); i++)
00388       {
00389          // Dont add duplicates.
00390          Type* t = dict.types.AlwaysGet(*right.catchable[i]);
00391          for (size_t j = 0; j < catchable.size() && t; j++)
00392          {
00393             if (t == catchable[j])
00394             {
00395                t = NULL;
00396             }
00397          }
00398 
00399          if (t)
00400          {
00401             catchable.push_back(t);
00402          }
00403       }
00404 
00405       // Merge the file references
00406       EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00407       {
00408          PushBackUnique(referenced_in_files,
00409             dict.files.AlwaysGet(*(*it)));
00410       }
00411 
00412       // After doing this we are assumed to be populated.
00413       populated = true;
00414    }
00415 
00416    //===========================================================================
00417    bool Type::IsCaughtBy(const Type& right) const
00418    {
00419       //returns true if this type is catchable by the type passed in as "right".
00420 
00421       if (&right == this)
00422       {
00423          return true;
00424       }
00425 
00426       if (right.name == "...")
00427       {
00428          return true;
00429       }
00430 
00431       if (!throw_type || !right.throw_type)
00432       {
00433          EDOC_THROW_EXCEPTION(BugException, "@@@Brendon", "");
00434       }
00435 
00436       if (right.throw_type == throw_type)
00437       {
00438          return true;
00439       }
00440 
00441       // @@@Brendon Do i want to take into account identical types?
00442       
00443       // Check to see if the type on the right is in our catchable list. I.e.
00444       // Can this be caught by right
00445       for (size_t i = 0; i < throw_type->catchable.size(); i++)
00446       {
00447          if (throw_type->catchable[i] == right.throw_type)
00448          {
00449             return true;
00450          }
00451       }
00452 
00453       // No matching catch.
00454       return false;
00455    }
00456 
00457    //===========================================================================
00458    void Type::Write(PersistenceIFace& file) const
00459    {
00460       file.WriteString(KEY_CANONICAL_NAME, name);
00461       file.WriteBoolean(KEY_EXTERNAL_LINKAGE, external_linkage);
00462       if (!external_linkage)
00463       {
00464          file.WriteUInt32Debug(KEY_TRANSLATION_UNIT, 
00465             dict.GetTranslationUnitIndex(translation_unit),
00466             translation_unit->GetName());
00467       }
00468       
00469       
00470       file.WriteUInt32Debug(KEY_THROW_TYPE, throw_type->GetIndex(),
00471          throw_type->name);
00472       file.WriteUInt32Debug(KEY_ROOT_TYPE, root_type->GetIndex(), root_type->name);
00473 
00474       loc.Write(file);
00475 
00476       file.WriteUInt32(KEY_IDENTICAL_TYPE_LS, identical.size());
00477       for (size_t i = 0; i < identical.size(); i++)
00478       {
00479          file.WriteUInt32Debug(KEY_IDENTICAL_TYPE_LI, identical[i]->GetIndex(), 
00480             identical[i]->name);
00481       }
00482 
00483       file.WriteUInt32(KEY_CATCHABLE_TYPE_LS, catchable.size());
00484       for (size_t i = 0; i < catchable.size(); i++)
00485       {
00486          file.WriteUInt32Debug(KEY_CATCHABLE_TYPE_LI, catchable[i]->GetIndex(), 
00487             catchable[i]->name);
00488       }
00489 
00490       file.WriteUInt32(KEY_REFERENCE_FILES_LS, referenced_in_files.size());
00491       EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
00492       {
00493          file.WriteUInt32Debug(KEY_REFERENCE_FILE, (*it)->GetIndex(),
00494             (*it)->GetKeyName());
00495       }
00496    }
00497    //===========================================================================
00498    bool Type::IsEquivilant(const Type& right) const
00499    {
00500       if (this == &right)
00501       {
00502          return true;
00503       }
00504 
00505       // If the types have the same key names then they are the same and no
00506       // additional checks need to be performed.
00507       if (GetKeyName() == right.GetKeyName())
00508       {
00509          return true;
00510       }
00511       
00512       // If eithre of the root types do not have external linkage then we must
00513       // assume they are equal.
00514       if (root_type->external_linkage &&
00515          right.root_type->external_linkage)
00516       {
00517          // If both have external linkage and the key names as above differ then
00518          // they are definatly different types.
00519          return false;
00520       }
00521       else
00522       {
00523          return true;
00524       }
00525    }
00526    //===========================================================================
00527    //@@@Brendon Possibly use special C++ type conversion functions.
00528    #define EDOC_REPLACE(DataType, Data, From, To, Count) \
00529       if ((void*)Data == From) {Data = (DataType*)To; Count++;}
00530    //===========================================================================
00531    size_t Type::ReplaceReferences(PStack& stack, void* remove, 
00532       void* replace)
00533    {
00534       size_t count = 0;
00535       if (!stack.Push(this))
00536       {
00537          return count;
00538       }
00539 
00540       //if (!external_linkage)
00541       //{
00542       //   //count += translation_unit->ReplaceReferences(stack, remove,
00543       //         replace);
00544       //   //EDOC_REPLACE(File, translation_unit, remove, replace, count);
00545       //}
00546       
00547       EDOC_REPLACE(Type, throw_type, remove, replace, count);
00548       EDOC_REPLACE(Type, root_type, remove, replace, count);
00549 
00550       for (size_t i = 0; i < identical.size(); i++)
00551       {
00552          EDOC_REPLACE(Type, identical[i], remove, replace, count);
00553       }
00554 
00555       for (size_t i = 0; i < catchable.size(); i++)
00556       {
00557          EDOC_REPLACE(Type, catchable[i], remove, replace, count);
00558       }
00559 
00560       count += loc.ReplaceReferences(stack, remove, replace);
00561 
00562       EDOC_FOREACH(FilePList, it, referenced_in_files)
00563       {
00564          EDOC_REPLACE(File, (*it), remove, replace, count);
00565       }
00566 
00567       return count;
00568    }
00569    //===========================================================================
00570    void Type::Validate(PStack& stack, const Dictionary& dict_in) const
00571    {
00572       // @@@Brendon Validate that the keyname from StringIdentifiedObject is the
00573       // same as what we would calculate the keyname to be from our internal
00574       // data. Mismatches may occur from assignment operator.
00575       StackRef ref(stack, this);
00576       if (!ref)
00577       {
00578          return;
00579       }
00580       
00581       EDOC_ASSERT(&dict == &dict_in, 
00582          "Current dict: " << &dict 
00583          << "\nRequired dict: " << &dict_in
00584          << "\nKey: " << key_name
00585          << "\nIndex: " << index);
00586       EDOC_ASSERT(populated, "");
00587       EDOC_ASSERT(dict_in.types.Get(GetKeyName()) == this, 
00588          "Our address: " << (const void*)this 
00589          << ", dicts address: " << (const void*)dict_in.types.Get(GetKeyName())
00590          << " type: " << *this
00591          << " types scoped name: " << GetKeyName());
00592 
00593       if (!external_linkage)
00594       {
00595          EDOC_ASSERT(translation_unit, *this);
00596          //translation_unit->Validate(stack, dict_in);
00597       }
00598       else
00599       {
00600          EDOC_ASSERT(!translation_unit, *this);
00601       }
00602       
00603       EDOC_ASSERT(throw_type, *this);
00604       throw_type->Validate(stack, dict_in);
00605 
00606       EDOC_ASSERT(root_type, *this);
00607       root_type->Validate(stack, dict_in);
00608 
00609       for (size_t i = 0; i < identical.size(); i++)
00610       {
00611          EDOC_ASSERT(identical[i], *this);
00612          identical[i]->Validate(stack, dict_in);
00613       }
00614 
00615       for (size_t i = 0; i < catchable.size(); i++)
00616       {
00617          EDOC_ASSERT(catchable[i], *this);
00618          catchable[i]->Validate(stack, dict_in);
00619       }
00620 
00621       loc.Validate(stack, dict_in);
00622       
00623       // Also test the "caches".
00624       EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
00625       {
00626          (*it)->Validate(stack, dict_in);
00627       }
00628    }
00629    //===========================================================================
00630    std::string Type::GetNameInternal() const
00631    {
00632       // The name of the type includes the file if it does not have external
00633       // linkage. I.e. When does not have external linkage the type is private
00634       // to the translation unit.
00635       std::ostringstream stream;
00636       if (!external_linkage)
00637       {
00638          stream << translation_unit->GetID() << ":" 
00639             << translation_unit->GetName() << ":" 
00640             << loc.line << ":"
00641             << name;
00642          return stream.str();
00643       }
00644       else
00645       {
00646          return name;
00647       }
00648    }
00649    //===========================================================================
00650 
00651 }

Generated on Tue Jan 20 18:26:07 2009 for EDoc-0.2.1 by  doxygen 1.5.1