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); } }