/* * Copyright (c) 2002-2006 Samit Basu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef __Scope_hpp__ #define __Scope_hpp__ /** * A Scope is a combination of a variable hashtable and a function hashtable. */ #include #include #include "Array.hpp" #include "SymbolTable.hpp" typedef SymbolTable VariableTable; class Serialize; /** * A Scope is a collection of functions and variables all visible * at some point in the execution. The scope also keeps track of * the loop level, and a list of the global and persistent variables * relevant to the current scope. */ class Scope { /** * This is a mutex to protect the scope when multiple threads * have access to the scope. For all scopes (except the global * one, this mutex is unused. */ QMutex *mutex; /** * The reference count for this Scope */ int refcount; /** * This is the hash-table of Array pointers that forms the * symbol table. Each variable has a name associated with * it that must be unique to the Scope. The Scope owns the * variables in the symbol table, and is responsible for * destructing them when destroyed. */ VariableTable symTab; /** * The name of the scope. */ std::string name; /** * The loop level. This is used to track the depth of nested * loops. */ int loopLevel; /** * These are the global variables as defined in the current * scope. Global variables are not stored in this Scope, but * are deferred to the top scope in the Context. */ stringVector globalVars; /** * Persistent variables are similar to global variables in that * they are deferred to the top scope in the Context. However, * unlike global variables, persistent variables are mangled * with the name of the scope before being indexed into the global * scope. */ stringVector persistentVars; /** * This string vector contains the names of variables accessed (potentially) * in this scope. */ stringVector variablesAccessed; /** * This string vector contains the names of variables that must be local to this * scope. */ stringVector localVariables; /** * On every call to modify the scope, we have to check the global/persistent * variable table. This is generally expensive, so we cache information * about these tables being empty (the usual case). */ bool anyPersistents; bool anyGlobals; bool isNested; public: /** * Construct a scope with the given name. */ Scope(std::string scopeName, bool nested) : name(scopeName), loopLevel(0), anyPersistents(false), anyGlobals(false), isNested(nested), mutex(NULL), refcount(0) {} inline void setVariablesAccessed(stringVector varList) { variablesAccessed = varList; } inline bool variableAccessed(string varName) { for (int i=0;ilock(); } /** * Unlock the scope's mutex */ inline void unlock() { if (mutex) mutex->unlock(); } /** * Initialize the scope's mutex - only needed in Global * scope. */ inline void mutexSetup() { if (mutex) delete mutex; mutex = new QMutex(QMutex::Recursive); } /** * Insert a variable with the given name. If the variable * already exists in the Scope, then the previous definition * is replaced with the given one. */ inline void insertVariable(const std::string& varName, const Array& val) { symTab.insertSymbol(varName,val); } /** * Lookup a variable. Return a pointer to the variable in the symbol * table if found and NULL otherwise. Different than lookupFunction * because in write-back assignments (e.g., A(:,346) = b) it is critical * to manage the number of copies. */ inline Array* lookupVariable(const std::string& varName) { return(symTab.findSymbol(varName)); } /** * Add a variable name to the global variables list. */ inline void addGlobalVariablePointer(std::string varName) { if (!isVariableGlobal(varName)) { globalVars.push_back(varName); anyGlobals = true; } } inline stringVector getGlobalVariablesList() { return globalVars; } /** * Delete a variable name from the global variables list. */ inline void deleteGlobalVariablePointer(std::string varName) { stringVector::iterator i = std::find(globalVars.begin(), globalVars.end(), varName); if (*i == varName) globalVars.erase(i); if (globalVars.empty()) anyGlobals = false; } /** * Check to see if a variable is globally defined. */ inline bool isVariableGlobal(const std::string& varName) { if (!anyGlobals) return false; bool foundName = false; int i = 0; i = 0; if (globalVars.empty()) return false; while (i0); } /** * Get a list of all possible completions of the given * string. */ inline stringVector getCompletions(const std::string& prefix) { return symTab.getCompletions(prefix); } /** * Returns a list of all currently defined variables * in the active scope. */ inline stringVector listAllVariables() { stringVector names(symTab.getCompletions("")); int i; for (i=0;icountunlock(); if (!d->referenced()) delete d; } } ScopePtr(Scope* ptr) { d = ptr; if (d) d->countlock(); } ScopePtr(const ScopePtr ©) { d = copy.d; if (d) d->countlock(); } ScopePtr& operator=(const ScopePtr ©) { if (copy.d == d) return *this; if (d) { d->countunlock(); if (!d->referenced()) delete d; } d = copy.d; if (d) d->countlock(); return *this; } Scope* operator->() const { return d; } Scope& operator*() const { return *d; } bool operator!() const { return (d == NULL); } operator Scope* () const {return d;} }; #endif void FreezeScope(ScopePtr scope, Serialize *s); ScopePtr ThawScope(Serialize *s); #endif