You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2016/04/26 06:29:03 UTC
[11/63] [abbrv] [partial] git commit: [flex-falcon]
[refs/heads/develop] - move stuff to where I think Maven wants it
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/DisplayAction.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/DisplayAction.java b/debugger/src/main/java/flex/tools/debugger/cli/DisplayAction.java
new file mode 100644
index 0000000..d8612d5
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/DisplayAction.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import flash.tools.debugger.expression.ValueExp;
+
+/**
+ * An object that relates a CLI debugger 'display' command
+ * with the contents of the display
+ */
+public class DisplayAction
+{
+ private static int s_uniqueIdentifier = 1;
+
+ boolean m_enabled;
+ int m_id;
+ ValueExp m_expression;
+ String m_content;
+ int m_isolateId;
+
+ public DisplayAction(ValueExp expr, String content, int isolateId)
+ {
+ init();
+ m_expression = expr;
+ m_content = content;
+ m_isolateId = isolateId;
+ }
+
+ void init()
+ {
+ m_enabled = true;
+ m_id = s_uniqueIdentifier++;
+ }
+
+ /* getters */
+ public String getContent() { return m_content; }
+ public int getId() { return m_id; }
+
+ public int getIsolateId() {
+ return m_isolateId;
+ }
+ public boolean isEnabled() { return m_enabled; }
+ public ValueExp getExpression() { return m_expression; }
+
+ /* setters */
+ public void setEnabled(boolean enable) { m_enabled = enable; }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/ExpressionCache.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/ExpressionCache.java b/debugger/src/main/java/flex/tools/debugger/cli/ExpressionCache.java
new file mode 100644
index 0000000..95698d5
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/ExpressionCache.java
@@ -0,0 +1,596 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.text.ParseException;
+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.NoResponseException;
+import flash.tools.debugger.NotConnectedException;
+import flash.tools.debugger.NotSuspendedException;
+import flash.tools.debugger.PlayerDebugException;
+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.concrete.DValue;
+import flash.tools.debugger.expression.ASTBuilder;
+import flash.tools.debugger.expression.IASTBuilder;
+import flash.tools.debugger.expression.NoSuchVariableException;
+import flash.tools.debugger.expression.PlayerFaultException;
+import flash.tools.debugger.expression.ValueExp;
+
+public class ExpressionCache
+{
+ Session m_session;
+ IASTBuilder m_builder;
+ Vector<Object> m_expressions;
+ IntProperties m_props;
+ DebugCLI m_cli;
+
+ /**
+ * Returned by evaluate().
+ */
+ public static class EvaluationResult
+ {
+ /**
+ * The value to which the expression evaluated.
+ */
+ public Object value;
+
+ /**
+ * The context that was used to evaluate the expression. Sometimes used
+ * to convert the <code>value</code> field to a <code>Value</code>
+ * with <code>context.toValue()</code>.
+ */
+ public ExpressionContext context;
+ }
+
+ /**
+ * 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<Object>();
+ 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 EvaluationResult evaluate(ValueExp e, int isolateId) throws NumberFormatException, NoSuchVariableException, PlayerFaultException, PlayerDebugException
+ {
+ EvaluationResult result = new EvaluationResult();
+ result.context = new ExpressionContext(this);
+ result.context.setIsolateId(isolateId);
+ result.value = e.evaluate(result.context);
+ return result;
+ }
+
+ public ValueExp parse(String s) throws IOException, 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<String> 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 void appendVariable(StringBuilder sb, Variable v, int isolateId)
+ {
+ //sb.append('\'');
+ String name = v.getName();
+ sb.append(name);
+ //sb.append('\'');
+ sb.append(" = "); //$NON-NLS-1$
+ appendVariableValue(sb, v.getValue(), name, isolateId);
+ //appendVariableAttributes(sb, v);
+ }
+
+ /**
+ * Given any arbitrary constant value, such as a Double, a String, etc.,
+ * format its value appropriately. For example, strings will be quoted.
+ *
+ * @param sb
+ * a StringBuilder to which the formatted value will be appended.
+ * @param o
+ * the value to format.
+ */
+ public void appendVariableValue(StringBuilder sb, final Object o, final int isolateId)
+ {
+ Value v;
+
+ if (o instanceof Value) {
+ v = (Value) o;
+ } else {
+ v = new Value() {
+ public int getAttributes() {
+ return 0;
+ }
+
+ public String[] getClassHierarchy(boolean allLevels) {
+ return new String[0];
+ }
+
+ public String getClassName() {
+ return ""; //$NON-NLS-1$
+ }
+
+ public long getId() {
+ return UNKNOWN_ID;
+ }
+
+ public int getMemberCount(Session s) throws NotSuspendedException,
+ NoResponseException, NotConnectedException {
+ return 0;
+ }
+
+ public Variable getMemberNamed(Session s, String name)
+ throws NotSuspendedException, NoResponseException,
+ NotConnectedException {
+ return null;
+ }
+
+ public Variable[] getMembers(Session s)
+ throws NotSuspendedException, NoResponseException,
+ NotConnectedException {
+ return new Variable[0];
+ }
+
+ public int getType() {
+ if (o instanceof Number)
+ return VariableType.NUMBER;
+ else if (o instanceof Boolean)
+ return VariableType.BOOLEAN;
+ else if (o instanceof String)
+ return VariableType.STRING;
+ else if (o == Value.UNDEFINED)
+ return VariableType.UNDEFINED;
+ else if (o == null)
+ return VariableType.NULL;
+
+ assert false;
+ return VariableType.UNKNOWN;
+ }
+
+ public String getTypeName() {
+ return ""; //$NON-NLS-1$
+ }
+
+ public Object getValueAsObject() {
+ return o;
+ }
+
+ public String getValueAsString() {
+ return DValue.getValueAsString(o);
+ }
+
+ public boolean isAttributeSet(int variableAttribute) {
+ return false;
+ }
+
+ public Variable[] getPrivateInheritedMembers() {
+ return new Variable[0];
+ }
+
+ public Variable[] getPrivateInheritedMemberNamed(String name) {
+ return new Variable[0];
+ }
+
+ public int getIsolateId() {
+ return isolateId;
+ }
+ };
+ }
+
+ appendVariableValue(sb, v, isolateId);
+ }
+
+ public void appendVariableValue(StringBuilder sb, Value val, final int isolateId) { appendVariableValue(sb,val,"", isolateId); } //$NON-NLS-1$
+
+ public void appendVariableValue(StringBuilder sb, Value val, String variableName, final int isolateId)
+ {
+ 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 = ((Number)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:
+ {
+ // Exceptions are displayed in angle brackets, e.g.
+ // foo = <Text of exception here>
+ // Strings are displayed quoted:
+ // foo = "Value of string here"
+ //
+ // Note that quotation marks within the string are not escaped. This
+ // is sort of weird, but it's what we want to do, at least for now;
+ // the debugger's output is intended to be human-readable, not
+ // machine-readable, and it's easier for a person to read the string
+ // if there is no escaping of quotation marks.
+ //
+ // As a small step in the direction of avoiding that weirdness, if
+ // the string contains double-quotes but no single-quotes, we will
+ // quote it in single quotes.
+ String s = val.getValueAsString();
+ char start, end;
+
+ if (val.isAttributeSet(ValueAttribute.IS_EXCEPTION))
+ {
+ start = '<';
+ end = '>';
+ }
+ else if (s.indexOf('"') != -1 && s.indexOf('\'') == -1)
+ {
+ start = end = '\'';
+ }
+ else
+ {
+ start = end = '"';
+ }
+
+ sb.append(start);
+ sb.append(escapeIfIde(s));
+ sb.append(end);
+ 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(escapeIfIde(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)
+ typeName = typeName.substring(0, at);
+
+ sb.append(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(escapeIfIde(String.valueOf(val.getValueAsObject())));
+ if (typeName != null && !typeName.equals(variableName))
+ {
+ sb.append(", name='"); //$NON-NLS-1$
+ sb.append(typeName);
+ sb.append('\'');
+ }
+ sb.append(']');
+ break;
+ }
+
+ case VariableType.MOVIECLIP:
+ {
+ sb.append("["); //$NON-NLS-1$
+ sb.append(className);
+ sb.append(" "); //$NON-NLS-1$
+ sb.append(escapeIfIde(String.valueOf(val.getValueAsObject())));
+ if (typeName != null && !typeName.equals(className))
+ {
+ sb.append(", named='"); //$NON-NLS-1$
+ sb.append(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(StringBuilder 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$
+ }
+
+ private String escapeIfIde(String s)
+ {
+ return m_cli != null && m_cli.isIde() ? escape(s) : s;
+ }
+
+ public static String escape(final String str) {
+ final StringBuilder buffer = new StringBuilder();
+
+ for (int idx = 0; idx < str.length(); idx++) {
+ char ch = str.charAt(idx);
+ switch (ch) {
+ case '\b':
+ buffer.append("\\b");
+ break;
+
+ case '\t':
+ buffer.append("\\t");
+ break;
+
+ case '\n':
+ buffer.append("\\n");
+ break;
+
+ case '\f':
+ buffer.append("\\f");
+ break;
+
+ case '\r':
+ buffer.append("\\r");
+ break;
+
+ case '\\':
+ buffer.append("\\\\");
+ break;
+
+ default:
+ if (Character.isISOControl(ch)) {
+ String hexCode = Integer.toHexString(ch).toUpperCase();
+ buffer.append("\\u");
+ int paddingCount = 4 - hexCode.length();
+ while (paddingCount-- > 0) {
+ buffer.append(0);
+ }
+ buffer.append(hexCode);
+ } else {
+ buffer.append(ch);
+ }
+ }
+ }
+ return buffer.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/ExpressionContext.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/ExpressionContext.java b/debugger/src/main/java/flex/tools/debugger/cli/ExpressionContext.java
new file mode 100644
index 0000000..2bed5ee
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/ExpressionContext.java
@@ -0,0 +1,653 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import flash.tools.debugger.Isolate;
+import flash.tools.debugger.PlayerDebugException;
+import flash.tools.debugger.Session;
+import flash.tools.debugger.SessionManager;
+import flash.tools.debugger.Value;
+import flash.tools.debugger.ValueAttribute;
+import flash.tools.debugger.Variable;
+import flash.tools.debugger.VariableType;
+import flash.tools.debugger.concrete.DValue;
+import flash.tools.debugger.events.ExceptionFault;
+import flash.tools.debugger.events.FaultEvent;
+import flash.tools.debugger.expression.Context;
+import flash.tools.debugger.expression.ExpressionEvaluatorException;
+import flash.tools.debugger.expression.NoSuchVariableException;
+import flash.tools.debugger.expression.PlayerFaultException;
+
+public class ExpressionContext implements Context
+{
+ ExpressionCache m_cache;
+ Object m_current;
+ boolean m_createIfMissing; // set if we need to create a variable if it doesn't exist
+ Vector<String> m_namedPath;
+ boolean m_nameLocked;
+ String m_newline = System.getProperty("line.separator"); //$NON-NLS-1$
+ int m_isolateId;
+
+ // used when evaluating an expression
+ public ExpressionContext(ExpressionCache cache)
+ {
+ m_cache = cache;
+ m_current = null;
+ m_createIfMissing = false;
+ m_namedPath = new Vector<String>();
+ m_nameLocked = false;
+ m_isolateId = Isolate.DEFAULT_ID;
+ }
+
+ public void setIsolateId(int id) {
+ m_isolateId = id;
+ }
+
+ void setContext(Object o) { m_current = o; }
+
+ void pushName(String name) { if (m_nameLocked || name.length() < 1) return; m_namedPath.add(name); }
+ boolean setName(String name) { if (m_nameLocked) return true; m_namedPath.clear(); pushName(name); return true; }
+ void lockName() { m_nameLocked = true; }
+
+ public String getName()
+ {
+ int size = m_namedPath.size();
+ StringBuilder sb = new StringBuilder();
+ for(int i=0; i<size; i++)
+ {
+ String s = m_namedPath.get(i);
+ if (i > 0)
+ sb.append('.');
+ sb.append(s);
+ }
+ return ( sb.toString() );
+ }
+
+ String getCurrentPackageName()
+ {
+ String s = null;
+ try
+ {
+ Integer o = (Integer)m_cache.get(DebugCLI.LIST_MODULE);
+ s = m_cache.getPackageName(o.intValue());
+ }
+ catch(NullPointerException npe)
+ {
+ }
+ catch(ClassCastException cce)
+ {
+ }
+ return s;
+ }
+
+ //
+ //
+ // Start of Context API implementation
+ //
+ //
+ public void createPseudoVariables(boolean oui) { m_createIfMissing = oui; }
+
+ // create a new context object by combining the current one and o
+ public Context createContext(Object o)
+ {
+ ExpressionContext c = new ExpressionContext(m_cache);
+ c.setContext(o);
+ c.createPseudoVariables(m_createIfMissing);
+ c.m_namedPath.addAll(m_namedPath);
+ c.setIsolateId(m_isolateId);
+ return c;
+ }
+
+ // assign the object o, the value v
+ public void assign(Object o, Value v) throws NoSuchVariableException, PlayerFaultException
+ {
+ try
+ {
+ // first see if it is an internal property (avoids player calls)
+ InternalProperty prop = resolveToInternalProperty(o);
+
+ // we expect that o is a variable that can be resolved or is a specially marked internal variable
+ if (prop != null)
+ {
+ assignInternal(prop, v);
+ }
+ else
+ {
+ boolean wasCreateIfMissing = m_createIfMissing;
+ createPseudoVariables(true);
+ Variable var = null;
+ try {
+ var = resolveToVariable(o);
+ } finally {
+ createPseudoVariables(wasCreateIfMissing);
+ }
+
+ if (var == null)
+ throw new NoSuchVariableException((var == null) ? m_current : var.getName());
+
+ // set the value, for the case of a variable that does not exist it will not have a type
+ // so we try to glean one from v.
+ FaultEvent faultEvent = var.setValue(getSession(), v.getType(), v.getValueAsString());
+ if (faultEvent != null)
+ throw new PlayerFaultException(faultEvent);
+ }
+ }
+ catch(PlayerDebugException pde)
+ {
+ throw new ExpressionEvaluatorException(pde);
+ }
+ }
+
+ /**
+ * The Context interface which goes out and gets values from the session
+ * Expressions use this interface as a means of evaluation.
+ *
+ * We also use this to create a reference to internal variables.
+ */
+ public Object lookup(Object o) throws NoSuchVariableException, PlayerFaultException
+ {
+ Object result = null;
+ try
+ {
+ // first see if it is an internal property (avoids player calls)
+ if ( (result = resolveToInternalProperty(o)) != null)
+ ;
+
+ // attempt to resolve to a player variable
+ else if ( (result = resolveToVariable(o)) != null)
+ ;
+
+ // or value
+ else if ( (result = resolveToValue(o)) != null)
+ ;
+
+ else
+ throw new NoSuchVariableException(o);
+
+ // take on the path to the variable; so 'what' command prints something nice
+ if ((result != null) && result instanceof VariableFacade)
+ {
+ ((VariableFacade)result).setPath(getName());
+ }
+
+ // if the attempt to get the variable's value threw an exception inside the
+ // player (most likely because the variable is actually a getter, and the
+ // getter threw something), then throw something here
+ Value resultValue = null;
+
+ if (result instanceof Variable)
+ {
+ if (result instanceof VariableFacade && ((VariableFacade)result).getVariable() == null)
+ resultValue = null;
+ else
+ resultValue = ((Variable)result).getValue();
+ }
+ else if (result instanceof Value)
+ {
+ resultValue = (Value) result;
+ }
+
+ if (resultValue != null)
+ {
+ if (resultValue.isAttributeSet(ValueAttribute.IS_EXCEPTION))
+ {
+ String value = resultValue.getValueAsString();
+ throw new PlayerFaultException(new ExceptionFault(value, false, resultValue, resultValue.getIsolateId()));
+ }
+ }
+ }
+ catch(PlayerDebugException pde)
+ {
+ result = Value.UNDEFINED;
+ }
+ return result;
+ }
+
+ /* returns a string consisting of formatted member names and values */
+ public Object lookupMembers(Object o) throws NoSuchVariableException
+ {
+ Variable var = null;
+ Value val = null;
+ Variable[] mems = null;
+ try
+ {
+ var = resolveToVariable(o);
+ if (var != null)
+ val = var.getValue();
+ else
+ val = resolveToValue(o);
+ mems = val.getMembers(getSession());
+ }
+ catch(NullPointerException npe)
+ {
+ throw new NoSuchVariableException(o);
+ }
+ catch(PlayerDebugException pde)
+ {
+ throw new NoSuchVariableException(o); // not quite right...
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ if (var != null)
+ m_cache.appendVariable(sb, var, m_isolateId);
+ else
+ m_cache.appendVariableValue(sb, val, m_isolateId);
+
+ boolean attrs = m_cache.propertyEnabled(DebugCLI.DISPLAY_ATTRIBUTES);
+ if (attrs && var != null)
+ ExpressionCache.appendVariableAttributes(sb, var);
+
+ // [mmorearty] experimenting with hierarchical display of members
+ String[] classHierarchy = val.getClassHierarchy(false);
+ if (classHierarchy != null && getSession().getPreference(SessionManager.PREF_HIERARCHICAL_VARIABLES) != 0)
+ {
+ for (int c=0; c<classHierarchy.length; ++c)
+ {
+ String classname = classHierarchy[c];
+ sb.append(m_newline + "(Members of " + classname + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ for (int i=0; i<mems.length; ++i)
+ {
+ if (classname.equals(mems[i].getDefiningClass()))
+ {
+ sb.append(m_newline + " "); //$NON-NLS-1$
+ m_cache.appendVariable(sb, mems[i], m_isolateId);
+ if (attrs)
+ ExpressionCache.appendVariableAttributes(sb, mems[i]);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(int i=0; i<mems.length; i++)
+ {
+ sb.append(m_newline + " "); //$NON-NLS-1$
+ m_cache.appendVariable(sb, mems[i], m_isolateId);
+ if (attrs)
+ ExpressionCache.appendVariableAttributes(sb, mems[i]);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ //
+ //
+ // End of Context API implementation
+ //
+ //
+
+ // used to assign a value to an internal variable
+ private void assignInternal(InternalProperty var, Value v) throws NoSuchVariableException, NumberFormatException, PlayerDebugException
+ {
+ // otherwise set it
+ if (v.getType() != VariableType.NUMBER)
+ throw new NumberFormatException(v.getValueAsString());
+ long l = Long.parseLong(v.getValueAsString());
+ m_cache.put(var.getName(), (int)l);
+ }
+
+ InternalProperty resolveToInternalProperty(Object o)
+ {
+ if (o instanceof String && ((String)o).charAt(0) == '$')
+ {
+ String key = (String)o;
+ Object value = null;
+
+ try { value = m_cache.get(key); } catch(Exception e) {}
+ return new InternalProperty(key, value);
+ }
+
+ return null;
+ }
+
+ /**
+ * Resolve the object into a variable by various means and
+ * using the current context.
+ * @return variable, or <code>null</code>
+ */
+ Variable resolveToVariable(Object o) throws PlayerDebugException
+ {
+ Variable v = null;
+
+ // if o is a variable already, then we're done!
+ if (o instanceof Variable)
+ return (Variable)o;
+
+ /**
+ * Resolve the name to something
+ */
+ {
+ // not an id so try as name
+ String name = o.toString();
+ long id = nameAsId(name);
+
+ /**
+ * if #N was used just pick up the variable, otherwise
+ * we need to use the current context to resolve
+ * the name to a member
+ */
+ if (id != Value.UNKNOWN_ID)
+ {
+ // TODO what here?
+ }
+ else
+ {
+ // try to resolve as a member of current context (will set context if null)
+ id = determineContext(name);
+ v = locateForNamed(id, name, true);
+ if (v != null)
+ v = new VariableFacade(v, id, m_isolateId);
+ else if (v == null && m_createIfMissing && name.charAt(0) != '$')
+ v = new VariableFacade(id, name, m_isolateId);
+ }
+ }
+
+ /* return the variable */
+ return v;
+ }
+
+ /*
+ * Resolve the object into a variable by various means and
+ * using the current context.
+ */
+ Value resolveToValue(Object o) throws PlayerDebugException
+ {
+ Value v = null;
+
+ // if o is a variable or a value already, then we're done!
+ if (o instanceof Value)
+ return (Value)o;
+ else if (o instanceof Variable)
+ return ((Variable)o).getValue();
+ else if (o instanceof InternalProperty)
+ return DValue.forPrimitive(((InternalProperty)o).m_value, m_isolateId);
+
+ /**
+ * Resolve the name to something
+ */
+ if (m_current == null)
+ {
+ // not an id so try as name
+ String name = o.toString();
+ long id = nameAsId(name);
+
+ /**
+ * if #N was used just pick up the variable, otherwise
+ * we need to use the current context to resolve
+ * the name to a member
+ */
+ if (id != Value.UNKNOWN_ID)
+ {
+ v = getSession().getWorkerSession(m_isolateId).getValue((int)id);
+ }
+ else if (name.equals("undefined")) //$NON-NLS-1$
+ {
+ v = DValue.forPrimitive(Value.UNDEFINED, m_isolateId);
+ }
+ else
+ {
+ // Ask the player to find something, anything, on the scope chain
+ // with this name. We'll end up here, for example, when resolving
+ // things like MyClass, String, Number, etc.
+ v = getSession().getWorkerSession(m_isolateId).getGlobal(name);
+ }
+ }
+
+ /* return the value */
+ return v;
+ }
+
+ // special code for #N support. I.e. naming a variable via an ID
+ long nameAsId(String name)
+ {
+ long id = Value.UNKNOWN_ID;
+ try
+ {
+ if (name.charAt(0) == '#')
+ id = Long.parseLong(name.substring(1));
+ }
+ catch(Exception e)
+ {
+ id = Value.UNKNOWN_ID;
+ }
+ return id;
+ }
+
+ /**
+ * Using the given id as a parent find the member named
+ * name.
+ * @throws NoSuchVariableException if id is UNKNOWN_ID
+ */
+ Variable memberNamed(long id, String name) throws NoSuchVariableException, PlayerDebugException
+ {
+ Variable v = null;
+ Value parent = getSession().getWorkerSession(m_isolateId).getValue(id);
+
+ if (parent == null)
+ throw new NoSuchVariableException(name);
+
+ /* got a variable now return the member if any */
+ v = parent.getMemberNamed(getSession(), name);
+
+ return v;
+ }
+
+ /**
+ * All the really good stuff about finding where name exists goes here!
+ *
+ * If name is not null, then it implies that we use the existing
+ * m_current to find a member of m_current. If m_current is null
+ * Then we need to probe variable context points attempting to locate
+ * name. When we find a match we set the m_current to this context
+ *
+ * If name is null then we simply return the current context.
+ */
+ long determineContext(String name) throws PlayerDebugException
+ {
+ long id = Value.UNKNOWN_ID;
+
+ // have we already resolved our context...
+ if (m_current != null)
+ {
+ id = toValue().getId();
+ }
+
+ // nothing to go on, so we're done
+ else if (name == null)
+ ;
+
+ // use the name and try and resolve where we are...
+ else
+ {
+ // Each stack frame has a root variable under (BASE_ID-depth)
+ // where depth is the depth of the stack.
+ // So we query for our current stack depth and use that
+ // as the context for our base computation
+ long baseId = Value.BASE_ID;
+ int depth = ((Integer)m_cache.get(DebugCLI.DISPLAY_FRAME_NUMBER)).intValue();
+ baseId -= depth;
+
+ // obtain data about our current state
+ Variable contextVar = null;
+ Value contextVal = null;
+ Value val = null;
+
+ // look for 'name' starting from local scope
+ if ( (val = locateParentForNamed(baseId, name, false)) != null)
+ ;
+
+ // get the this pointer, then look for 'name' starting from that point
+ else if ( ( (contextVar = locateForNamed(baseId, "this", false)) != null ) && //$NON-NLS-1$
+ ( setName("this") && (val = locateParentForNamed(contextVar.getValue().getId(), name, true)) != null ) ) //$NON-NLS-1$
+ ;
+
+ // now try to see if 'name' exists off of _root
+ else if ( setName("_root") && (val = locateParentForNamed(Value.ROOT_ID, name, true)) != null ) //$NON-NLS-1$
+ ;
+
+ // now try to see if 'name' exists off of _global
+ else if ( setName("_global") && (val = locateParentForNamed(Value.GLOBAL_ID, name, true)) != null ) //$NON-NLS-1$
+ ;
+
+ // now try off of class level, if such a thing can be found
+ else if ( ( (contextVal = locate(Value.GLOBAL_ID, getCurrentPackageName(), false)) != null ) &&
+ ( setName("_global."+getCurrentPackageName()) && (val = locateParentForNamed(contextVal.getId(), name, true)) != null ) ) //$NON-NLS-1$
+ ;
+
+ // if we found it then stake this as our context!
+ if (val != null)
+ {
+ id = val.getId();
+ pushName(name);
+ lockName();
+ }
+ }
+
+ return id;
+ }
+
+ /**
+ * Performs a search for a member with the given name using the
+ * given id as the parent variable.
+ *
+ * If a match is found then, we return the parent variable of
+ * the member that matched. The proto chain is optionally traversed.
+ *
+ * No exceptions are thrown
+ */
+ Value locateParentForNamed(long id, String name, boolean traverseProto) throws PlayerDebugException
+ {
+ StringBuilder sb = new StringBuilder();
+
+ Variable var = null;
+ Value val = null;
+ try
+ {
+ var = memberNamed(id, name);
+
+ // see if we need to traverse the proto chain
+ while (var == null && traverseProto)
+ {
+ // first attempt to get __proto__, then resolve name
+ Variable proto = memberNamed(id, "__proto__"); //$NON-NLS-1$
+ sb.append("__proto__"); //$NON-NLS-1$
+ if (proto == null)
+ traverseProto = false;
+ else
+ {
+ id = proto.getValue().getId();
+ var = memberNamed(id, name);
+ if (var == null)
+ sb.append('.');
+ }
+ }
+ }
+ catch(NoSuchVariableException nsv)
+ {
+ // don't worry about this one, it means variable with id couldn't be found
+ }
+ catch(NullPointerException npe)
+ {
+ // probably no session
+ }
+
+ // what we really want is the parent not the child variable
+ if (var != null)
+ {
+ pushName(sb.toString());
+ val = getSession().getWorkerSession(m_isolateId).getValue(id);
+ }
+
+ return val;
+ }
+
+ // variant of locateParentForNamed, whereby we return the child variable
+ Variable locateForNamed(long id, String name, boolean traverseProto) throws PlayerDebugException
+ {
+ Variable var = null;
+ Value v = locateParentForNamed(id, name, traverseProto);
+ if (v != null)
+ {
+ try
+ {
+ var = memberNamed(v.getId(), name);
+ }
+ catch(NoSuchVariableException nse)
+ {
+ v = null;
+ }
+ }
+
+ return var;
+ }
+
+ /**
+ * Locates the member via a dotted name starting at the given id.
+ * It will traverse any and all proto chains if necc. to find the name.
+ */
+ Value locate(long startingId, String dottedName, boolean traverseProto) throws PlayerDebugException
+ {
+ if (dottedName == null)
+ return null;
+
+ // first rip apart the dottedName
+ StringTokenizer names = new StringTokenizer(dottedName, "."); //$NON-NLS-1$
+ Value val = getSession().getWorkerSession(m_isolateId).getValue(startingId);
+
+ while(names.hasMoreTokens() && val != null)
+ val = locateForNamed(val.getId(), names.nextToken(), traverseProto).getValue();
+
+ return val;
+ }
+
+ /*
+ * @see flash.tools.debugger.expression.Context#toValue(java.lang.Object)
+ */
+ public Value toValue(Object o)
+ {
+ // if o is a variable or a value already, then we're done!
+ if (o instanceof Value)
+ return (Value)o;
+ else if (o instanceof Variable)
+ return ((Variable)o).getValue();
+ else if (o instanceof InternalProperty)
+ return DValue.forPrimitive(((InternalProperty)o).m_value, m_isolateId);
+ else
+ return DValue.forPrimitive(o, m_isolateId);
+ }
+
+ public Value toValue()
+ {
+ return toValue(m_current);
+ }
+
+ public Session getSession()
+ {
+ return m_cache.getSession();
+ }
+
+ @Override
+ public int getIsolateId() {
+ return m_isolateId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/Extensions.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/Extensions.java b/debugger/src/main/java/flex/tools/debugger/cli/Extensions.java
new file mode 100644
index 0000000..0222290
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/Extensions.java
@@ -0,0 +1,547 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.io.PrintWriter;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+
+import flash.localization.LocalizationManager;
+import flash.swf.tools.Disassembler;
+import flash.swf.types.ActionList;
+import flash.tools.ActionLocation;
+import flash.tools.debugger.Bootstrap;
+import flash.tools.debugger.NotConnectedException;
+import flash.tools.debugger.PlayerDebugException;
+import flash.tools.debugger.Session;
+import flash.tools.debugger.SourceFile;
+import flash.tools.debugger.SuspendReason;
+import flash.tools.debugger.SuspendedException;
+import flash.tools.debugger.SwfInfo;
+import flash.tools.debugger.Value;
+import flash.tools.debugger.concrete.DMessage;
+import flash.tools.debugger.concrete.DMessageCounter;
+import flash.tools.debugger.concrete.DModule;
+import flash.tools.debugger.concrete.DSuspendInfo;
+import flash.tools.debugger.concrete.DSwfInfo;
+import flash.tools.debugger.concrete.PlayerSession;
+import flash.tools.debugger.concrete.PlayerSessionManager;
+import flash.util.FieldFormat;
+
+/**
+ * Extensions class is a singleton that contains
+ * every cli method that does not conform to the
+ * API. Thus we can easily remove these features
+ * from the cli if the implementation does not
+ * support these calls.
+ */
+public class Extensions
+{
+ public final static String m_newline = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ public static void doShowStats(DebugCLI cli) throws IllegalStateException
+ {
+ /* we do some magic casting */
+ Session session = cli.getSession();
+ StringBuilder sb = new StringBuilder();
+ try
+ {
+ PlayerSession p = (PlayerSession)session;
+ DMessageCounter cnt = p.getMessageCounter();
+
+ sb.append(getLocalizationManager().getLocalizedTextString("key16")); //$NON-NLS-1$
+ sb.append(m_newline);
+ for(int i=0; i<=DMessage.InSIZE; i++)
+ {
+ long amt = cnt.getInCount(i);
+ if (amt > 0)
+ {
+ sb.append('\n');
+ sb.append(DMessage.inTypeName(i));
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(amt);
+ }
+ }
+
+ sb.append("\n\n"); //$NON-NLS-1$
+ sb.append(getLocalizationManager().getLocalizedTextString("key17")); //$NON-NLS-1$
+ sb.append("\n"); //$NON-NLS-1$
+ for(int i=0; i<=DMessage.OutSIZE; i++)
+ {
+ long amt = cnt.getOutCount(i);
+ if (amt > 0)
+ {
+ sb.append('\n');
+ sb.append(DMessage.outTypeName(i));
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(amt);
+ }
+ }
+
+ sb.append('\n');
+ cli.out( sb.toString() );
+ }
+ catch(NullPointerException e)
+ {
+ throw new IllegalStateException();
+ }
+ }
+
+ public static void doShowFuncs(DebugCLI cli)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ String arg = null;
+ FileInfoCache fileInfo = cli.getFileCache();
+
+ // we take an optional single arg which specifies a module
+ try
+ {
+ if (cli.hasMoreTokens())
+ {
+ arg = cli.nextToken();
+ int id = arg.equals(".") ? cli.propertyGet(DebugCLI.LIST_MODULE) : cli.parseFileArg(cli.getActiveIsolateId(), -1, arg); //$NON
+
+ DModule m = (DModule)fileInfo.getFile(id, cli.getActiveIsolateId());
+ m.lineMapping(sb);
+ }
+ else
+ {
+ SourceFile[] ar = fileInfo.getFileList();
+ if (ar == null)
+ cli.err(getLocalizationManager().getLocalizedTextString("key18")); //$NON-NLS-1$
+ else
+ {
+ for (int i = 0; ar != null && i < ar.length; i++)
+ {
+ DModule m = (DModule)ar[i];
+ m.lineMapping(sb);
+ }
+ }
+ }
+
+ cli.out(sb.toString());
+ }
+ catch(NullPointerException npe)
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key19")); //$NON-NLS-1$
+ }
+ catch(ParseException pe)
+ {
+ cli.err(pe.getMessage());
+ }
+ catch(AmbiguousException ae)
+ {
+ cli.err(ae.getMessage());
+ }
+ catch(NoMatchException nme)
+ {
+ cli.err(nme.getMessage());
+ }
+ }
+
+ /**
+ * Dump the content of internal variables
+ */
+ public static void doShowProperties(DebugCLI cli)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ Session session = cli.getSession();
+ for (String key: cli.propertyKeys())
+ {
+ int value = cli.propertyGet(key);
+ sb.append(key);
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(value);
+ sb.append('\n');
+ }
+
+ // session manager
+ {
+ PlayerSessionManager mgr = (PlayerSessionManager)Bootstrap.sessionManager();
+ sb.append(getLocalizationManager().getLocalizedTextString("key21")); //$NON-NLS-1$
+ sb.append('\n');
+ for (String key: mgr.keySet())
+ {
+ Object value = mgr.getPreferenceAsObject(key);
+ sb.append(key);
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(value);
+ sb.append('\n');
+ }
+ }
+
+ if (session != null)
+ {
+ PlayerSession psession = (PlayerSession)session;
+ sb.append(getLocalizationManager().getLocalizedTextString("key22")); //$NON-NLS-1$
+ sb.append('\n');
+ for (String key: psession.keySet())
+ {
+ Object value = psession.getPreferenceAsObject(key);
+ sb.append(key);
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(value);
+ sb.append('\n');
+ }
+ }
+
+ cli.out( sb.toString() );
+ }
+
+ /**
+ * Dump the break reason and offset
+ */
+ public static void doShowBreak(DebugCLI cli) throws NotConnectedException
+ {
+ int isolateId = cli.getActiveIsolateId();
+ cli.waitTilHalted(isolateId);
+ try
+ {
+ Session session = cli.getSession();
+ StringBuilder sb = new StringBuilder();
+ if (session.getWorkerSession(isolateId).isSuspended())
+ {
+ sb.append(getLocalizationManager().getLocalizedTextString("stopped")); //$NON-NLS-1$
+ sb.append(' ');
+ appendBreakInfo(cli, sb, true, isolateId);
+ }
+ else
+ sb.append(getLocalizationManager().getLocalizedTextString("key24")); //$NON-NLS-1$
+
+ cli.out( sb.toString() );
+ }
+ catch(NullPointerException npe)
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key25")); //$NON-NLS-1$
+ }
+ }
+
+ // Extended low level break information
+ public static void appendBreakInfo(DebugCLI cli, StringBuilder sb, boolean includeFault, int isolateId) throws NotConnectedException
+ {
+ Session session = cli.getSession();
+ FileInfoCache fileInfo = cli.getFileCache();
+
+ int reason = session.suspendReason();
+ int offset = ((PlayerSession)session).getSuspendOffset();
+ int index = ((PlayerSession)session).getSuspendActionIndex();
+
+ SwfInfo info = null;
+ try { info = fileInfo.getSwfs(isolateId)[index]; } catch(ArrayIndexOutOfBoundsException oobe) {}
+ if (info != null)
+ {
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("swfName", FileInfoCache.nameOfSwf(info) ); //$NON-NLS-1$
+ sb.append(getLocalizationManager().getLocalizedTextString("key35", args)); //$NON-NLS-1$
+ sb.append(' ');
+ }
+
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("address", "0x" + FieldFormat.formatLongToHex(new StringBuilder(), offset, 8) + " (" + offset + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ sb.append(getLocalizationManager().getLocalizedTextString("atAddress", args)); //$NON-NLS-1$
+
+ if (includeFault)
+ {
+ args = new HashMap<String, String>();
+ StringBuilder reasonBuffer = new StringBuilder();
+ cli.appendReason(reasonBuffer, reason);
+ args.put("fault", reasonBuffer.toString() ); //$NON-NLS-1$
+ sb.append(' ');
+ sb.append(getLocalizationManager().getLocalizedTextString("haltedDueToFault", args)); //$NON-NLS-1$
+ }
+ }
+
+ // Raw direct call to Player
+ public static void doShowVariable(DebugCLI cli) throws PlayerDebugException
+ {
+ int isolateId = cli.getActiveIsolateId();
+ cli.waitTilHalted(isolateId);
+ try
+ {
+ // an integer followed by a variable name
+ Session session = cli.getSession();
+ long id = cli.nextLongToken();
+ String name = (cli.hasMoreTokens()) ? cli.nextToken() : null;
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ sb.append(" = "); //$NON-NLS-1$
+ Value v = ((PlayerSession)session).getValue(id, name, isolateId);
+ cli.m_exprCache.appendVariableValue(sb, v, isolateId);
+ cli.out( sb.toString() );
+ }
+ catch(NullPointerException npe)
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key26")); //$NON-NLS-1$
+ }
+ }
+
+ public static void doDisassemble(DebugCLI cli) throws PlayerDebugException
+ {
+ /* currentXXX may NOT be invalid! */
+ int currentModule = cli.propertyGet(DebugCLI.LIST_MODULE);
+ int currentLine = cli.propertyGet(DebugCLI.LIST_LINE);
+ int currentIsolate = cli.propertyGet(DebugCLI.LIST_WORKER);
+
+ String arg1 = null;
+ int module1 = currentModule;
+ int line1 = currentLine;
+
+ String arg2 = null;
+ int line2 = currentLine;
+
+ boolean functionNamed = false;
+ int numLines = 0;
+ try
+ {
+ FileInfoCache fileInfo = cli.getFileCache();
+ Session session = cli.getSession();
+ int isolateId = cli.getActiveIsolateId();
+ if (cli.hasMoreTokens())
+ {
+ arg1 = cli.nextToken();
+ if (arg1.equals("-")) //$NON-NLS-1$
+ {
+ // move back one line
+ line1 = line2 = line1 - 1;
+ }
+ else
+ {
+ int wasFunc = 0;
+
+ FileLocation[] fileLocations = cli.parseLocationArg(currentModule, currentLine, arg1, false);
+
+ if (fileLocations.length == 1) {
+ module1 = fileLocations[0].getModule();
+ line2 = line1 = fileLocations[0].getLine();
+ functionNamed = (fileLocations[0].getWasFunc() != 0);
+ }
+
+ if (cli.hasMoreTokens()) {
+ arg2 = cli.nextToken();
+ line2 = cli.parseLineArg(module1, arg2);
+ }
+ }
+ }
+ else
+ {
+ // since no parms test for valid location if none use players concept of where we stopped
+ if( fileInfo.getFile(currentModule, currentIsolate) == null)
+ {
+ //here we simply use the players concept of suspsend
+ DSuspendInfo info = ((PlayerSession)session).getSuspendInfoIsolate(isolateId);
+ int at = info.getOffset();
+ int which = info.getActionIndex();
+ int until = info.getNextOffset();
+ if (info.getReason() == SuspendReason.Unknown)
+ throw new SuspendedException();
+
+ SwfInfo swf = fileInfo.getSwfs(isolateId)[which];
+ outputAssembly(cli, (DSwfInfo)swf, at, until);
+ throw new AmbiguousException(getLocalizationManager().getLocalizedTextString("key27")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Check for a few error conditions, otherwise we'll write a listing!
+ */
+ if (cli.hasMoreTokens())
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key28")); //$NON-NLS-1$
+ }
+ else
+ {
+ SourceFile file = fileInfo.getFile(module1);
+ numLines = file.getLineCount();
+
+ // pressing return is ok, otherwise throw the exception
+ if (line1 > numLines && arg1 != null)
+ throw new IndexOutOfBoundsException();
+
+ /* if no arg2 then user list a single line */
+ if (arg2 == null)
+ line2 = line1;
+
+ /* adjust our range of lines to ensure we conform */
+ if (line1 < 1)
+ {
+ /* shrink line 1, grow line2 */
+ line2 += -(line1 - 1);
+ line1 = 1;
+ }
+
+ if (line2 > numLines)
+ line2 = numLines;
+
+ // System.out.println("1="+module1+":"+line1+",2="+module2+":"+line2+",num="+numLines+",half="+half);
+
+ /* nothing to display */
+ if (line1 > line2)
+ throw new IndexOutOfBoundsException();
+
+ /* now dump the mixed source / assembly */
+ // now lets find which swf this in
+ DSwfInfo swf = (DSwfInfo)fileInfo.swfForFile(file, cli.getActiveIsolateId());
+ ActionLocation lStart = null;
+ ActionLocation lEnd = null;
+
+ if (swf == null)
+ {
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("arg3", file.getName()); //$NON-NLS-1$
+ cli.err(getLocalizationManager().getLocalizedTextString("key29", args)); //$NON-NLS-1$
+ }
+ else if (functionNamed)
+ {
+ // if we name a function just dump the whole thing without source.
+ int offset = file.getOffsetForLine(line1);
+ lStart = swf.locate(offset);
+ if (lStart.function == null)
+ cli.err(getLocalizationManager().getLocalizedTextString("key30")); //$NON-NLS-1$
+ else
+ {
+ // create a psudeo action list from which to disasemble the function
+ ActionList al = new ActionList(true);
+ al.setActionOffset(0, lStart.function);
+ lStart.actions = al;
+ lStart.at = 0;
+ lEnd = new ActionLocation();
+ lEnd.actions = al;
+ lEnd.at = 0;
+ outputAssembly(cli, swf, lStart, lEnd);
+ }
+ }
+ else
+ {
+ ActionLocation lastEnd = null;
+ for(int i=line1; i<=line2; i++)
+ {
+ int offset = file.getOffsetForLine(i);
+
+ // locate the action list associated with this of the swf
+ if (offset != 0)
+ {
+ // get the starting point and try to locate a nice ending
+ lStart = swf.locate(offset);
+ lEnd = swf.locateSourceLineEnd(lStart);
+
+ // now see if we skipped some assembly between source lines
+ if (lastEnd != null)
+ {
+ lastEnd.at++; // point our pseudo start to the next action
+
+ // new actions list so attempt to find the end of source in the old actions list
+ if (lastEnd.actions != lStart.actions && lastEnd.actions.size() != lastEnd.at)
+ {
+ String atString = Integer.toHexString(lastEnd.actions.getOffset(lastEnd.at));
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("arg4", atString); //$NON-NLS-1$
+ cli.out(getLocalizationManager().getLocalizedTextString("key31", args)); //$NON-NLS-1$
+
+ // we are missing some of the dissassembly, so back up a bit and dump it out
+ ActionLocation gapEnd = swf.locateSourceLineEnd(lastEnd);
+ outputAssembly(cli, swf, lastEnd, gapEnd);
+ }
+ else if (lastEnd.at < lStart.at)
+ {
+ // same action list but we skipped some instructions
+ ActionLocation gapEnd = new ActionLocation(lStart);
+ gapEnd.at--;
+ outputAssembly(cli, swf, lastEnd, gapEnd);
+ }
+ }
+ lastEnd = lEnd;
+ }
+
+ // dump source
+ cli.outputSource(module1, i, file.getLine(i));
+
+ // obtain the offset, locate it in the swf
+ if (offset != 0)
+ outputAssembly(cli, swf, lStart, lEnd);
+ }
+
+ /* save away valid context */
+ cli.propertyPut(DebugCLI.LIST_MODULE, module1);
+ cli.propertyPut(DebugCLI.LIST_LINE, line2 + 1); // add one
+ cli.m_repeatLine = "disassemble"; /* allow repeated listing by typing CR */ //$NON-NLS-1$
+ }
+ }
+ }
+ catch(IndexOutOfBoundsException iob)
+ {
+ String name = "#"+module1; //$NON-NLS-1$
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("arg5", Integer.toString(line1)); //$NON-NLS-1$
+ args.put("arg6", name); //$NON-NLS-1$
+ args.put("arg7", Integer.toString(numLines)); //$NON-NLS-1$
+ cli.err(getLocalizationManager().getLocalizedTextString("key32", args)); //$NON-NLS-1$
+ }
+ catch(AmbiguousException ae)
+ {
+ cli.err(ae.getMessage());
+ }
+ catch(NullPointerException npe)
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key33")); //$NON-NLS-1$
+ }
+ catch(ParseException pe)
+ {
+ cli.err(pe.getMessage());
+ }
+ catch(NoMatchException nme)
+ {
+ cli.err(nme.getMessage());
+ }
+ catch(SuspendedException se)
+ {
+ cli.err(getLocalizationManager().getLocalizedTextString("key34")); //$NON-NLS-1$
+ }
+ }
+
+ private static LocalizationManager getLocalizationManager()
+ {
+ return DebugCLI.getLocalizationManager();
+ }
+
+ /**
+ * Disassemble part of the swf to the output
+ */
+ public static ActionLocation outputAssembly(DebugCLI cli, DSwfInfo swf, int start, int end)
+ {
+ // first we need to locate the action list associated with this
+ // portion of the swf
+ ActionLocation lStart = swf.locate(start);
+ ActionLocation lEnd = (end > -1) ? swf.locate(end) : swf.locateSourceLineEnd(lStart);
+
+ return outputAssembly(cli, swf, lStart, lEnd);
+ }
+
+ public static ActionLocation outputAssembly(DebugCLI cli, SwfInfo info, ActionLocation lStart, ActionLocation lEnd)
+ {
+ // now make sure our actions lists are the same (i.e we haven't spanned past one tag)
+ if (lStart.actions != lEnd.actions)
+ lEnd.at = lStart.actions.size()-1;
+
+ Disassembler.disassemble(lStart.actions, lStart.pool, lStart.at, lEnd.at, new PrintWriter(cli.getOut()));
+ return lEnd;
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/ExtensionsDisabled.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/ExtensionsDisabled.java b/debugger/src/main/java/flex/tools/debugger/cli/ExtensionsDisabled.java
new file mode 100644
index 0000000..caf33af
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/ExtensionsDisabled.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+/**
+ * ExtensionsDisabled class is a singleton that contains
+ * every cli method that does not conform to the
+ * API. There are two implementations of this singleton
+ * In Extensions the full code is provided in this class
+ * ExtensionsDisabled emtpy stubs are provided that allow
+ * for DebugCLI to be fully compliant with the API
+ */
+public class ExtensionsDisabled
+{
+ public static void doShowStats(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void doShowFuncs(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void doShowProperties(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void doShowBreak(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void appendBreakInfo(DebugCLI cli, StringBuilder sb, boolean includeFault) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void doShowVariable(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+ public static void doDisassemble(DebugCLI cli) { cli.out("Command not supported."); } //$NON-NLS-1$
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/FaultActions.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/FaultActions.java b/debugger/src/main/java/flex/tools/debugger/cli/FaultActions.java
new file mode 100644
index 0000000..73bc074
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/FaultActions.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.util.HashMap;
+
+import flash.localization.LocalizationManager;
+import flash.tools.debugger.events.DivideByZeroFault;
+import flash.tools.debugger.events.ExceptionFault;
+import flash.tools.debugger.events.InvalidTargetFault;
+import flash.tools.debugger.events.InvalidURLFault;
+import flash.tools.debugger.events.InvalidWithFault;
+import flash.tools.debugger.events.ProtoLimitFault;
+import flash.tools.debugger.events.RecursionLimitFault;
+import flash.tools.debugger.events.ScriptTimeoutFault;
+import flash.tools.debugger.events.StackUnderFlowFault;
+
+/**
+ * FaultActions proivdes a convenient wrapper for housing the user specified
+ * behaviour for a set of faults (aka text strings)
+ *
+ * The underlying data structure is a HashMap that maps strings (i.e. fault
+ * names) to Integers. The integers are used as bit fields for holding
+ * the state of setting per fault.
+ *
+ * Add new actions by calling addAction("name")
+ */
+public class FaultActions
+{
+ HashMap<String, Integer> m_faults = new HashMap<String, Integer>();
+ HashMap<String, String> m_description = new HashMap<String, String>(); // @todo should really use an object within the faults map for this
+ HashMap<String, Integer> m_actions = new HashMap<String, Integer>();
+
+ int m_nextBitForAction = 0x1; // the next bit to use for the action
+
+ private FaultActions() {}
+
+ Integer get(String o) { return m_faults.get(o); }
+ Integer getAction(String o) { return m_actions.get(o); }
+ void put(String k, Integer v){ m_faults.put(k,v); }
+
+ /* getters */
+ public void clear() { m_faults.clear(); }
+ public int size() { return m_faults.size(); }
+ public Object[] names() { return m_faults.keySet().toArray(); }
+ public Object[] actions() { return m_actions.keySet().toArray(); }
+ public boolean exists(String k) { return (get(k) == null) ? false : true; }
+
+ public void putDescription(String k, String v) { m_description.put(k,v); }
+ public String getDescription(String k) { return (m_description.get(k) == null) ? "" : m_description.get(k); } //$NON-NLS-1$
+
+ /**
+ * Add a new fault to the table, with all actions disabled
+ */
+ public void add(String k)
+ {
+ put(k, new Integer(0));
+ }
+
+ /**
+ * Add a new action type to the table
+ */
+ public void addAction(String k)
+ {
+ Integer v = new Integer(m_nextBitForAction++);
+ m_actions.put(k,v);
+ }
+
+ /**
+ * Check if the given fault has the action set or not
+ */
+ public boolean is(String fault, String action)
+ {
+ int mask = getAction(action).intValue();
+ int bits = get(fault).intValue();
+
+ boolean set = ( (bits & mask) == mask ) ? true : false;
+ return set;
+ }
+
+ /**
+ * Sets the action bits as appropriate for the given fault
+ * and action
+ */
+ public int action(String fault, String action)
+ {
+ // first check if fault is legal
+ Integer current = get(fault);
+ if (current == null)
+ throw new IllegalArgumentException(fault);
+
+ // check for no?
+ boolean no = action.startsWith("no"); //$NON-NLS-1$
+ if (no)
+ action = action.substring(2);
+
+ // do the search for action
+ Integer bit = getAction(action);
+ if (bit == null)
+ throw new IllegalArgumentException(action);
+
+ // now do the math
+ int old = current.intValue();
+ int mask = bit.intValue();
+
+ int n = (old & (~mask)); // turn it off
+ n = (no) ? n : (n | mask); // leave it off or turn it on
+
+ put(fault, new Integer(n));
+
+ return n;
+ }
+
+ public static class FaultActionsBuilder {
+
+ private final LocalizationManager localizationManager;
+
+ public FaultActionsBuilder(LocalizationManager localizationManager) {
+ super();
+ this.localizationManager = localizationManager;
+ }
+
+ public FaultActions build() {
+ FaultActions faultActions = new FaultActions();
+ populateFaultTable(faultActions);
+ return faultActions;
+ }
+
+ private void populateFaultTable(FaultActions faultActions) {
+ // possible actions for our fault table
+ faultActions.addAction("stop"); //$NON-NLS-1$
+ faultActions.addAction("print"); //$NON-NLS-1$
+
+ // the faults we support
+ faultActions.add(InvalidTargetFault.name);
+ faultActions.add(RecursionLimitFault.name);
+ faultActions.add(InvalidWithFault.name);
+ faultActions.add(ProtoLimitFault.name);
+ faultActions.add(InvalidURLFault.name);
+ faultActions.add(ExceptionFault.name);
+ faultActions.add(StackUnderFlowFault.name);
+ faultActions.add(DivideByZeroFault.name);
+ faultActions.add(ScriptTimeoutFault.name);
+ // faultActions.add(ConsoleErrorFault.name);
+
+ // nice description of the faults
+ faultActions.putDescription(
+ InvalidTargetFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "invalidTargetFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ RecursionLimitFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "recursionLimitFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ InvalidWithFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "invalidWithFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ ProtoLimitFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "protoLimitFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ InvalidURLFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "invalidUrlFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ ExceptionFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "exceptionFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ StackUnderFlowFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "stackUnderflowFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ DivideByZeroFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "divideByZeroFault")); //$NON-NLS-1$
+ faultActions.putDescription(
+ ScriptTimeoutFault.name,
+ getLocalizationManager().getLocalizedTextString(
+ "scriptTimeoutFault")); //$NON-NLS-1$
+ // faultActions.putDescription(ConsoleErrorFault.name,
+ // "ActionScript recoverable error");
+
+ // default values for the faults
+ faultActions.action(InvalidTargetFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(InvalidTargetFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(RecursionLimitFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(RecursionLimitFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(InvalidWithFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(InvalidWithFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(ProtoLimitFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(ProtoLimitFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(InvalidURLFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(InvalidURLFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(ExceptionFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(ExceptionFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(StackUnderFlowFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(StackUnderFlowFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(DivideByZeroFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(DivideByZeroFault.name, "print"); //$NON-NLS-1$
+ faultActions.action(ScriptTimeoutFault.name, "stop"); //$NON-NLS-1$
+ faultActions.action(ScriptTimeoutFault.name, "print"); //$NON-NLS-1$
+ // faultActions.action(ConsoleErrorFault.name, "print"); //$NON-NLS-1$
+ // faultActions.action(ConsoleErrorFault.name, "stop"); //$NON-NLS-1$
+ }
+
+ private LocalizationManager getLocalizationManager() {
+ return localizationManager;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flex/tools/debugger/cli/FileInfoCache.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flex/tools/debugger/cli/FileInfoCache.java b/debugger/src/main/java/flex/tools/debugger/cli/FileInfoCache.java
new file mode 100644
index 0000000..e66b89a
--- /dev/null
+++ b/debugger/src/main/java/flex/tools/debugger/cli/FileInfoCache.java
@@ -0,0 +1,569 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import flash.tools.debugger.InProgressException;
+import flash.tools.debugger.Isolate;
+import flash.tools.debugger.NoResponseException;
+import flash.tools.debugger.Session;
+import flash.tools.debugger.SourceFile;
+import flash.tools.debugger.SwfInfo;
+import flash.util.IntMap;
+
+/**
+ * FileInfoCache manages a list of files that are unique
+ * across multiple swfs.
+ */
+public class FileInfoCache implements Comparator<SourceFile>
+{
+ Session m_session;
+
+ /**
+ * We can get at files by module id or path
+ */
+ IntMap m_byInt = new IntMap();
+ HashMap<Integer, IntMap> m_isolateState = new HashMap<Integer, IntMap> ();
+
+ private IntMap getIsolateState(int isolateId) {
+ IntMap isolateState = null;
+ if (!m_isolateState.containsKey(isolateId)) {
+ isolateState = new IntMap();
+ m_isolateState.put(isolateId, isolateState);
+ }
+ else
+ isolateState = m_isolateState.get(isolateId);
+ return isolateState;
+ }
+
+ SourceFile[] m_files = null;
+ SourceFile[] m_isolateFiles = null;
+ SwfInfo m_swfFilter = null;
+ int m_swfsLoaded = 0;
+ boolean m_dirty = false;
+ int lastActiveIsolate = Isolate.DEFAULT_ID;
+
+ public FileInfoCache() {
+
+ }
+
+ public void bind(Session s) { setSession(s); }
+ public void unbind() { m_session = null; }
+
+ public SourceFile getFile(int i) {
+ return getFile(i, Isolate.DEFAULT_ID);
+ }
+
+ public SourceFile getFile(int i, int isolateId) {
+ populate();
+ if (isolateId == Isolate.DEFAULT_ID)
+ return (SourceFile) m_byInt.get(i);
+ else
+ return (SourceFile)getIsolateState(isolateId).get(i);
+ }
+
+ public SourceFile[] getFileList() {
+ populate();
+ return m_files;
+ }
+
+ public SourceFile[] getFileList(int isolateId) {
+ populate();
+ if (isolateId == Isolate.DEFAULT_ID) {
+ final Object[] valuesToArray = m_byInt.valuesToArray(new Object[m_byInt.size()]);
+ return Arrays.copyOf(valuesToArray, valuesToArray.length, SourceFile[].class);
+ }
+ else if (isolateId != lastActiveIsolate) {
+ buildIsolateFiles(isolateId);
+ }
+ return m_isolateFiles;
+ }
+
+ private void buildIsolateFiles(int isolateId) {
+ SwfInfo[] swfs = getSwfs(isolateId);
+ boolean worked = true; // check that all worked correctly
+ ArrayList<SourceFile> files = new ArrayList<SourceFile>();
+
+ for(int i=0; i<swfs.length; i++)
+ {
+ if (swfs[i] != null)
+ worked = loadSwfFiles(files, swfs[i]) ? worked : false;
+ }
+
+ // trim the file list
+ ArrayList<SourceFile> fa = trimFileList(files);
+ m_isolateFiles = fa.toArray( new SourceFile[fa.size()] );
+
+ // sort this array in place so calls to getFileList will be ordered
+ Arrays.sort(m_isolateFiles, this);
+ }
+
+ public Iterator getAllFiles(int isolateId) {
+ populate();
+ if (isolateId == Isolate.DEFAULT_ID)
+ return m_byInt.iterator();
+ else
+ return getIsolateState(isolateId).iterator();
+ }
+
+ public SwfInfo getSwfFilter() { return m_swfFilter; }
+ public boolean isSwfFilterOn() { return (m_swfFilter != null); }
+ public void setDirty() { m_dirty = true; }
+
+ void setSession(Session s)
+ {
+ m_session = s;
+ m_swfFilter = null;
+ clear();
+ }
+
+ SwfInfo[] getAllSwfs() {
+ ArrayList<SwfInfo> result = new ArrayList<SwfInfo>();
+
+ for ( Isolate isolate : m_session.getWorkers()) {
+ SwfInfo[] swfs = new SwfInfo[0];
+ try {
+ swfs = m_session.getWorkerSession(isolate.getId()).getSwfs();
+ } catch (NoResponseException e) {
+ swfs = new SwfInfo[0];
+ }
+
+ for (SwfInfo swf : swfs)
+ result.add(swf);
+ }
+
+ return result.toArray(new SwfInfo[0]);
+ }
+
+ void populate()
+ {
+ // do we have a new swf to load?
+ if (m_session != null && (m_dirty || getAllSwfs().length > m_swfsLoaded))
+ reloadCache();
+ }
+
+ void reloadCache()
+ {
+ clear();
+ loadCache();
+ m_dirty = false;
+ }
+
+ void clear()
+ {
+ m_byInt.clear();
+ m_isolateState.clear();
+ m_files = null;
+ }
+
+ /**
+ * Determine if the given SourceFile is in the current fileList
+ */
+ public boolean inFileList(SourceFile f)
+ {
+ boolean isIt = false;
+
+ SourceFile[] files = getFileList();
+ for(int i=0; i<files.length && !isIt; i++)
+ {
+ if (files[i] == f)
+ isIt = true;
+ }
+ return isIt;
+ }
+
+ /**
+ * Go out to the session and request a list of files
+ * But we dump ones that have a name collision.
+ * Also if selectedSwf is set then we only add files
+ * that are contained within the given swf.
+ */
+ void loadCache()
+ {
+ boolean worked = true; // check that all worked correctly
+ ArrayList<SourceFile> files = new ArrayList<SourceFile>();
+ SwfInfo[] swfs = getAllSwfs();
+ for(int i=0; i<swfs.length; i++)
+ {
+ if (swfs[i] != null)
+ worked = loadSwfFiles(files, swfs[i]) ? worked : false;
+ }
+
+ // trim the file list
+ ArrayList<SourceFile> fa = trimFileList(files);
+ m_files = fa.toArray( new SourceFile[fa.size()] );
+
+ // sort this array in place so calls to getFileList will be ordered
+ Arrays.sort(m_files, this);
+
+ // mark our cache complete if all was good.
+ if (worked)
+ m_swfsLoaded = swfs.length;
+ }
+
+ boolean loadSwfFiles(ArrayList<SourceFile> ar, SwfInfo swf)
+ {
+ boolean worked = true;
+ try
+ {
+ // @todo should we include unloaded swfs?
+ SourceFile[] files = swf.getSourceList(m_session);
+ ar.ensureCapacity(ar.size()+files.length);
+
+ // add each file to our global source file IntMap and our list
+ for(int i=0; i<files.length; i++)
+ {
+ putFile(files[i], swf.getIsolateId());
+ ar.add(files[i]);
+ }
+ }
+ catch(InProgressException ipe)
+ {
+ // can't load this one, its not ready yet
+ worked = false;
+ }
+ return worked;
+ }
+
+ /**
+ * Walk the file list looking for name collisions.
+ * If we find one, then we remove it
+ */
+ ArrayList<SourceFile> trimFileList(ArrayList<SourceFile> files)
+ {
+ HashMap<String, String> names = new HashMap<String, String>();
+ ArrayList<SourceFile> list = new ArrayList<SourceFile>();
+
+ int size = files.size();
+ for(int i=0; i<size; i++)
+ {
+ boolean addIt = false;
+
+ SourceFile fi = files.get(i);
+ // no filter currently in place so we add the file as long
+ // as no duplicates exist. We use the original Swd full
+ // name for matching.
+ String fName = fi.getRawName();
+ if (m_swfFilter == null)
+ {
+ // If it exists, then we don't add it!
+ if (names.get(fName) == null)
+ addIt = true;
+ }
+ else
+ {
+ // we have a filter in place so, see
+ // if the source file is in our currently
+ // selected swf.
+ addIt = m_swfFilter.containsSource(fi);
+ }
+
+ // did we mark this one to add?
+ if (addIt)
+ {
+ names.put(fName, fName);
+ list.add(fi);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * All files from all swfs are placed into our byInt map
+ * since we know that ids are unique across the entire
+ * Player session.
+ *
+ * This is also important in the case that the player
+ * halts in one of these files, that the debugger
+ * be able to locate the SourceFile so that we can
+ * display the correct context for the user.
+ */
+ void putFile(SourceFile s, int isolateId)
+ {
+ int i = s.getId();
+ if (isolateId == Isolate.DEFAULT_ID)
+ m_byInt.put(i, s);
+ else
+ getIsolateState(isolateId).put(i, s);
+ }
+
+ /**
+ * Attempt to set a swf as a filter
+ * for the file list that we create
+ */
+ public boolean setSwfFilter(String swfName)
+ {
+ // look for a match in our list
+ boolean worked = false;
+ if (swfName == null)
+ {
+ m_swfFilter = null;
+ worked = true;
+ }
+ else
+ {
+ SwfInfo[] swfs = getAllSwfs();
+ for(int i=0; i<swfs.length; i++)
+ {
+ SwfInfo e = swfs[i];
+ if (e != null && nameOfSwf(e).equalsIgnoreCase(swfName))
+ {
+ worked = true;
+ m_swfFilter = e;
+ break;
+ }
+ }
+ }
+
+ // reload if it worked
+ if (worked)
+ reloadCache();
+
+ return worked;
+ }
+
+ // list all swfs we know about
+ public SwfInfo[] getSwfs(int isolateId)
+ {
+ return getSwfsIsolate(isolateId);
+ }
+
+ public SwfInfo[] getSwfsIsolate(int isolateId)
+ {
+ SwfInfo[] swfs = null;
+ try
+ {
+ swfs = m_session.getWorkerSession(isolateId).getSwfs();
+ }
+ catch(NoResponseException nre)
+ {
+ swfs = new SwfInfo[] {}; // oh bery bad
+ }
+ return swfs;
+ }
+
+ /**
+ * Given a SourceFile locate the swf which it came from
+ */
+ public SwfInfo swfForFile(SourceFile f, int isolateId)
+ {
+ // We use the id to determine which swf this source files resides in
+ int id = f.getId();
+ SwfInfo info = null;
+ SwfInfo[] swfs = getSwfs(isolateId);//getAllSwfs();
+ for(int i=0; ( i<swfs.length && (info == null) ); i++)
+ {
+ if (swfs[i] != null && swfs[i].containsSource(f))
+ info = swfs[i];
+ }
+ return info;
+ }
+
+ // locate the name of the swf
+ public static String nameOfSwf(SwfInfo e)
+ {
+ int at = -1;
+ String name = e.getUrl();
+ if ( (at = e.getUrl().lastIndexOf('/')) > -1)
+ name = e.getUrl().substring(at+1);
+ if ( (at = e.getUrl().lastIndexOf('\\')) > -1)
+ name = e.getUrl().substring(at+1);
+ else if ( (at = e.getPath().lastIndexOf('\\')) > -1)
+ name = e.getPath().substring(at+1);
+ else if ( (at = e.getPath().lastIndexOf('/')) > -1)
+ name = e.getPath().substring(at+1);
+
+ // now rip off any trailing ? options
+ at = name.lastIndexOf('?');
+ name = (at > -1) ? name.substring(0, at) : name;
+
+ return name;
+ }
+
+ // locate the name of the swf
+ public static String shortNameOfSwf(SwfInfo e)
+ {
+ String name = nameOfSwf(e);
+
+ // now strip off any leading path
+ int at = -1;
+ if ( (at = name.lastIndexOf('/')) > -1)
+ name = name.substring(at+1);
+ else if ( (at = name.lastIndexOf('\\')) > -1)
+ name = name.substring(at+1);
+ return name;
+ }
+
+ /**
+ * Given the URL of a specfic swf determine
+ * if there is a file within it that appears
+ * to be the same as the given source file
+ * @param f
+ * @return
+ */
+ public SourceFile similarFileInSwf(SwfInfo info, SourceFile f) throws InProgressException
+ {
+ SourceFile hit = null;
+ SourceFile[] files = info.getSourceList(m_session);
+ if (!info.isProcessingComplete())
+ throw new InProgressException();
+
+ for(int i=0; i<files.length; i++)
+ {
+ if (filesMatch(f, files[i]))
+ hit = files[i];
+ }
+ return hit;
+ }
+
+ /**
+ * Comparator interface for sorting SourceFiles
+ */
+ public int compare(SourceFile o1, SourceFile o2)
+ {
+ String n1 = o1.getName();
+ String n2 = o2.getName();
+
+ return n1.compareTo(n2);
+ }
+
+ /**
+ * Compare two files and determine if they are the same.
+ * Our criteria included only line count package names
+ * and the name of the class itself. If there are
+ * any other differences then we won't be able to detect
+ * them. We should probably do something like an MD5
+ * computation on the characters in ScriptText. Then
+ * we'd really be sure of a match.
+ * @param a first file to compare
+ * @param b second file to compare
+ * @return true if files appear to be the same
+ */
+ public boolean filesMatch(SourceFile a, SourceFile b)
+ {
+ boolean yes = true;
+
+ if (a == null || b == null)
+ yes = false;
+ else if (a.getPackageName().compareTo(b.getPackageName()) != 0)
+ yes = false;
+ else if (a.getName().compareTo(b.getName()) != 0)
+ yes = false;
+ else if (a.getLineCount() != b.getLineCount()) // warning, this is sometimes expensive, so do it last
+ yes = false;
+
+ return yes;
+ }
+ /**
+ * Return a array of SourceFiles whose names match
+ * the specified string. The array is sorted by name.
+ * The input can be mx.controls.xxx which will
+ */
+ public SourceFile[] getFiles(String matchString)
+ {
+ return getFiles(matchString, -1);
+ }
+
+ public SourceFile[] getFiles(String matchString, int isolateId)
+ {
+ boolean doStartsWith = false;
+ boolean doIndexOf = false;
+ boolean doEndsWith = false;
+
+ boolean leadingAsterisk = matchString.startsWith("*") && matchString.length() > 1; //$NON-NLS-1$
+ boolean trailingAsterisk = matchString.endsWith("*"); //$NON-NLS-1$
+ boolean usePath = matchString.indexOf('.') > -1;
+
+ if (leadingAsterisk && trailingAsterisk)
+ {
+ matchString = matchString.substring(1, matchString.length() - 1);
+ doIndexOf = true;
+ }
+ else if (leadingAsterisk)
+ {
+ matchString = matchString.substring(1);
+ doEndsWith = true;
+ }
+ else if (trailingAsterisk)
+ {
+ matchString = matchString.substring(0, matchString.length() - 1);
+ doStartsWith = true;
+ }
+ else if (usePath)
+ {
+ doIndexOf = true;
+ }
+ else
+ {
+ doStartsWith = true;
+ }
+
+ SourceFile[] files = isolateId > -1 ? getFileList(isolateId) : getFileList();
+ ArrayList<SourceFile> fileList = new ArrayList<SourceFile>();
+ int n = files.length;
+ int exactHitAt = -1;
+ // If the matchString already starts with "." (e.g. ".as" or ".mxml"), then dotMatchString
+ // will be equal to matchString; otherwise, dotMatchString will be "." + matchString
+ String dotMatchString = (matchString.startsWith(".")) ? matchString : ("." + matchString); //$NON-NLS-1$ //$NON-NLS-2$
+ for (int i = 0; i < n; i++)
+ {
+ SourceFile sourceFile = files[i];
+ boolean pathExists = (usePath && sourceFile.getFullPath().matches(".*[/\\\\].*")); //$NON-NLS-1$
+ String name = pathExists ? sourceFile.getFullPath() : sourceFile.getName();
+
+ // if we are using the full path string, then prefix a '.' to our matching string so that abc.as and Gabc.as don't both hit
+ String match = (usePath && pathExists) ? dotMatchString : matchString;
+
+ match = match.replace('/', '.'); // get rid of path identifiers and use dots
+ match = match.replace('\\', '.');
+
+ name = name.replace('/', '.'); // get rid of path identifiers and use dots
+ name = name.replace('\\', '.'); // would be better to modify the input string, but we don't know which path char will be used.
+
+ // exact match? We are done
+ if (name.equals(match))
+ {
+ exactHitAt = i;
+ break;
+ }
+ else if (doStartsWith && name.startsWith(match))
+ fileList.add(sourceFile);
+ else if (doEndsWith && name.endsWith(match))
+ fileList.add(sourceFile);
+ else if (doIndexOf && name.contains(match))
+ fileList.add(sourceFile);
+ }
+
+ // trim all others if we have an exact file match
+ if (exactHitAt > -1)
+ {
+ fileList.clear();
+ fileList.add(files[exactHitAt]);
+ }
+
+ SourceFile[] fileArray = fileList.toArray( new SourceFile[fileList.size()] );
+ Arrays.sort(fileArray, this);
+ return fileArray;
+ }
+
+}