package com.drawbridge.jsengine;
import java.util.LinkedList;
import com.drawbridge.jsengine.JsEngine.JSEngineListener;
import com.drawbridge.jsengine.SymbolTable.SymbolTableException;
import com.drawbridge.jsengine.jsobjects.Document;
import com.drawbridge.jsengine.jsobjects.JSObject;
import com.drawbridge.jsengine.jsobjects.JSString;
import com.drawbridge.jsengine.jsobjects.JSType;
import com.drawbridge.jsengine.jsobjects.Math;
import com.google.caja.parser.js.Identifier;
/*
* This class provides a centralized model for the languages. When each representation is parsed, this model is updated
* to reflect the changes. It needs to be abstract in order to be applicable to all languages
*/
public class Scope {
/**
* This contains our current working set of objects. Possibly should
* maintain a list of static and dynamic objects. Static could be
* dynamically populated.
*/
private SymbolTable mSymbolTable = new SymbolTable();
private LinkedList<String> mStaticAnalysisIdentifiers = new LinkedList<String>();
private LinkedList<Scope> mChildren = new LinkedList<Scope>();
public final JsEngine mModel;
public final Scope mScopeParent;
/**
* Constructor
*/
public Scope(JsEngine model, Scope scopeParent) {
mModel = model;
mScopeParent = scopeParent;
//Only initialise if we're the root scope
if(scopeParent == null){
initEnvironment();
}
}
/**
* @return the symbol table
*/
public SymbolTable getSymbolTable() {
return mSymbolTable;
}
private synchronized void initEnvironment() {
try
{
mSymbolTable.add("document", new SymbolTableEntry(new Document()));
mSymbolTable.add("Math", new SymbolTableEntry(new Math()));
mSymbolTable.add("Object", new SymbolTableEntry(new JSObject()));
mSymbolTable.add("String", new SymbolTableEntry(new JSString("")));
} catch (SymbolTableException e)
{
e.printStackTrace();
}
}
public synchronized void resetVariables() {
mSymbolTable = new SymbolTable();
for(int i = 0; i < mChildren.size(); i++){
mChildren.remove();
}
if(mScopeParent == null){
initEnvironment();
}
}
public synchronized void declareVariable(JSEngineListener source, String name, SymbolTableEntry object) {
try
{
mSymbolTable.add(name, object);
} catch (SymbolTableException e)
{
e.printStackTrace();
}
mModel.childChanged(this,source);
}
public synchronized void setVariable(JSEngineListener source, String name, JSType newValue) throws Exception {
try
{
mSymbolTable.update(name, newValue);
} catch (SymbolTableException e)
{
throw new Exception("Scope SetVariable Exception: " + e.getMessage());
}
mModel.childChanged(this,source);
}
public static boolean validateParamTypes(Object [] object, Class<?> [] class1)
{
if(object == null && class1 == null)
return true;
if(object == null || class1 == null || object.length != class1.length)
return false;
for(int i = 0; i < object.length; i++){
if(object[i] == null){
return false;
}
else if(object[i].getClass().equals(class1[i]))
;
else
return false;
}
return true;
}
public SymbolTableEntry getVariable(String value)
{
if(this.mSymbolTable.contains(value)){
try
{
return this.mSymbolTable.get(value);
} catch (SymbolTableException e)
{
e.printStackTrace();
return null;
}
}
else if(this.mScopeParent != null){
return mScopeParent.getVariable(value);
}
else{
return null;
}
}
public void addChild(Scope childScope){
mChildren.add(childScope);
}
public LinkedList<Scope> getChildren(){
return mChildren;
}
public void printScopeDeep(int increment)
{
printVariables(increment);
for(int i = 0; i < mChildren.size(); i++){
mChildren.get(i).printScopeDeep(increment + 4);
}
}
public synchronized void printVariables(int increment) {
mSymbolTable.printSymbolTable(increment);
}
public void declareVariableForStaticAnalysis(Identifier identifier)
{
mStaticAnalysisIdentifiers.add(identifier.getName());
}
public boolean isIdentifierDeclaredForStaticAnalysis(String name)
{
return mStaticAnalysisIdentifiers.contains(name);
}
}