//////////////////////////////////////////////////////////////////////////////// // // ADOBE SYSTEMS INCORPORATED // Copyright 2003-2007 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file // in accordance with the terms of the license agreement accompanying it. // //////////////////////////////////////////////////////////////////////////////// // Original file can be found at: // svn://opensource.adobe.com/svn/opensource/flex/sdk/tags/3.0.0.477/modules/debugger/src/java/flex/tools/debugger/cli/ExpressionCache.java package flex.tools.debugger.cli; import java.io.IOException; import java.io.StringReader; import java.text.ParseException; import java.util.EmptyStackException; import java.util.NoSuchElementException; import java.util.Set; import java.util.Vector; import flash.localization.LocalizationManager; import flash.tools.debugger.Bootstrap; import flash.tools.debugger.Session; import flash.tools.debugger.Value; import flash.tools.debugger.ValueAttribute; import flash.tools.debugger.Variable; import flash.tools.debugger.VariableAttribute; import flash.tools.debugger.VariableType; import flash.tools.debugger.expression.ASTBuilder; import flash.tools.debugger.expression.IncompleteExpressionException; import flash.tools.debugger.expression.NoSuchVariableException; import flash.tools.debugger.expression.PlayerFaultException; import flash.tools.debugger.expression.UnknownOperationException; import flash.tools.debugger.expression.ValueExp; import util.StringUtil; public class ExpressionCache { Session m_session; ASTBuilder m_builder; Vector m_expressions; IntProperties m_props; DebugCLI m_cli; /** * We can get at files by name or module id, eventually we will put functions in here too */ public ExpressionCache(DebugCLI cli) { m_builder = new ASTBuilder(true); // allow fdb's "*x" and "x." indirection operators m_expressions = new Vector(); m_props = new IntProperties(); m_cli = cli; } public void clear() { m_expressions.clear(); } public void unbind() { m_session = null; } public int size() { return m_expressions.size(); } public Object at(int i) { return m_expressions.elementAt(i); } void setSession(Session s) { m_session = s; } public Session getSession() { return m_session; } public String getPackageName(int id) { return m_cli.module2ClassName(id); } public void bind(Session s) { setSession(s); // propagates our properties to the session / non-critical if fails try { ((flash.tools.debugger.concrete.PlayerSession)s).setPreferences(m_props.map()); } catch(Exception e) {} } public Object evaluate(ValueExp e) throws NumberFormatException, NoSuchVariableException, PlayerFaultException { // evaluate away... ExpressionContext c = new ExpressionContext(this); return e.evaluate(c); } public ValueExp parse(String s) throws IOException, EmptyStackException, UnknownOperationException, IncompleteExpressionException, ParseException { return m_builder.parse(new StringReader(s)); } public int add(Object e) { int at = m_expressions.size(); m_expressions.add(e); return at+1; } // // Interface for accessing previous expression values and also the properties // public boolean propertyEnabled(String which) { boolean enabled = false; try { Number number = (Number) get(which); if (number != null) enabled = (number.intValue() != 0); } catch (Exception e) { // nothing; leave 'enabled' as false } return enabled; } // this goes in properties public void put(String s, int value) { m_props.put(s, value); setSessionProperty(s, value); } public Set keySet() { return m_props.keySet(); } /** * Allow the session to receive property updates */ void setSessionProperty(String s, int value) { Session sess = getSession(); if (sess != null) sess.setPreference(s, value); Bootstrap.sessionManager().setPreference(s, value); } /** * We are able to fetch properties or expressions (i.e previous expression) * using this single call, despite the fact that each of these types of * results lie in different data structures m_expressions and m_props. * This allows us to easily perform expression evaluation without * need or concern over which 'type' of $ reference we are dealing with */ public Object get(String s) throws NumberFormatException, ArrayIndexOutOfBoundsException, NoSuchElementException { Object exp = null; // should be of form '$n' where n is a number 0..size() if (s.charAt(0) != '$') throw new NoSuchElementException(s); String num = s.substring(1); if (num == null || num.length() == 0) exp = at(size()-1); else if (num.equals("$")) //$NON-NLS-1$ exp = at(size()-2); else { try { int index = Integer.parseInt(num); exp = at(index-1); } catch(NumberFormatException nfe) { // must be in the property list exp = m_props.getInteger(s); } } return exp; } // // Statics for formatting stuff // /** * Formatting function for variable */ public static void appendVariable(StringBuffer sb, Variable v) { //sb.append('\''); String name = v.getName(); sb.append(name); //sb.append('\''); sb.append(" = "); //$NON-NLS-1$ appendVariableValue(sb, v.getValue(), name); //appendVariableAttributes(sb, v); } public static void appendVariableValue(StringBuffer sb, Value val) { appendVariableValue(sb,val,""); } //$NON-NLS-1$ public static void appendVariableValue(StringBuffer sb, Value val, String variableName) { int type = val.getType(); String typeName = val.getTypeName(); String className = val.getClassName(); // if no string or empty then typeName is blank if (typeName != null && typeName.length() == 0) typeName = null; switch (type) { case VariableType.NUMBER: { double value = ((Double)val.getValueAsObject()).doubleValue(); long longValue = (long) value; // The value is stored as a double; however, in practice most values are // actually integers. Check to see if this is the case, and if it is, // then display it: // - without a fraction, and // - with its hex equivalent in parentheses. // Note, we use 'long' instead of 'int', in order to deal with the // ActionScript type 'uint'. if (longValue == value) { sb.append(longValue); sb.append(" (0x"); //$NON-NLS-1$ sb.append(Long.toHexString(longValue)); sb.append(")"); //$NON-NLS-1$ } else { sb.append(value); } break; } case VariableType.BOOLEAN: { Boolean b = (Boolean)val.getValueAsObject(); if (b.booleanValue()) sb.append("true"); //$NON-NLS-1$ else sb.append("false"); //$NON-NLS-1$ break; } case VariableType.STRING: { boolean isException = (val.isAttributeSet(ValueAttribute.IS_EXCEPTION)); sb.append(isException ? '<' : '\"'); sb.append(StringUtil.escape((val.getValueAsString()))); sb.append(isException ? '>' : '\"'); break; } case VariableType.OBJECT: { sb.append("["); //$NON-NLS-1$ sb.append(className); // Normally, we include the object id after the class name. // However, when running fdbunit, don't show object IDs, so that // results can reproduce consistently from one run to the next. if (System.getProperty("fdbunit") == null) //$NON-NLS-1$ { sb.append(" "); //$NON-NLS-1$ sb.append(StringUtil.escape(String.valueOf(val.getValueAsObject()))); // object id } if (typeName != null && !typeName.equals(className)) { sb.append(", class='"); //$NON-NLS-1$ // Often the typename is of the form 'classname@hexaddress', // but the hex address is the same as the object id which // is returned by getValue() -- we don't want to display it // here. int at = typeName.indexOf('@'); if (at != -1) { final boolean isXml = typeName.startsWith("XML@"); if (!isXml) { typeName = typeName.substring(0, at); } } sb.append(StringUtil.escape(typeName)); sb.append('\''); } sb.append(']'); break; } case VariableType.FUNCTION: { // here we have a special case for getters/setters which // look like functions to us, except the attribute is set. sb.append('['); if (val.isAttributeSet(VariableAttribute.HAS_GETTER)) sb.append(getLocalizationManager().getLocalizedTextString("getterFunction")); //$NON-NLS-1$ else if (val.isAttributeSet(VariableAttribute.HAS_SETTER)) sb.append(getLocalizationManager().getLocalizedTextString("setterFunction")); //$NON-NLS-1$ else sb.append(getLocalizationManager().getLocalizedTextString("function")); //$NON-NLS-1$ sb.append(' '); sb.append(StringUtil.escape(String.valueOf(val.getValueAsObject()))); if (typeName != null && !typeName.equals(variableName)) { sb.append(", name='"); //$NON-NLS-1$ sb.append(StringUtil.escape(typeName)); sb.append('\''); } sb.append(']'); break; } case VariableType.MOVIECLIP: { sb.append("["); //$NON-NLS-1$ sb.append(className); sb.append(" "); //$NON-NLS-1$ sb.append(StringUtil.escape(String.valueOf(val.getValueAsObject()))); if (typeName != null && !typeName.equals(className)) { sb.append(", named='"); //$NON-NLS-1$ sb.append(StringUtil.escape(typeName)); sb.append('\''); } sb.append(']'); break; } case VariableType.NULL: { sb.append("null"); //$NON-NLS-1$ break; } case VariableType.UNDEFINED: { sb.append("undefined"); //$NON-NLS-1$ break; } case VariableType.UNKNOWN: { sb.append(getLocalizationManager().getLocalizedTextString("unknownVariableType")); //$NON-NLS-1$ break; } } } private static LocalizationManager getLocalizationManager() { return DebugCLI.getLocalizationManager(); } public static void appendVariableAttributes(StringBuffer sb, Variable v) { if (v.getAttributes() == 0) return; sb.append(" "); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.DONT_ENUMERATE)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_dontEnumerate")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.READ_ONLY)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_readOnly")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.IS_LOCAL)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_localVariable")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.IS_ARGUMENT)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_functionArgument")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.HAS_GETTER)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_getterFunction")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.HAS_SETTER)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_setterFunction")); //$NON-NLS-1$ //$NON-NLS-2$ if (v.isAttributeSet(VariableAttribute.IS_DYNAMIC)) sb.append(", dynamic"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.IS_STATIC)) sb.append(", static"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.IS_CONST)) sb.append(", const"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.PRIVATE_SCOPE)) sb.append(", private"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.PUBLIC_SCOPE)) sb.append(", public"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.PROTECTED_SCOPE)) sb.append(", protected"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.INTERNAL_SCOPE)) sb.append(", internal"); //$NON-NLS-1$ if (v.isAttributeSet(VariableAttribute.NAMESPACE_SCOPE)) sb.append(", " + getLocalizationManager().getLocalizedTextString("variableAttribute_hasNamespace")); //$NON-NLS-1$ //$NON-NLS-2$ } }