1 /***************************************************************************
2                           envt.hpp  -  the environment for each GDL module
3                              -------------------
4     begin                : July 22 2002
5     copyright            : (C) 2002 by Marc Schellens
6     email                : m_schellens@users.sourceforge.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 #ifndef ENVT_HPP_
19 #define ENVT_HPP_
20 
21 #include <limits>
22 #include <vector>
23 #include <cstdlib>
24 
25 #include "typedefs.hpp"
26 #include "str.hpp"
27 #include "dpro.hpp"
28 #include "datatypes.hpp"
29 #include "dstructgdl.hpp"
30 #include "datalistt.hpp"
31 #include "extrat.hpp"
32 #include "calendar.hpp"
33 
34 //#define GDL_DEBUG
35 #undef GDL_DEBUG
36 
37 class DInterpreter;
38 
39 namespace lib {
40   BaseGDL* obj_new( EnvT* e);
41   void obj_destroy( EnvT* e);
42 }
43 
44 
45 
46 class EnvBaseT
47 {
48 private:
49   //   typedef std::deque<BaseGDL*> ContainerT;
50   typedef ExprListT ContainerT;
51 
52   //   SizeT toDestroyInitialIndex;
53 
EnvBaseT()54   EnvBaseT(){}
55 
56 protected:
57   // stores all data which has to deleted upon destruction
58   ContainerT toDestroy;
59   //   static ContainerT toDestroy;
60 
61 public:
62   // needed to delete temporary ptr parameters only after subroutine completion
63   // 'guards' a newly created variable which should be deleted
64   // upon library routines exit (normal or on error)
65   // elimates the need of auto_ptr and in some places later destruction is needed
66 
DeleteAtExit(BaseGDL * toGuard)67   void DeleteAtExit( BaseGDL* toGuard)
68   {
69     //	if( toDestroy == NULL)
70     //		toDestroy = new ContainerT();
71     toDestroy.push_back( toGuard);
72   }
73 
74 protected:
75 
76   // for obj cleanup
77   static std::set< DObj> inProgress;
78 
79   static DInterpreter* interpreter;
80   DataListT         env;
81   SizeT                parIx;     // ix of next parameter to put
82   DSub*              pro;
83   ProgNodeP      callingNode;
84   int			          lineNumber;
85   bool                 obj;       // member subroutine?
86   ExtraT*            extra;
87 
88   EnvBaseT*      newEnvOff;
89 
90   // finds the local variable pp points to
91   //   int FindLocalKW( BaseGDL** pp) { return env.FindLocal( pp);}
92 private:
93   BaseGDL** ptrToReturnValue;
94 public:
95 
SetPtrToReturnValue(BaseGDL ** p)96   void SetPtrToReturnValue(BaseGDL** p) { ptrToReturnValue = p;}
GetPtrToReturnValueNull()97   BaseGDL** GetPtrToReturnValueNull() { BaseGDL** p = ptrToReturnValue;ptrToReturnValue=NULL;return p;}
GetPtrToReturnValue() const98   BaseGDL** GetPtrToReturnValue() const { return ptrToReturnValue;}
GetPtrToGlobalReturnValue()99   BaseGDL** GetPtrToGlobalReturnValue()
100   {
101     if( ptrToReturnValue == NULL)
102       return NULL;
103     if( env.InLoc(ptrToReturnValue))
104       {
105 	*ptrToReturnValue = NULL; // steal local value
106 	return NULL; // return as not global
107       }
108     return ptrToReturnValue;
109 
110   }
InLoc(BaseGDL ** pp)111   bool InLoc( BaseGDL** pp)
112   {
113     return env.InLoc(pp);
114   }
115 
116 
117   void SetKW( SizeT ix, BaseGDL* newVal);
118 
119   // used by the interperter returns the keyword index, used for UD functions
120   // and used by WRAPPED subroutines
121   int GetKeywordIx( const std::string& k);
122 
123 
124   int findvar(const std::string& s);
125   int findvar(BaseGDL* delP);
126   bool Remove(int* rindx);
127   bool Removeall();
128 
StealLocalKW(SizeT ix)129   bool StealLocalKW( SizeT ix)
130   {
131     if( LocalKW( ix))
132       {
133 	env.Clear( ix);
134 	return true;
135       }
136     return false;
137   }
138 
139   //   bool StealLocalKW( BaseGDL** ref)
140   //   {
141   //    if( !env.InLoc( pp))
142   //      return false;
143   //
144   //    *ref = NULL;
145   //     return true;
146   //   }
147 
LocalKW(SizeT ix) const148   bool LocalKW( SizeT ix) const
149   {
150     if( ix >= env.size()) return false;
151     return ( env.Loc( ix) != NULL);
152   }
153 
GlobalKW(SizeT ix) const154   bool GlobalKW( SizeT ix) const
155   {
156     if( ix >= env.size()) return false;
157     return ( env.Env( ix) != NULL);
158   }
159 
160   bool KeywordSet( SizeT ix);
161   //as KeyWordSet but return true if KW is not present/defined (for logical that default to true)
162   bool BooleanKeywordAbsentOrSet( SizeT ix);
163 protected:
164   // for HEAP_GC
165   static void AddStruct( DPtrListT& ptrAccessible,  DPtrListT& objAccessible,
166 			 DStructGDL* stru);
167   static void AddPtr( DPtrListT& ptrAccessible, DPtrListT& objAccessible,
168 		      DPtrGDL* ptr);
169   static void AddObj( DPtrListT& ptrAccessible, DPtrListT& objAccessible,
170 		      DObjGDL* obj);
171   static void Add( DPtrListT& ptrAccessible, DPtrListT& objAccessible,
172 		   BaseGDL* p);
173 
174   // definition in list.cpp
175   static void AddLIST( DPtrListT& ptrAccessible,
176 		       DPtrListT& objAccessible, DStructGDL* listStruct);
177 
178 
179 public:
180   // 	void DebugInfo()
181   // 	{
182   // 		std::cout << this->pro->ObjectName() << std::endl;
183   // 	}
184 
GetNewEnv()185   EnvBaseT* GetNewEnv() {return newEnvOff; }
SetNewEnv(EnvBaseT * nE)186   void SetNewEnv( EnvBaseT* nE) { newEnvOff = nE;}
187 
188   virtual void ObjCleanup( DObj actID);
189 
190   // for CLEANUP calls due to reference counting
191   void PushNewEmptyEnvUD(  DSubUD* newPro, DObjGDL** newObj = NULL);
192   //   void PushNewEmptyEnvUDWithExtra(  DSubUD* newPro, BaseGDL** newObj = NULL);
193 
194   void AddEnv( DPtrListT& ptrAccessible, DPtrListT& objAccessible);
195   void AddToDestroy( DPtrListT& ptrAccessible, DPtrListT& objAccessible);
196 
~EnvBaseT()197   virtual ~EnvBaseT()
198   {
199     delete extra;
200     // 	delete toDestroy; // cleans up its content
201     /*    for( SizeT i=toDestroyInitialIndex; i<toDestroy.size(); ++i)
202 	  {
203 	  delete toDestroy[i];
204 	  }
205 	  toDestroy.resize( toDestroyInitialIndex);*/
206     //      for( ContainerT::iterator i=toDestroy.begin();
207     //  	 i != toDestroy.end(); ++i)
208     //        delete *i;
209   }
210 
211   EnvBaseT( ProgNodeP cN, DSub* pro_);
212 
213   static SizeT NewObjHeap( SizeT n=1, DStructGDL* v=NULL);
214   static SizeT NewHeap( SizeT n=1, BaseGDL* v=NULL);
215   static void FreeObjHeap( DObj id);
216   static void FreeHeap( DPtr id);
217   static void FreeHeap( DPtrGDL* p);
218   static DStructGDL* GetObjHeap( DObj ID);
219   static BaseGDL* GetHeap( DPtr ID);
220 
GetLineNumber()221   int GetLineNumber()
222   {
223     return lineNumber;
224   }
SetLineNumber(int l)225   void SetLineNumber(int l)
226   {
227     lineNumber = l;
228   }
CompileOpt()229   unsigned int CompileOpt()
230   {
231     DSubUD* proUD = dynamic_cast<DSubUD*>(pro);
232     if( proUD == NULL)
233       throw GDLException("Intenal error: CompileOpt called non DSub object.");
234     return proUD->GetCompileOpt();
235   }
SetCompileOpt(unsigned int cOpt)236   void SetCompileOpt( unsigned int cOpt)
237   {
238     DSubUD* proUD = dynamic_cast<DSubUD*>(pro);
239     if( proUD == NULL)
240       throw GDLException("Intenal error: CompileOpt called non DSub object.");
241     proUD->SetCompileOpt( cOpt);
242   }
243 
244   // raise an exception from within a library function
245   // automatically cares for adding line/column info and the
246   // function name. 's' should be set to the 'raw' error message
247   // saves some typing :-)
Throw(const std::string & s)248   void Throw( const std::string& s)
249   { throw GDLException( CallingNode(), pro->ObjectName()+": "+s, false, false);}
250 
251   // finds the global variable pp (used by arg_present function)
FindGlobalKW(BaseGDL ** pp)252   int FindGlobalKW( BaseGDL** pp) { return env.FindGlobal( pp);}
253 
254   // checks if pp points to a local variable
IsLocalKW(BaseGDL ** pp) const255   bool IsLocalKW( BaseGDL** pp) const { return env.InLoc( pp);}
256 
257   //   void RemoveLoc( BaseGDL* p) { env.RemoveLoc( p);}
258 
259   // called after parameter definition
260   void ResolveExtra();
261   friend class ExtraT;
262 
263   // used by compiler and from EnvT (for variable number of paramters)
AddEnv()264   SizeT AddEnv()
265   {
266     SizeT s = env.size();
267     env.AddOne();
268     return s;
269   }
270 
DelEnv()271   void DelEnv()
272   {
273     env.pop_back();
274   }
275 
276   // the upper (calling) environment
277   // a EnvT must have always a /*EnvUDT*/ caller
278   // i.e. library functions never call each other
279   // with a new EnvT environment
280   // for library subroutines, get the EnvUDT from which they are called
281   EnvBaseT* Caller();
282 
283   // returns environment data, by value (but that by C++ reference)
GetKW(SizeT ix)284   BaseGDL*& GetKW(SizeT ix) { return env[ix];}
285 
286   // used by HELP, SetNextPar(...)
EnvSize() const287   SizeT EnvSize() const { return env.size();}
288 
289   // next four are used by Parameter...(...) functions
290   void SetNextParUnchecked( BaseGDL* const nextP); // by value (reset loc)
291   void SetNextParUnchecked( BaseGDL** const nextP); // by reference (reset env)
292   void SetNextParUncheckedVarNum( BaseGDL* const nextP); // by value (reset loc)
293   void SetNextParUncheckedVarNum( BaseGDL** const nextP); // by reference (reset env)
294   // these are used outside Parameter functions
295   void SetNextPar( BaseGDL* const nextP); // by value (reset loc)
296   void SetNextPar( BaseGDL** const nextP); // by reference (reset env)
297   void SetKeyword( const std::string& k, BaseGDL* const val);  // value
298   void SetKeyword( const std::string& k, BaseGDL** const val); // reference
299 
300   // to check if a lib function returned a variable of this env
301   //   bool Contains( BaseGDL* p) const;
302 
303   //   BaseGDL** GetPtrTo( BaseGDL* p);
304 
Interpreter() const305   DInterpreter* Interpreter() const { return interpreter;}
306 
IsObject() const307   bool  IsObject() const { return obj;}
GetPro() const308   DSub* GetPro()   const { return pro;}
309 
CallingNode()310   ProgNodeP CallingNode() { return callingNode;}
311 
312   SizeT NParam( SizeT minPar = 0); //, const std::string& subName = "");
313 
GetProName() const314   const std::string GetProName() const
315   {
316     if( pro == NULL) return "";
317     return pro->ObjectName();
318   }
319 
320   // get the name of 'i'th parameter
GetParString(SizeT i)321   const std::string GetParString( SizeT i)
322   {
323     SizeT ix= i + pro->key.size();
324     return GetString( ix);
325   }
326 
327   // get the name of 'ix'th environment entry (asks 'pro')
328   const std::string GetString( SizeT ix);
329 
330   // get name of 'p'
331   const std::string GetString( BaseGDL*& p, bool calledFromHELP=false);
332 
333   //   // get name of 'p'
334   //   const std::string GetString( BaseGDL* p);
335 
336   virtual const std::string GetFilename() const=0;
337 
338   void AssureGlobalKW( SizeT ix);
339 
340   // converts parameter 'ix' if necessary and sets 'scalar'
341   void AssureLongScalarPar( SizeT ix, DLong& scalar);
342   void AssureLongScalarPar( SizeT ix, DLong64& scalar);
343   // get i'th parameter
344   // throws if not defined (ie. never returns NULL)
345   BaseGDL*& GetParDefined(SizeT i); //, const std::string& subName = "");
346 
347   bool KeywordPresent( SizeT ix);
348   bool KeywordPresentAndDefined( SizeT ix);
349 
350   void SetNextParUnckeckedVarNum(BaseGDL** arg1);
351 
352   friend class DInterpreter; // gcc 4.4 compatibility
353   friend class InProgressGuard;
354 };
355 
356 
357 // preallocates a buffer which should never be exceeded
358 // but will work with any number of elements
359 template< typename T, SizeT defaultLength> class ForInfoListT
360 {
361 public:
362   typedef T* iterator;
363 
364 private:
365   T* eArr;
366   char buf[defaultLength * sizeof(T)]; // prevent constructor calls
367   SizeT sz;
368 
369 public:
370 
ForInfoListT()371   ForInfoListT(): eArr( reinterpret_cast<T*>(buf)), sz( 0)
372   {
373   }
374 
~ForInfoListT()375   ~ForInfoListT()
376   {
377     if( eArr != reinterpret_cast<T*>(buf))
378       delete[] eArr;
379     else
380       {
381 	T* pEnd = &eArr[sz];
382 	for( T* p = &eArr[0]; p!=pEnd; ++p)
383 	  p->Clear();
384       }
385   }
386 
387   // must be called before access
InitSize(SizeT s)388   void InitSize( SizeT s)
389   {
390     assert( sz == 0);
391     if( s == 0)
392       return;
393     sz = s;
394     if( s < defaultLength)
395       {
396 	for( SizeT i=0; i<s; ++i)
397 	  eArr[ i].Init();
398 	return;
399       }
400     eArr = new T[ s]; // constructor called
401   }
402   // only needed for EXECUTE
resize(SizeT s)403   void resize( SizeT s)
404   {
405     if( s == sz)
406       return;
407     if( s < sz) // shrink
408       {
409 	for( SizeT i=s; i<sz; ++i)
410 	  eArr[ i].ClearInit(); // in case eArr was allocated
411 	sz = s;
412 	return;
413       }
414     // s > sz -> grow
415     if( s <= defaultLength && eArr == reinterpret_cast<T*>(buf))
416       {
417 	for( SizeT i=sz; i<s; ++i)
418 	  eArr[ i].Init();
419 	sz = s;
420 	return;
421       }
422     // this should never happen (or only in extreme rarely cases)
423     // the performance will go down
424     // s > defaultLength
425     T* newArr = new T[ s]; // ctor called
426     if( eArr != reinterpret_cast<T*>(buf))
427       {
428 	for( SizeT i=0; i<sz; ++i)
429 	  {
430 	    newArr[i] = eArr[ i];
431 	    eArr[ i].Init(); // prevent dtor from freeing
432 	  }
433 	delete[] eArr;
434       }
435     else
436       {
437 	for( SizeT i=0; i<s; ++i)
438 	  {
439 	    newArr[i] = eArr[ i];
440 	  }
441       }
442     eArr = newArr;
443     sz = s;
444   }
445   // T operator[]( SizeT i) const { assert( i<sz);  return eArr[i];}
operator [](SizeT i)446   T& operator[]( SizeT i) { assert( i<sz);  return eArr[i];}
size() const447   SizeT size() const { return sz;}
begin() const448   iterator begin() const { return &eArr[0];}
end() const449   iterator end() const { return &eArr[sz];}
empty() const450   bool empty() const { return sz == 0;}
front()451   T& front() { return eArr[0];}
front() const452   const T& front() const { return eArr[0];}
back()453   T& back() { return eArr[sz-1];}
back() const454   const T& back() const { return eArr[sz-1];}
455 };
456 
457 
458 
459 // for UD subroutines (written in GDL) ********************************
460 class EnvUDT: public EnvBaseT
461 {
462   // static std::deque< void*> freeList;
463   static FreeListT freeList;
464 
465 public:
466   static 	void* operator new( size_t bytes);
467   static	void operator delete( void *ptr);
468 
469   enum CallContext {
470     RFUNCTION = 0
471     ,LFUNCTION
472     ,LRFUNCTION
473   };
474 
475 private:
476   ForInfoListT<ForLoopInfoT, 32> forLoopInfo;
477   // std::vector<ForLoopInfoT> forLoopInfo;
478 
479   ProgNodeP         ioError;
480   DLong             onError; // on_error setting
481   BaseGDL**         catchVar;
482   ProgNodeP         catchNode;
483   CallContext       callContext; // assignment paramter for functions as l_value
484   SizeT             nJump; // number of jumps in current environment
485   int               lastJump; // to which label last jump went
486 
487 public:
GetForLoopInfo(int forIx)488   ForLoopInfoT& GetForLoopInfo( int forIx) { return forLoopInfo[forIx];}
489 
NForLoops() const490   int NForLoops() const { return forLoopInfo.size();}
ResizeForLoops(int newSize)491   void ResizeForLoops( int newSize) { forLoopInfo.resize(newSize);}
492 
493   // UD pro/fun
494   EnvUDT( ProgNodeP idN, DSubUD* pro_, CallContext lF = RFUNCTION);
495 
496   // member procedure
497   EnvUDT( ProgNodeP idN, BaseGDL* self,
498 	  const std::string& parent="");
499   // member function
500   EnvUDT( BaseGDL* self, ProgNodeP idN,
501 	  const std::string& parent="", CallContext lF = RFUNCTION);
502 
503 
504   // for obj_new and obj_destroy
505   //EnvUDT( EnvBaseT* pEnv, DSub* newPro, BaseGDL** self);
506   EnvUDT( ProgNodeP callindNode_, DSubUD* newPro, DObjGDL** self);
507 
GetOnError() const508   DLong GetOnError() const { return onError;}
509 
GetCatchNode() const510   ProgNodeP GetCatchNode() const { return catchNode;}
GetCatchVar() const511   BaseGDL** GetCatchVar() const { return catchVar;}
512 
NJump() const513   SizeT NJump() const { return nJump;}
LastJump() const514   int   LastJump() const { return lastJump;}
GotoTarget(int ix)515   ProgNodeP GotoTarget( int ix)
516   {
517     lastJump = ix; //static_cast<DSubUD*>( pro)->LabelOrd( ix);
518     ++nJump;
519     return static_cast<DSubUD*>( pro)->GotoTarget( ix);
520   }
GetCallContext() const521   CallContext GetCallContext() const { return callContext;} // left-function
SetCallContext(CallContext cC)522   void SetCallContext(CallContext cC) { callContext = cC;} // left-function
523 
SetIOError(int targetIx)524   void SetIOError( int targetIx)
525   { // this isn't a jump
526     if( targetIx != -1)
527       ioError = static_cast<DSubUD*>( pro)->GotoTarget( targetIx)->
528 	getNextSibling();
529     else
530       ioError = NULL;
531   }
GetIOError()532   ProgNodeP GetIOError() { return ioError;}
533 
GetFilename() const534   const std::string GetFilename() const
535   {
536     DSubUD* subUD=static_cast<DSubUD*>( pro);
537     return subUD->GetFilename();
538   }
539 
540   //   // for internal non-library routines (e.g. operator overloads) ('this' is on the stack)
541   //   EnvUDT* CallingEnv();
542 
543   friend class DInterpreter;
544   friend class EnvT;
545 };
546 
547 
548 // for library subroutines **************************************
549 // this contains the library function API ***********************
550 class EnvT: public EnvBaseT
551 {
552   static std::vector< void*> freeList;
553 
554 public:
555   static 	void* operator new( size_t bytes);
556   static	void operator delete( void *ptr);
557 
558   // Please use non library API (see below) function with caution
559   // (most of them can be ignored by library function authors)
560 public:
~EnvT()561   ~EnvT()
562   {
563   }
564 
565   EnvT( ProgNodeP cN, DSub* pro_);
566 
567   // for obj_new and obj_destroy
568   EnvT( EnvT* pEnv, DSub* newPro, DObjGDL** self);
569 
570   void HeapGC( bool doPtr, bool doObj, bool verbose);
571   void ObjCleanup( DObj actID);
572 
573   // used by obj_new (basic_fun.cpp)
574   EnvT* NewEnv(  DSub* newPro, SizeT skipP, DObjGDL** newObj=NULL);
575   EnvUDT* PushNewEnvUD(  DSubUD* newPro, SizeT skipP, DObjGDL** newObj=NULL);
576   // for exclusive use by lib::on_error
577   void OnError();
578   // for exclusive use by lib::catch_pro
579   void Catch();
580 
GetFilename() const581   const std::string GetFilename() const
582   {
583     static const std::string internal(INTERNAL_LIBRARY_STR);
584     return internal;
585   }
586 
587   // *************************
588   // API for library functions
589   // *************************
590 
591   //   // raise an exception from within a library function
592   //   // automatically cares for adding line/column info and the
593   //   // function name. 's' should be set to the 'raw' error message
594   //   // saves some typing :-)
595   //   void Throw( const std::string& s)
596   //   { throw GDLException( CallingNode(), pro->ObjectName()+": "+s);}
597 
598   // From now on all library functions which return a l-value must
599   // call SetPtrToReturnValue with the ptr to the returned value
SetPtrToReturnValue(BaseGDL ** p)600   void SetPtrToReturnValue(BaseGDL** p) { EnvBaseT::SetPtrToReturnValue(p);}
601 
602   // will print the message (can be multiline) and exit
603   // first usage in "math_fun_ac.cpp"
604   void Help(const std::string s_help[], int size_of_s);
605 
606   // returns environment data, by value (but that by C++ reference)
607   // in EnvBaseT
608   //   BaseGDL*& GetKW(SizeT ix) { return env[ix];}
609 
610   // it is now possible to define a niminum number of parameters for library subroutines
611   // if this is done the next function can be used
612   //   BaseGDL*& GetParUnchecked(SizeT i);
613 
614   // returns the ix'th parameter (NULL if not defined)
615   BaseGDL*& GetPar( SizeT i);
616 
617   // get i'th parameter
618   // throws if not defined (ie. never returns NULL)
619   BaseGDL*& GetParDefined(SizeT i); //, const std::string& subName = "");
620 
621   // throw for GDL_STRING, GDL_STRUCT, GDL_PTR and GDL_OBJ
GetNumericParDefined(SizeT ix)622   BaseGDL*& GetNumericParDefined( SizeT ix)
623   {
624     BaseGDL*& p0 = GetParDefined( ix);
625     if( NumericType( p0->Type()))
626       return p0;
627 
628     // AC 2014-08-14 : in fact, in most case, a tentative of String to Numeric
629     // convertion is done. E.g. invert(['1']) is OK !
630     //    if( p0->Type() == GDL_STRING)
631     //  Throw( "String expression not allowed in this context: "+GetParString(ix));
632     if( p0->Type() == GDL_STRUCT)
633       Throw( "Struct expression not allowed in this context: "+GetParString(ix));
634     if( p0->Type() == GDL_PTR)
635       Throw( "Pointer expression not allowed in this context: "+GetParString(ix));
636     if( p0->Type() == GDL_OBJ)
637       Throw( "Object reference not allowed in this context: "+GetParString(ix));
638 
639     assert( false);
640     return p0;
641   }
642 
643   // throw for non-Arrays
GetNumericArrayParDefined(SizeT ix)644   BaseGDL*& GetNumericArrayParDefined( SizeT ix)
645   {
646     BaseGDL*& p0 = GetNumericParDefined( ix);
647     if (p0->Rank() != 0) return p0;
648     Throw("Expression must be an array in this context: "+GetParString(ix));
649     assert(false);
650     throw;
651   }
652 
653   // get i'th parameter
654   // throws if not global (might be NULL), for assigning a new variable to
655   // (write only)
656   BaseGDL*& GetParGlobal(SizeT i);
657 
658   // get the pIx'th paramter and converts it to T if necessary
659   // implies that the parameter must be defined
660   // if it converts it cares for the destruction of the copy
661   // CAUTION: this is for *read only* data, as the returned data might
662   // be a copy or not
663   template <typename T>
GetParAs(SizeT pIx)664   T* GetParAs( SizeT pIx)
665   {
666     BaseGDL* p = GetParDefined( pIx);
667     if( p->Type() == T::t)
668       return static_cast<T*>( p);
669     //     T* res = dynamic_cast<T*>( p);
670     //     if( res != NULL) return res;
671     T* res = static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
672     this->DeleteAtExit( res);
673     return res;
674   }
675   // same as before for keywords
676   template <typename T>
GetKWAs(SizeT ix)677   T* GetKWAs( SizeT ix)
678   {
679     BaseGDL* p = GetKW( ix);
680     if( p == NULL)
681       Throw( "Keyword is undefined: "+GetString( ix));
682     if( p->Type() == T::t)
683       return static_cast<T*>( p);
684     //     T* res = dynamic_cast<T*>( p);
685     //     if( res != NULL) return res;
686     T* res = static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
687     this->DeleteAtExit( res);
688     return res;
689   }
690 
691   // next two same as last two, but return NULL if parameter/keyword is not defined
692   template <typename T>
IfDefGetParAs(SizeT pIx)693   T* IfDefGetParAs( SizeT pIx)
694   {
695     BaseGDL* p = GetPar( pIx);
696     if( p == NULL) return NULL;
697     if( p->Type() == T::t)
698       return static_cast<T*>( p);
699     //     T* res = dynamic_cast<T*>( p);
700     //     if( res != NULL) return res;
701     T* res = static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
702     this->DeleteAtExit( res);
703     return res;
704   }
705   // same as before for keywords
706   template <typename T>
IfDefGetKWAs(SizeT ix)707   T* IfDefGetKWAs( SizeT ix)
708   {
709     BaseGDL* p = GetKW( ix);
710     if( p == NULL) return NULL;
711     if( p->Type() == T::t)
712       return static_cast<T*>( p);
713     //     T* res = dynamic_cast<T*>( p);
714     //     if( res != NULL) return res;
715     T* res = static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
716     this->DeleteAtExit( res);
717     return res;
718   }
719 
720   // returns the struct of a valid object reference or throws
721   DStructGDL* GetObjectPar( SizeT pIx);
722 
723   // returns the actual number of paramters passed to a library function
724   // minPar is the minimal number of paramters the function needs
725   // (if less it throws), subName is used for error reporting
726   SizeT NParam( SizeT minPar = 0); //, const std::string& subName = "");
727 
728   // for library functions (keyword must be exact)
729   // returns the index of keyword k
730   int KeywordIx( const std::string& k);
731 
732   // for use within library functions
733   // consider to use (note: 'static' is the point here):
734   // static int kwIx = env->KeywordIx( "KEYWORD");
735   // bool kwSet = env->KeywordSet( kwIx);
736   //
737   // instead of:
738   // bool kwSet = env->KeywordSet( "KEYWORD");
739   //
740   // this one adds some overhead, but is easy to use
741   bool KeywordSet( const std::string& kw);
742   // this one together with a static int holding the index is faster
743   // (after the first call)
744   bool KeywordSet( SizeT ix);
745   // GD added -- possibly very wrong?
746   bool KeywordPresent( const std::string& kw);
KeywordPresent(SizeT ix)747   bool KeywordPresent( SizeT ix)
748   { return EnvBaseT::KeywordPresent( ix);}
749 
750   // local/global keyword/paramter
LocalKW(SizeT ix) const751   bool LocalKW( SizeT ix) const
752   {
753     return EnvBaseT::LocalKW( ix);
754     //     if( ix >= env.size()) return false;
755     //     return ( env.Loc( ix) != NULL);
756   }
GlobalKW(SizeT ix) const757   bool GlobalKW( SizeT ix) const
758   {
759     return EnvBaseT::GlobalKW( ix);
760   }
LocalPar(SizeT ix)761   bool LocalPar( SizeT ix) { return LocalKW( ix + pro->key.size());}
StealLocalPar(SizeT ix)762   bool StealLocalPar( SizeT ix)
763   {
764     if( LocalKW( ix + pro->key.size()))
765       {
766 	env.Clear( ix + pro->key.size());
767 	return true;
768       }
769     return false;
770   }
771   // removed: IDL does not undefine the global parameter with OVERWRITE
772   //   void StealLocalParUndefGlobal( SizeT ix)
773   //   {
774   //     if( LocalKW( ix + pro->key.size()))
775   //       {
776   // 	env.Clear( ix + pro->key.size());
777   //       }
778   //       else
779   //       {
780   //       env[ ix + pro->key.size()] = NULL;
781   //       }
782   //   }
GlobalPar(SizeT ix)783   bool GlobalPar( SizeT ix) { return GlobalKW( ix + pro->key.size());}
784 
785   // next two to set keywords/paramters
786   // note that the value MUST be created in the library function
787   // with operator new
788   // Before it must be tested with KeywordPresent() or NParam() if
789   // the keyword/paramter is present
790   // this is not done automatically because its more effective, to
791   // create the data (newVal) only if its necessary
792   // if the functions throw, they delete newVal before -> no
793   // guarding of newVal is needed
794   //   void SetKW( SizeT ix, BaseGDL* newVal);
795   void SetPar( SizeT ix, BaseGDL* newVal);
796 
797   // Assure functions:
798   // if name contains "Par" they must be used for paramters, else for keywords
799   // (the error messages are defined for this usage and the indexing is
800   // done respectively)
801 
802   // next two: NO CONVERSION (throw if wrong type)
803   // NOTE: only few functions need to be so restrictive
804   // converts parameter to scalar, throws if parameter is of different type,
805   // non-scalar or not defined
806   template <typename T>
AssureScalarPar(SizeT pIx,typename T::Ty & scalar)807   void AssureScalarPar( SizeT pIx, typename T::Ty& scalar)
808   {
809     BaseGDL* p = GetParDefined( pIx);
810     if( p->Type() != T::t)
811       Throw( "Variable must be a "+T::str+" in this context: "+
812 	     GetParString(pIx));
813     T* tp= static_cast<T*>(p);
814     if( !tp->Scalar( scalar))
815       Throw("Variable must be a scalar in this context: "+
816 	    GetParString(pIx));
817   }
818   // same as before for keywords
819   template <typename T>
AssureScalarKW(SizeT ix,typename T::Ty & scalar)820   void AssureScalarKW( SizeT ix, typename T::Ty& scalar)
821   {
822     BaseGDL* p = GetKW( ix);
823     if( p == NULL)
824       Throw("Keyword undefined: "+GetString(ix));
825     if( p->Type() != T::t)
826       Throw("Keyword must be a "+T::str+" in this context: "+
827 	    GetString(ix));
828     T* tp= static_cast<T*>(p);
829     if( !tp->Scalar( scalar))
830       Throw("Keyword must be a scalar in this context: "+
831 	    GetString(ix));
832   }
833 
834   //milder version, will convert to a given type scalar if possible.
835   template <typename T>
ProvideScalarPar(SizeT pIx,typename T::Ty & scalar)836   void ProvideScalarPar( SizeT pIx, typename T::Ty& scalar)
837   {
838     BaseGDL* p = GetParDefined( pIx);
839     if( p->Type() != T::t) Throw( "Variable must be a "+T::str+" in this context: "+ GetParString(pIx));
840     T* tp= static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
841     this->DeleteAtExit(tp);
842     if( !tp->Scalar( scalar))  Throw("Keyword must be a scalar in this context: "+GetString(pIx));
843   } // same as before for keywords
844   template <typename T>
ProvideScalarKW(SizeT ix,typename T::Ty & scalar)845   void ProvideScalarKW( SizeT ix, typename T::Ty& scalar)
846   {
847     BaseGDL* p = GetKW( ix);
848     if( p == NULL)
849       Throw("Keyword undefined: "+GetString(ix));
850     T* tp = static_cast<T*>( p->Convert2( T::t, BaseGDL::COPY));
851     this->DeleteAtExit(tp);
852     if( !tp->Scalar( scalar))  Throw("Keyword must be a scalar in this context: "+GetString(ix));
853   }
854 
855 
856   void AssureGlobalPar( SizeT pIx);
857   //   void AssureGlobalKW( SizeT ix);
858 
859   // if keyword 'kw' is not set, 'scalar' is left unchanged
860   void AssureLongScalarKWIfPresent( const std::string& kw, DLong& scalar);
861   void AssureLongScalarKWIfPresent( SizeT ix, DLong& scalar);
862   // converts keyword 'kw' if necessary and sets 'scalar'
863   void AssureLongScalarKW( const std::string& kw, DLong& scalar);
864   void AssureLongScalarKW( const std::string& kw, DLong64& scalar);
865   // converts ix'th keyword if necessary and sets 'scalar'
866   void AssureLongScalarKW( SizeT ix, DLong& scalar);
867   void AssureLongScalarKW( SizeT ix, DLong64& scalar);
868   // converts parameter 'ix' if necessary and sets 'scalar'
869   void AssureLongScalarPar( SizeT ix, DLong& scalar);
870   void AssureLongScalarPar( SizeT ix, DLong64& scalar);
871 
872   // same as for Long
873   void AssureDoubleScalarKWIfPresent( const std::string& kw, DDouble& scalar);
874   void AssureDoubleScalarKWIfPresent( SizeT ix, DDouble& scalar);
875   void AssureDoubleScalarKW( const std::string& kw, DDouble& scalar);
876   void AssureDoubleScalarKW( SizeT ix, DDouble& scalar);
877   void AssureDoubleScalarPar( SizeT ix, DDouble& scalar);
878 
879   // same as for Long
880   void AssureFloatScalarKWIfPresent( const std::string& kw, DFloat& scalar);
881   void AssureFloatScalarKWIfPresent( SizeT ix, DFloat& scalar);
882   void AssureFloatScalarKW( const std::string& kw, DFloat& scalar);
883   void AssureFloatScalarKW( SizeT ix, DFloat& scalar);
884   void AssureFloatScalarPar( SizeT ix, DFloat& scalar);
885 
886   // same as for Long
887   void AssureStringScalarKWIfPresent( const std::string& kw, DString& scalar);
888   void AssureStringScalarKWIfPresent( SizeT ix, DString& scalar);
889   void AssureStringScalarKW( const std::string& kw, DString& scalar);
890   void AssureStringScalarKW( SizeT ix, DString& scalar);
891   void AssureStringScalarPar( SizeT ix, DString& scalar);
892 
893   // to be extended on demand for other data types
894 
895   // SA: used by GDL_STRING() for VMS-compat hack
896   void ShiftParNumbering(int n);
897 };
898 
899 const int defaultStackDepth = 64;
900 class EnvStackT
901 {
902   EnvUDT** envStackFrame;
903   EnvUDT** envStack;
904 
905   SizeT top;
906   SizeT sz;
907 
908 public:
909   typedef SizeT size_type;
910   typedef EnvUDT* pointer_type;
911 
EnvStackT()912   EnvStackT(): top(0), sz(defaultStackDepth)
913   {
914     envStackFrame = new EnvUDT* [ sz+1];
915     envStack = envStackFrame + 1;
916   }
~EnvStackT()917   ~EnvStackT() { delete[] envStackFrame;}
918 
empty() const919   bool empty() const { return top == 0;}
920 
push_back(EnvUDT * b)921   void push_back( EnvUDT* b)
922   {
923     if( top >= sz)
924       {
925 	if( sz >= 32768)
926 	  throw GDLException("Recursion limit reached ("+i2s(sz)+").");
927 
928 	EnvUDT** newEnvStackFrame = new EnvUDT* [ sz + sz + 1];
929 	EnvUDT** newEnvStack = newEnvStackFrame + 1;
930 
931 	for( SizeT i=0; i<sz; ++i)
932 	  newEnvStack[ i] = envStack[ i];
933 
934 	delete[] envStackFrame;
935 	envStackFrame = newEnvStackFrame;
936 	envStack = newEnvStack;
937 	sz += sz;
938       }
939     envStackFrame[ ++top] = b;
940   }
pop_back()941   void pop_back() { assert(top>0); --top;}
back() const942   EnvUDT* back() const { assert(top>0); return envStackFrame[ top];}
size() const943   SizeT size() const { return top;}
operator [](SizeT ix) const944   EnvUDT* operator[]( SizeT ix) const { return envStack[ ix];}
operator [](SizeT ix)945   EnvUDT*& operator[]( SizeT ix) { return envStack[ ix];}
946   //   EnvUDT** begin() const { return &envStack[0];}
947   //   EnvUDT** end() const { return &envStack[sz];}
948 };
949 
950 // typedef std::deque<EnvBaseT*> EnvStackT;
951 // typedef std::deque<EnvUDT*> EnvStackT;
952 
953 #endif
954 
955 
956