/*
* 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 <string>
#include <QMutex>
#include "Array.hpp"
#include "SymbolTable.hpp"
typedef SymbolTable<Array> 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;i<variablesAccessed.size();i++)
if (variablesAccessed[i] == varName) return true;
return false;
}
inline stringVector getVariablesAccessedList() {
return variablesAccessed;
}
inline void setLocalVariables(stringVector varList) {
localVariables = varList;
}
inline stringVector getLocalVariablesList() {
return localVariables;
}
inline bool variableLocal(string varName) {
for (int i=0;i<localVariables.size();i++)
if (localVariables[i] == varName) return true;
return false;
}
inline bool isnested() {
return isNested;
}
inline bool nests(string peerName) {
// Nesting requires that our peer have a strictly more
// qualified (longer) name, and that our name is a prefix
// of that name.
return ((name.size() < peerName.size()) &&
(string(peerName,0,name.size()) == name));
}
static bool nests(string name, string peerName) {
// Nesting requires that our peer have a strictly more
// qualified (longer) name, and that our name is a prefix
// of that name.
return ((name.size() < peerName.size()) &&
(string(peerName,0,name.size()) == name));
}
/**
* Lock the scope's mutex
*/
inline void lock() {
if (mutex) mutex->lock();
}
/**
* 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 (i<globalVars.size() && !foundName) {
foundName = (globalVars[i] == varName);
if (!foundName) i++;
}
return foundName;
}
/**
* Add a variable name to the persistent variables list.
*/
inline void addPersistentVariablePointer(std::string varName) {
if (!isVariablePersistent(varName)) {
persistentVars.push_back(varName);
anyPersistents = true;
}
}
inline stringVector getPersistentVariablesList() {
return persistentVars;
}
/**
* Delete a variable name from the persistent variables list.
*/
inline void deletePersistentVariablePointer(std::string varName) {
stringVector::iterator i = std::find(persistentVars.begin(),
persistentVars.end(),
varName);
if (*i == varName)
persistentVars.erase(i);
if (persistentVars.empty()) anyPersistents = false;
}
/**
* Check to see if a variable is defined in the persistent
* list.
*/
inline bool isVariablePersistent(const std::string& varName) {
if (!anyPersistents) return false;
bool foundName = false;
int i = 0;
i = 0;
if (persistentVars.empty()) return false;
while (i<persistentVars.size() && !foundName) {
foundName = (persistentVars[i] == varName);
if (!foundName) i++;
}
return foundName;
}
/**
* Mangle the name of a variable by prepending
* a "_scopename_" to the name of the variable.
*/
inline std::string getMangledName(std::string varName) {
return (std::string("_") + name + std::string("_") + varName);
}
/**
* Get the name of the scope.
*/
inline std::string getName() {
return name;
}
/**
* Increment the loop counter.
*/
inline void enterLoop() {
loopLevel++;
}
/**
* Decrement the loop counter.
*/
inline void exitLoop() {
loopLevel--;
}
/**
* Test the loop counter.
*/
inline bool inLoop() {
return (loopLevel>0);
}
/**
* 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;i<globalVars.size();i++)
names.push_back(globalVars[i]);
for (i=0;i<persistentVars.size();i++)
names.push_back(persistentVars[i]);
return names;
}
/**
* Delete a variable in this scope. It does not simply
* replace the variable with an empty variable, but deletes
* the variable from the symbol table completely.
*/
inline void deleteVariable(std::string var) {
symTab.deleteSymbol(var);
}
/**
* Clear the list of global variable names
*/
inline void clearGlobalVariableList() {
globalVars.clear();
anyGlobals = false;
}
/**
* Clear the list of persistent variable names
*/
inline void clearPersistentVariableList() {
persistentVars.clear();
anyPersistents = false;
}
};
typedef Scope* ScopePtr;
#if 0
class ScopePtr {
private:
Scope* d;
public:
ScopePtr() : d(NULL) {}
~ScopePtr() {
if (d) {
d->countunlock();
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
syntax highlighted by Code2HTML, v. 0.9.1