libs/EDoc/FunctionType.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/FunctionType.h"
00022 #include "EDoc/PersistenceIFace.h"
00023 #include "EDoc/Dictionary.h"
00024 #include "EDoc/exceptions.h"
00025 #include "EDoc/Logger.h"
00026 #include "EDoc/utils.h"
00027 #include "EDoc/PStack.h"
00028 #include "EDoc/StackRef.h"
00029 
00030 #include "EDoc/Type.h"
00031 #include "EDoc/Function.h"
00032 #include "EDoc/NotificationIFace.h"
00033 
00034 #include "EDoc/persistence_data.h"
00035 #include "IndexedDictionary.h"
00036 
00037 #include <iostream>
00038 
00039 //==============================================================================
00040 /** \brief define a small macro that is called upon a merge error.
00041  */
00042 #define EDOC_MERGE_ERROR(Message) \
00043    EDOC_Error(Message); \
00044    EDOC_THROW_EXCEPTION(MergeException, \
00045       "Failed merging function type.", Message);
00046 
00047 
00048 namespace EDoc
00049 {
00050    //===========================================================================
00051    uint8_t FunctionType::GetRecordType() const
00052    {
00053       return VALUE_RECORD_TYPE_FUNCTION_TYPE;
00054    }
00055    //===========================================================================
00056    FunctionType::FunctionType(Dictionary& dict_in, std::string key_name_in) :
00057       StringIdentifiedObject(dict_in, key_name_in),
00058       return_type(NULL),
00059       method_context(NULL),
00060       is_const(false),
00061       has_exception_spec(false)
00062    {
00063    }
00064    //===========================================================================
00065    FunctionType::FunctionType(Dictionary& dict_in, int32_t index_in) :
00066       StringIdentifiedObject(dict_in, index_in),
00067       return_type(NULL),
00068       method_context(NULL),
00069       is_const(false),
00070       has_exception_spec(false)
00071    {
00072    }
00073    //===========================================================================
00074    FunctionType& FunctionType::operator=(const FunctionType& 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       full_name = right.full_name;
00084       return_type = dict.types.AlwaysGet(*right.return_type);
00085       method_context = NULL;
00086       if (right.method_context)
00087       {
00088          method_context = dict.types.AlwaysGet(*right.method_context);
00089       }
00090 
00091       Erase(parameters);
00092       for (size_t i = 0; i < right.parameters.size(); i++)
00093       {
00094          parameters.push_back(
00095             dict.types.AlwaysGet(*right.parameters[i]));
00096       }
00097       
00098       is_const = right.is_const;
00099 
00100       has_exception_spec = right.has_exception_spec;
00101       Erase(exception_spec);
00102       for (size_t i = 0; i < right.exception_spec.size(); i++)
00103       {
00104          exception_spec.push_back(
00105             dict.types.AlwaysGet(*right.exception_spec[i]));
00106       }
00107 
00108       populated = right.populated;
00109       return *this;
00110    }
00111    //===========================================================================
00112    void FunctionType::Read(PersistenceIFace& file, IndexedDictionary& idict)
00113    {
00114       size_t size = 0;
00115       
00116       full_name = file.ReadString(KEY_FULL_NAME);
00117       return_type = idict.types.AlwaysGet(file.ReadUInt32(KEY_RETURN_TYPE));
00118       is_const = file.ReadBoolean(KEY_IS_CONST);
00119       
00120       method_context = NULL;
00121       if (file.ReadBoolean(KEY_IS_METHOD))
00122       {
00123          method_context = idict.types.AlwaysGet(
00124             file.ReadUInt32(KEY_METHOD_CONTEXT));
00125       }
00126 
00127       size = file.ReadUInt32(KEY_PARAMETERS_LS);
00128       for (size_t i = 0; i < size; i++)
00129       {
00130          exception_spec.push_back(
00131             idict.types.AlwaysGet(file.ReadUInt32(KEY_PARAMETERS_LI)));
00132       }
00133 
00134 
00135       Erase(exception_spec);
00136       has_exception_spec = file.ReadBoolean(KEY_HAS_EXCEPTION_SPEC);
00137       if (has_exception_spec)
00138       {
00139          size = file.ReadUInt32(KEY_EXCEPTION_SPEC_LS);
00140          for (size_t i = 0; i < size; i++)
00141          {
00142             exception_spec.push_back(
00143                idict.types.AlwaysGet(file.ReadUInt32(KEY_EXCEPTION_SPEC_LI)));
00144          }
00145       }
00146 
00147       populated = true;
00148       SetKeyName(full_name);
00149    }
00150    //===========================================================================
00151    void FunctionType::Write(PersistenceIFace& file) const
00152    {
00153       file.WriteString(KEY_FULL_NAME, full_name);
00154       file.WriteUInt32(KEY_RETURN_TYPE, return_type->GetIndex());
00155       file.WriteBoolean(KEY_IS_CONST, is_const);
00156       
00157       file.WriteBoolean(KEY_IS_METHOD, method_context);
00158       if (method_context)
00159       {
00160          file.WriteUInt32(KEY_METHOD_CONTEXT, method_context->GetIndex());
00161       }
00162 
00163       file.WriteUInt32(KEY_PARAMETERS_LS, exception_spec.size());
00164       for (size_t i = 0; i < exception_spec.size(); i++)
00165       {
00166          file.WriteUInt32(KEY_PARAMETERS_LI, exception_spec[i]->GetIndex());
00167       }
00168 
00169 
00170       file.WriteBoolean(KEY_HAS_EXCEPTION_SPEC, has_exception_spec);
00171       if (has_exception_spec)
00172       {
00173          file.WriteUInt32(KEY_EXCEPTION_SPEC_LS, exception_spec.size());
00174          for (size_t i = 0; i < exception_spec.size(); i++)
00175          {
00176             file.WriteUInt32(KEY_EXCEPTION_SPEC_LI, 
00177                exception_spec[i]->GetIndex());
00178          }
00179       }
00180    }
00181    //===========================================================================
00182    std::ostream& FunctionType::Print(std::ostream& out, std::string prefix) const
00183    {
00184       out << prefix << "Name: " << full_name << std::endl;
00185       out << prefix << "Return Type: " << return_type->GetDeclaredName() 
00186          << std::endl;
00187       if (method_context)
00188       {
00189          out << prefix << "Method Context: " 
00190             << method_context->GetDeclaredName() << std::endl;
00191       }
00192       
00193       for (size_t i = 0; i < parameters.size(); i++)
00194       {
00195          out << prefix << "Parameter: " << parameters[i]->GetDeclaredName() 
00196             << std::endl;
00197       }
00198       
00199       if (is_const)
00200       {
00201          out << prefix << "Is Const: True" << std::endl;
00202       }
00203       else
00204       {
00205          out << prefix << "Is Const: False" << std::endl;
00206       }
00207 
00208       if (has_exception_spec)
00209       {
00210          out << prefix << "Has Throw Spec: True" << std::endl;
00211          out << "Throw spec: " << GetSpecString() << std::endl;
00212       }
00213       else
00214       {
00215          out << prefix << "Has Throw Spec: False" << std::endl;
00216       }
00217       
00218       return out;
00219    }
00220    //===========================================================================
00221    void FunctionType::Merge(const StringIdentifiedObject& right_in)
00222    {
00223       const FunctionType& right(dynamic_cast<const FunctionType&>(right_in));
00224       
00225       if (!populated)
00226       {
00227          *this = right;
00228          return;
00229       }
00230       
00231       if (full_name != right.full_name)
00232       {
00233          EDOC_MERGE_ERROR("Unable to merge two function types with "
00234             "different names. "
00235             "Left: " << full_name << ", right: " << right.full_name);
00236       }
00237       
00238       if (return_type->GetNormalisedName() != 
00239          right.return_type->GetNormalisedName())
00240       {
00241          EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00242       }
00243       
00244       if ((method_context && !right.method_context) ||
00245           (!method_context && right.method_context))
00246       {
00247          EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00248       }
00249       else if (method_context && right.method_context)
00250       {
00251          if (method_context->GetNormalisedName() != 
00252             right.method_context->GetNormalisedName())
00253          {
00254             EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00255          }
00256       }
00257       
00258       if (parameters.size() != right.parameters.size())
00259       {
00260          EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00261       }
00262       
00263       for (size_t i = 0; i < parameters.size(); i++)
00264       {
00265          if (parameters[i]->GetNormalisedName() != 
00266             right.parameters[i]->GetNormalisedName())
00267          {
00268             EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00269          }
00270       }
00271       
00272       if (is_const != right.is_const)
00273       {
00274          EDOC_MERGE_ERROR("Unable to merge two function types @@@");
00275       }
00276       
00277       // Merge exception specs with warnings, but do not emit any errors...
00278       // Warn if the exception specs differ, but the merge should inherit the
00279       // most restrictive exception spec of both.
00280       bool exception_specs_differ = false;
00281       if (has_exception_spec != right.has_exception_spec)
00282       {
00283          exception_specs_differ = true;
00284       }
00285 
00286 
00287       if (!exception_specs_differ && 
00288          (exception_spec.size() != right.exception_spec.size()))
00289       {
00290          exception_specs_differ = true;
00291       }
00292       for (size_t i = 0; !exception_specs_differ && (i < exception_spec.size());
00293          i++)
00294       {
00295          bool found = false;
00296          for (size_t j = 0; j < right.exception_spec.size(); j++)
00297          {
00298             if (right.exception_spec[j]->GetNormalisedName() == 
00299                exception_spec[i]->GetNormalisedName())
00300             {
00301                found = true;
00302                break;
00303             }
00304          }
00305 
00306          if (!found)
00307          {
00308             exception_specs_differ = true;
00309          }
00310       }
00311 
00312       // If the specs differ then set the merged to the most restrictive spec.
00313       if (exception_specs_differ)
00314       {
00315          EDOC_NOTIFICATION(WDIFF_THROW, 
00316                "Function: " << GetKeyName()
00317             << ", Declared Name: " << GetDeclaredName()
00318             << ", Left Spec:  " << GetSpecString()
00319             << ", Right Spec: " << right.GetSpecString(), 
00320             NULL, NULL, 0, NULL, 0, NULL, NULL, this, NULL)
00321          //EDOC_WARNING(WDIFF_THROW, 
00322          //      "Function: " << GetKeyName()
00323          //   << ", Declared Name: " << GetDeclaredName()
00324          //   << ", Left Spec:  " << GetSpecString()
00325          //   << ", Right Spec: " << right.GetSpecString());
00326          
00327          EDOC_Warning("Merging two functions with different exception specs."
00328             << "\nLeft Spec: " << GetSpecString()
00329             << "\nRight Spec: " << right.GetSpecString()
00330             << "\nFunction Name: " << GetKeyName());
00331 
00332          has_exception_spec = true;
00333          std::vector<Type*> merged_spec;
00334 
00335          // only add an exception if it is found in both specs.
00336          for (size_t i = 0; i < exception_spec.size(); i++)
00337          {
00338             bool found = false;
00339             for (size_t j = 0; j < right.exception_spec.size(); j++)
00340             {
00341                if (right.exception_spec[j]->GetNormalisedName() == 
00342                   exception_spec[i]->GetNormalisedName())
00343                {
00344                   found = true;
00345                   break;
00346                }
00347             }
00348 
00349             if (found)
00350             {
00351                merged_spec.push_back(exception_spec[i]);
00352             }
00353          }
00354          exception_spec = merged_spec;
00355 
00356          EDOC_Warning("Resulting merged spec is: " << GetSpecString());
00357       }
00358       
00359    }
00360    //===========================================================================
00361    std::string FunctionType::GetSpecString() const
00362    {
00363       std::ostringstream stream;
00364 
00365       if (has_exception_spec)
00366       {
00367          stream << "throws(";
00368          for (size_t i = 0; i < exception_spec.size(); i++)
00369          {
00370             if (i != 0)
00371             {
00372                stream << ", ";
00373             }
00374             if (exception_spec[i]->IsPopulated())
00375             {
00376                stream << exception_spec[i]->GetDeclaredName();
00377             }
00378             else
00379             {
00380                stream << "(UNPOPULATED: " << exception_spec[i]->GetKeyName()
00381                   <<")";
00382             }
00383          }
00384          stream << ")";
00385       }
00386 
00387       return stream.str();
00388    }
00389    //===========================================================================
00390    bool FunctionType::IsEquivilant(const FunctionType& right) const
00391    {
00392       if (this == &right)
00393       {
00394          return true;
00395       }
00396       
00397       // Check the return types.
00398       if (!return_type->IsEquivilant(*right.return_type))
00399       {
00400          return false;
00401       }
00402       
00403       // Check the parameter list sizes.
00404       if (parameters.size() != right.parameters.size())
00405       {
00406          return false;
00407       }
00408       
00409       // Check the indicitual parameters.
00410       for (size_t i = 0; i < parameters.size(); i++)
00411       {
00412          if (!parameters[i]->IsEquivilant(*right.parameters[i]))
00413          {
00414             return false;
00415          }
00416       }
00417       
00418       // If we get this far then the function pointer types are the same.
00419       // @@@Brendon Do i warn about incompatible throw specs here?
00420       return true;
00421    }
00422    //===========================================================================
00423    //@@@Brendon Possibly use special C++ type conversion functions.
00424    #define EDOC_REPLACE(DataFunctionType, Data, From, To, Count) \
00425       if ((void*)Data == From) {Data = (DataFunctionType*)To; Count++;}
00426    //===========================================================================
00427    size_t FunctionType::ReplaceReferences(PStack& stack, void* remove, 
00428       void* replace)
00429    {
00430       size_t count = 0;
00431       if (!stack.Push(this))
00432       {
00433          return count;
00434       }
00435 
00436       EDOC_REPLACE(Type, return_type, remove, replace, count);
00437       EDOC_REPLACE(Type, method_context, remove, replace, count);
00438 
00439       for (size_t i = 0; i < parameters.size(); i++)
00440       {
00441          EDOC_REPLACE(Type, parameters[i], remove, replace, count);
00442       }
00443 
00444       for (size_t i = 0; i < exception_spec.size(); i++)
00445       {
00446          EDOC_REPLACE(Type, exception_spec[i], remove, replace, count);
00447       }
00448 
00449       for (size_t i = 0; i < addressed_functions.size(); i++)
00450       {
00451          EDOC_REPLACE(Function, addressed_functions[i], remove, replace, count);
00452       }
00453 
00454       return count;
00455    }
00456    //===========================================================================
00457    void FunctionType::Validate(PStack& stack, const Dictionary& dict_in) const
00458    {
00459       // @@@Brendon Validate that the keyname from StringIdentifiedObject is the
00460       // same as what we would calculate the keyname to be from our internal
00461       // data. Mismatches may occur from assignment operator.
00462       StackRef ref(stack, this);
00463       if (!ref)
00464       {
00465          return;
00466       }
00467       
00468       EDOC_ASSERT(&dict == &dict_in, 
00469          "Current dict: " << &dict 
00470          << "\nRequired dict: " << &dict_in
00471          << "\nKey: " << key_name
00472          << "\nIndex: " << index);
00473       EDOC_ASSERT(populated, "");
00474       EDOC_ASSERT(dict_in.function_types.Get(GetKeyName()) == this, 
00475          "Our address: " << (const void*)this 
00476          << ", dicts address: " 
00477          << (const void*)dict_in.function_types.Get(GetKeyName())
00478          << " type: " << *this
00479          << " types scoped name: " << GetKeyName());
00480 
00481       EDOC_ASSERT(return_type, *this);
00482       return_type->Validate(stack, dict_in);
00483 
00484       if (method_context)
00485       {
00486          method_context->Validate(stack, dict_in);
00487       }
00488 
00489       for (size_t i = 0; i < parameters.size(); i++)
00490       {
00491          EDOC_ASSERT(parameters[i], *this);
00492          parameters[i]->Validate(stack, dict_in);
00493       }
00494 
00495       // If there is no exception spec, then the list should not have anything
00496       // in it.
00497       if (!has_exception_spec)
00498       {
00499          EDOC_ASSERT(exception_spec.size() == 0, "");
00500       }
00501 
00502       for (size_t i = 0; i < exception_spec.size(); i++)
00503       {
00504          EDOC_ASSERT(exception_spec[i], *this);
00505          exception_spec[i]->Validate(stack, dict_in);
00506       }
00507 
00508 
00509       for (size_t i = 0; i < addressed_functions.size(); i++)
00510       {
00511          EDOC_ASSERT(addressed_functions[i], *this);
00512          addressed_functions[i]->Validate(stack, dict_in);
00513       }
00514    }
00515    //===========================================================================
00516    std::string FunctionType::GetNameInternal(bool canonical) const
00517    {
00518       if (!canonical)
00519       {
00520          return full_name;
00521       }
00522       else
00523       {
00524          // Then we must construct a name based on the root types.
00525          std::ostringstream stream;
00526          
00527          stream << return_type->GetNormalisedName() << " (";
00528          if (method_context)
00529          {
00530             stream << method_context->GetNormalisedName() << "::";
00531          }
00532          stream << "*)(";
00533          for (size_t i = 0; i < parameters.size(); i++)
00534          {
00535             if (i == 0)
00536             {
00537                stream << parameters[i]->GetNormalisedName();
00538             }
00539             stream << ", " << parameters[i]->GetNormalisedName();
00540          }
00541          stream << ")";
00542          
00543          // @@@Brendon Do i include the throw spec?
00544          return stream.str();
00545       }
00546    }
00547    //===========================================================================
00548 
00549 }

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