1 /***************************************************************************
2                           dstructdesc.cpp  -  GDL struct descriptor
3                              -------------------
4     begin                : July 22 2002
5     copyright            : (C) 2002 by Marc Schellens
6     email                : m_schellens@users.sf.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "includefirst.hpp"
19 
20 #include <algorithm>
21 
22 #include "datatypes.hpp"
23 #include "dstructdesc.hpp"
24 #include "GDLInterpreter.hpp"
25 #include "dstructgdl.hpp"
26 
27 using namespace std;
28 
29 // store vtable in this obj file
~DStructBase()30 DStructBase::~DStructBase()
31 {
32   SizeT nTags = NTags();
33   for( SizeT i=0; i < nTags; ++i)
34     {
35       delete tags[ i];
36     }
37 }
38 
39 // DUStructDesc::~DUStructDesc()
40 // {}
41 
~DStructDesc()42 DStructDesc::~DStructDesc()
43 {
44   assert( !isUnnamed || (operatorList == NULL));
45   if( !isUnnamed) // only named structs have members and overloaded operators
46   // (usually they are never deleted only with .RESET_SESSION and .FULL_RESET_SESSION dot commands)
47   {
48     delete operatorList;
49     for(FunListT::iterator i = this->fun.begin(); i != this->fun.end(); ++i)
50       { delete *i;}
51     for(ProListT::iterator i = this->pro.begin(); i != this->pro.end(); ++i)
52       { delete *i;}
53   }
54 }
55 
FindInStructList(StructListT v,const string & s)56 DStructDesc* FindInStructList(StructListT v, const string& s)
57 {
58   StructListT::iterator f=find_if(v.begin(),v.end(),DStruct_eq(s));
59   if( f == v.end()) return NULL;
60   return *f;
61 }
FindObjectInStructList(StructListT v,const string & s)62 DStructDesc* FindObjectInStructList(StructListT v, const string& s)
63 {
64   StructListT::iterator f=find_if(v.begin(),v.end(),DStruct_eq(s));
65   if( f == v.end()) return NULL;
66   if (((*f)->FunList().size() + (*f)->ProList().size()) == 0) return NULL;
67   return *f;
68 }
ContainsStringPtrObject()69   bool DStructBase::ContainsStringPtrObject()
70   {
71    for( SizeT t=0; t<tags.size(); ++t)
72 	{
73 		if( tags[t]->Type() == GDL_STRING) return true;
74 		if( tags[t]->Type() == GDL_PTR) return true;
75 		if( tags[t]->Type() == GDL_OBJ) return true;
76 		if( tags[t]->Type() == GDL_STRUCT)
77 		{
78 			if( static_cast<DStructGDL*>( tags[t])->Desc()->ContainsStringPtrObject()) return true;
79 		}
80         }
81    return false;
82   }
83 
AddTag(const string & tagName,const BaseGDL * data)84 void DUStructDesc::AddTag( const string& tagName, const BaseGDL* data)
85 {
86   string TN = StrUpCase( tagName);  // prevent non-capitalized chars.
87   for( SizeT i=0; i < tNames.size(); i++)
88     if( tNames[i] == TN)
89       throw GDLException(TN+" is already defined "
90 			 "with a conflicting definition");
91 
92   tNames.push_back(  TN);
93   Add( data->GetTag());
94 }
95 
AddParent(DStructDesc * p)96 void DStructDesc::AddParent( DStructDesc* p)
97 {
98   SizeT nTags=p->NTags();
99   for( SizeT t=0; t < nTags; t++)
100     AddTag( p->TagName(t), (*p)[t]);
101   parent.push_back(p);
102   OperatorList* parentOperatorList = p->GetOperatorList();
103   if( parentOperatorList != NULL)
104   {
105     assert( this->operatorList == NULL); // GDL_OBJECT can only be inherited once
106     operatorList = new OperatorList(*parentOperatorList);
107   }
108 }
109 
AddParentListOnly(DStructDesc * p)110 void DStructDesc::AddParentListOnly( DStructDesc* p)
111 {
112   parent.push_back(p);
113   OperatorList* parentOperatorList = p->GetOperatorList();
114   if( parentOperatorList != NULL)
115   {
116     assert( this->operatorList == NULL); // GDL_OBJECT can only be inherited once
117     operatorList = new OperatorList(*parentOperatorList);
118   }
119 }
120 
121 // copy appropriate member subroutines from fun and pro lists
SetupOperators()122 void DStructDesc::SetupOperators()
123 {
124   assert( this->operatorList != NULL);
125   for( FunListT::iterator f = this->fun.begin(); f != this->fun.end(); ++f)
126   {
127     int ix = OverloadOperatorIndexFun( (*f)->Name());
128     if( ix != -1)
129       operatorList->SetOperator(ix,*f);
130   }
131   for( ProListT::iterator p = this->pro.begin(); p != this->pro.end(); ++p)
132   {
133     int ix = OverloadOperatorIndexPro( (*p)->Name());
134     if( ix != -1)
135       operatorList->SetOperator(ix,*p);
136   }
137 }
138 
139 // more sophisticated error messages than operator==
AssureIdentical(DStructDesc * d)140 void DStructDesc::AssureIdentical( DStructDesc* d)
141 {
142   // name is the same
143   if( NTags() != d->NTags())
144     {
145       throw GDLException( "STRUCT: "+name+": redefinition with different "
146 			  "number of tags.");
147     }
148   if( parent.size() != d->parent.size())
149     {
150       throw GDLException( "STRUCT: "+name+": redefinition with different "
151 			  "number of parents.");
152     }
153   // compare all tag names
154   // compare the tags (type and dim)
155   for( SizeT i=0; i < NTags(); i++)
156     {
157       if( TagName(i) != d->TagName(i))
158 	{
159 	  throw GDLException( "STRUCT: "+name+": "+TagName(i)+
160 			      " tag name differs in redefinition.");
161 	}
162       if( tags[i]->Dim() != d->tags[i]->Dim())
163 	{
164 	  throw GDLException( "STRUCT: "+name+": "+TagName(i)+
165 			      " tag dimension "
166 			      "differs in redefinition.");
167 	}
168 
169       // tag type is converted for convertable types
170       if( (!ConvertableType( tags[i]->Type()) ||
171 	   !ConvertableType( d->tags[i]->Type())) &&
172 	  tags[i]->Type() != d->tags[i]->Type())
173 	{
174 	  throw GDLException( "STRUCT: "+name+": "+TagName(i)+
175 			      " tag type differs in redefinition.");
176 	}
177       if( tags[i]->Type() == GDL_STRUCT)
178 	{
179 	  SpDStruct* castLeft=
180 	    static_cast<SpDStruct*>(tags[i]);
181 	  SpDStruct* castRight=
182 	    static_cast<SpDStruct*>(d->tags[i]);
183 	  DStructDesc* leftD=castLeft->Desc();
184 	  DStructDesc* rightD=castRight->Desc();
185 
186 	  if( !(*leftD == *rightD))
187 	    {
188 	      throw GDLException( "STRUCT: "+name+": "+TagName(i)+
189 				  " tag struct differs in"
190 				  " redefinition.");
191 	    }
192 	}
193     }
194   // compare all parents
195   for( SizeT i=0; i < parent.size(); i++)
196     {
197       if( parent[i] != d->parent[i])
198 	{
199 	  throw GDLException( "STRUCT: "+name+": "+parent[i]->Name()+
200 			      " parent class differs in redefinition.");
201 	}
202     }
203 }
204 
205 // two structs are equal if the contain the same datatypes in the
206 // same order (although names might differ)
operator ==(const DStructDesc & left,const DStructDesc & right)207 bool operator==(const DStructDesc& left,
208 		const DStructDesc& right)
209 {
210   // name is the same
211   if( left.NTags() != right.NTags()) return false;
212   // struct layout can be same with different inheritance
213   //  if( left.parent.size() != right.parent.size()) return false;
214   // compare all tag names
215   // compare the tags (type and dim)
216   for( SizeT i=0; i < left.NTags(); i++)
217     {
218       //      if( left.TagName(i) != right.TagName(i)) return false;
219       if( left.tags[i]->Dim() != right.tags[i]->Dim()) return false;
220       if( left.tags[i]->Type() != right.tags[i]->Type()) return false;
221       if( left.tags[i]->Type() == GDL_STRUCT)
222 	{
223 	  SpDStruct* castLeft=
224 	    static_cast<SpDStruct*>(left.tags[i]);
225 	  SpDStruct* castRight=
226 	    static_cast<SpDStruct*>(right.tags[i]);
227 	  DStructDesc* leftD=castLeft->Desc();
228 	  DStructDesc* rightD=castRight->Desc();
229 
230 	  // recursive call of operator ==
231 	  if( (leftD != rightD) && !(*leftD == *rightD))
232 	    return false;
233 	}
234     }
235   // compare all parents
236   //  for( SizeT i=0; i < left.parent.size(); i++)
237   //    {
238   //      if( left.parent[i] != right.parent[i]) return false;
239   //    }
240   return true;
241 }
242 
operator !=(const DStructDesc & left,const DStructDesc & right)243 bool operator!=(const DStructDesc& left,
244 		const DStructDesc& right)
245 {
246   return !(left == right);
247 }
248 
249 // DStructDesc* DStructDesc::FindEqual( const StructListT& sL)
250 // {
251 //   for( SizeT i=0; i<sL.size(); i++)
252 //     {
253 //       if( *this == *sL[i]) return sL[i];
254 //     }
255 //   return NULL;
256 // }
257 
GetPro(const string & pName)258 DPro* DStructDesc::GetPro( const string& pName)
259 {
260   DPro* p;
261 
262   p=FindInProList( pName);
263   if( p != NULL) return p;
264 
265   int fInIDList=FindInIDList( noDirectMembers, pName);
266   if( fInIDList == -1)
267     {
268       bool found=GDLInterpreter::SearchCompilePro( name+"__"+pName, true); // true -> search for procedure
269       if( found)
270 	{
271 	  p=FindInProList( pName);
272 	  if( p != NULL) return p;
273 	}
274       else
275 	noDirectMembers.push_back(pName);
276     }
277 
278   SizeT nParents=parent.size();
279   for( SizeT i=0; i<nParents; i++)
280     {
281       p=parent[i]->GetPro( pName);
282       if( p != NULL) return p;
283     }
284   return NULL;
285 }
286 
GetFun(const string & pName)287 DFun* DStructDesc::GetFun( const string& pName)
288 {
289   DFun* p;
290 
291   p=FindInFunList( pName);
292   if( p != NULL) return p;
293 
294   int fInIDList=FindInIDList( noDirectMembers, pName);
295   if( fInIDList == -1)
296     {
297       bool found=GDLInterpreter::SearchCompilePro( name+"__"+pName, false); // false -> search for function
298       if( found)
299 	{
300 	  p=FindInFunList( pName);
301 	  if( p != NULL) return p;
302 	}
303       else
304 	noDirectMembers.push_back(pName);
305     }
306 
307   SizeT nParents=parent.size();
308   for( SizeT i=0; i<nParents; i++)
309     {
310       p=parent[i]->GetFun( pName);
311       if( p != NULL) return p;
312     }
313   return NULL;
314 }
315 
GetPro(const string & pName,const string & parentName)316 DPro* DStructDesc::GetPro( const string& pName, const string& parentName)
317 {
318   if( !IsParent( parentName))
319     throw GDLException( parentName+" is not a parent of "+name);
320 
321   DStructDesc* d=FindInStructList( structList, parentName);
322   if( d == NULL)
323     throw GDLException("Internal error: Struct "+parentName+" not found.");
324 
325   return d->GetPro( pName);
326 }
327 
GetFun(const string & pName,const string & parentName)328 DFun* DStructDesc::GetFun( const string& pName, const string& parentName)
329 {
330   if( !IsParent( parentName))
331     throw GDLException( parentName+" is not a parent of "+name);
332 
333   DStructDesc* d=FindInStructList( structList, parentName);
334   if( d == NULL)
335     throw GDLException("Internal error: Struct "+parentName+" not found.");
336 
337   return d->GetFun( pName);
338 }
339 
340