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