http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/ASTBuilder.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/ASTBuilder.java b/debugger/src/main/java/flash/tools/debugger/expression/ASTBuilder.java new file mode 100644 index 0000000..a3950a1 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/ASTBuilder.java @@ -0,0 +1,153 @@ +/* + * 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 flash.tools.debugger.expression; + +import java.io.IOException; +import java.io.Reader; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.tree.as.IASNode; + +import flash.localization.LocalizationManager; +import flash.tools.debugger.DebuggerLocalizer; + +/** + * ASTBuilder.java + * + * This class creates an abstract syntax tree representation + * of an expression given a sequence of tokens. + * + * The tree is built by calling the ActionScript compiler and + * having it parse the expression, then converting the result + * to a form we prefer. + * + * No compression is performed on the tree, thus expressions + * such as (3*4) will result in 3 nodes. + * + */ +public class ASTBuilder implements IASTBuilder +{ + private static LocalizationManager s_localizationManager; + + /** + * whether the fdb indirection operators are allowed, e.g. asterisk (*x) or + * trailing dot (x.) + */ + private boolean m_isIndirectionOperatorAllowed = true; + + static + { + // set up for localizing messages + s_localizationManager = new LocalizationManager(); + s_localizationManager.addLocalizer( new DebuggerLocalizer("flash.tools.debugger.expression.expression.") ); //$NON-NLS-1$ + } + + /** + * @param isIndirectionOperatorAllowed + * whether the fdb indirection operators are allowed, e.g. + * asterisk (*x) or trailing dot (x.) + */ + public ASTBuilder(boolean isIndirectionOperatorAllowed) + { + m_isIndirectionOperatorAllowed = isIndirectionOperatorAllowed; + } + + /** + * @return whether the fdb indirection operators are allowed, e.g. asterisk + * (*x) or trailing dot (x.) + */ + public boolean isIndirectionOperatorAllowed() + { + return m_isIndirectionOperatorAllowed; + } + + + /* + * @see flash.tools.debugger.expression.IASTBuilder#parse(java.io.Reader) + */ + public ValueExp parse(Reader in) throws IOException, ParseException + { + DebuggerExpression retval = new DebuggerExpression(); + + StringBuilder sb = new StringBuilder(); + int ch; + while ( (ch=in.read()) != -1 ) + sb.append((char)ch); + + String s = sb.toString(); + + // FB-16879: If expression begins with "#N" where N is a number, + // replace that with "$obj(N)". For example, "#3" would become + // "$obj(3)". Later, in PlayerSession.callFunction(), we will + // detect the $obj() function and handle it. + s = s.replaceFirst("^#([0-9]+)", "\\$obj($1)"); //$NON-NLS-1$ //$NON-NLS-2$ + + if (isIndirectionOperatorAllowed()) { + if (s.endsWith(".")) { //$NON-NLS-1$ + retval.setLookupMembers(true); + s = s.substring(0, s.length() - 1); + } else if (s.startsWith("*")) { //$NON-NLS-1$ + retval.setLookupMembers(true); + s = s.substring(1); + } + } + + // Enclose the expression in parentheses, in order to ensure that the + // parser considers it to be an expression. For example, "{x:3}" would + // be considered to be a block with label "x" and value "3", but, + // "({x:3})" is considered to be an inline object with field "x" that + // has value 3. + s = "(" + s + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + + final List<ICompilerProblem> errors = new ArrayList<ICompilerProblem>(); +// CompilerHandler newHandler = new CompilerHandler() { +// @Override +// public void error(final String filename, int ln, int col, String msg, String source) { +// ErrorInfo ei = new ErrorInfo(); +// ei.filename = filename; +// ei.ln = ln; +// ei.col = col; +// ei.msg = msg; +// ei.source = source; +// errors.add(ei); +// } +// }; +// cx.setHandler(newHandler); +// cx.scriptAssistParsing = true; + // Parser parser = new Parser(cx, s, "Expression"); //$NON-NLS-1$ + IASNode programNode = DebuggerUtil.parseExpression(s, errors); + //ProgramNode programNode = parser.parseProgram(); + + if (errors.size() > 0) { + ICompilerProblem firstError = errors.get(0); + throw new ParseException(firstError.toString(), firstError.getColumn()); + } + + retval.setProgramNode(programNode); + return retval; + } + + + static LocalizationManager getLocalizationManager() + { + return s_localizationManager; + } +}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/Context.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/Context.java b/debugger/src/main/java/flash/tools/debugger/expression/Context.java new file mode 100644 index 0000000..0088ac3 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/Context.java @@ -0,0 +1,126 @@ +/* + * 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 flash.tools.debugger.expression; + +import flash.tools.debugger.Session; +import flash.tools.debugger.Value; + +/** + * An object which returns a value given a name and + * appropriate context information. + */ +public interface Context +{ + /** + * Looks for an object of the given name in this context -- for example, a member variable. + * + * The returned Object can be of any type at all. For example, it could be: + * + * <ul> + * <li> a <code>flash.tools.debugger.Variable</code> </li> + * <li> your own wrapper around <code>Variable</code> </li> + * <li> a <code>flash.tools.debugger.Value</code> </li> + * <li> any built-in Java primitive such as <code>Long</code>, <code>Integer</code>, + * <code>Double</code>, <code>Boolean</code>, or <code>String</code> </li> + * <li> any other type you want which has a good <code>toString()</code>; see below </li> + * </ul> + * + * Since the return type is just Object, the returned value is only meaningful when + * passed to other functions this interface. For example, the returned Object can be + * passed to createContext(), assign(), or toValue(). + * + * @param o the object to look up; most commonly a string representing the name of + * a member variable. + */ + public Object lookup(Object o) throws NoSuchVariableException, PlayerFaultException; + + /** + * Looks for the members of an object. + * + * @param o + * A variable whose members we want to look up + * @return Some object which represents the members; could even be just a + * string. See lookup() for more information about the returned + * type. + * @see #lookup(Object) + */ + public Object lookupMembers(Object o) throws NoSuchVariableException; + + /** + * Creates a new context object by combining the current one and o. + * For example, if the user typed "myVariable.myMember", then this function + * will get called with o equal to the object which represents "myVariable". + * This function should return a new context which, when called with + * lookup("myMember"), will return an object for that member. + * + * @param o any object which may have been returned by this class's lookup() function + */ + public Context createContext(Object o); + + /** + * Assign the object o, the value v. + * + * @param o + * a variable to assign to -- this should be some value returned + * by an earlier call to lookup(). + * @param v + * a value, such as a Boolean, Long, String, etc. + */ + public void assign(Object o, Value v) throws NoSuchVariableException, PlayerFaultException; + + /** + * Enables/disables the creation of variables during lookup calls. + * This is ONLY used by AssignmentExp for creating a assigning a value + * to a property which currently does not exist. + */ + public void createPseudoVariables(boolean oui); + + /** + * Converts the object to a Value. + * + * @param o + * Either object that was returned by an earlier call to + * <code>lookup()</code>, or one of the raw types that can be + * returned by <code>Value.getValueAsObject()</code>. + * @return the corresponding Value, or <code>null</code>. + * @see Value#getValueAsObject() + */ + public Value toValue(Object o); + + /** + * Converts the context to a Value. Very similar to + * <code>toValue(Object o)</code>, except that the object being converted + * is the object that was used to initialize this context. + * + * @return the corresponding Value, or <code>null</code>. + */ + public Value toValue(); + + /** + * Returns the session associated with this context, or null. + * This can legitimately be null; for example, in fdb, you are + * allowed to do things like "set $columnwidth = 120" before + * beginning a debugging session. + */ + public Session getSession(); + + /** + * The worker id to which this context object belongs. + */ + public int getIsolateId(); +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpression.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpression.java b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpression.java new file mode 100644 index 0000000..14eab90 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpression.java @@ -0,0 +1,163 @@ +/* + * 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 flash.tools.debugger.expression; + +import java.util.HashSet; + +import org.apache.flex.compiler.internal.projects.ASCProject; +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorLogicalAndNode; +import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.workspaces.IWorkspace; + +import flash.tools.debugger.PlayerDebugException; + +/** + * A wrapper around an abstract syntax tree (AST) that was provided by the + * ActionScript Compiler (ASC), suitable for use by the debugger. + * + * When {@link #evaluate(Context)} is called, this will walk the AST and return + * a value. But please note that this class's implementation of expression + * evaluation should not be taken as a model of 100% perfect ActionScript + * evaluation. While this implementation handles all the cases the debugger is + * likely to run into, there are many edge cases that this class can't handle. + * For most cases where you need an on-the-fly expression evaluator, you would + * be better off using the code from the "esc" project. + * + * @author Mike Morearty + */ +class DebuggerExpression implements ValueExp { + + private final static HashSet<ASTNodeID> ASSIGN_OPRATORS = new HashSet<ASTNodeID>(); + static { + ASSIGN_OPRATORS.add(ASTNodeID.Op_AssignId); + ASSIGN_OPRATORS.add(ASTNodeID.Op_LeftShiftAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_RightShiftAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_UnsignedRightShiftAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_MultiplyAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_DivideAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_ModuloAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_BitwiseAndAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_BitwiseXorAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_BitwiseOrAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_AddAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_SubtractAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_LogicalAndAssignID); + ASSIGN_OPRATORS.add(ASTNodeID.Op_LogicalOrAssignID); + } + /** + * The AST representing the expression. + */ + private IASNode m_programNode; + + /** + * @see #isLookupMembers() + */ + private boolean m_lookupMembers = false; + + /** + * @return the AST representing the expression. + */ + public IASNode getProgramNode() { + return m_programNode; + } + + /** + * Sets the AST representing the expression. + */ + public void setProgramNode(IASNode programNode) { + m_programNode = programNode; + } + + /* + * @see flash.tools.debugger.expression.ValueExp#isLookupMembers() + */ + public boolean isLookupMembers() { + return m_lookupMembers; + } + + /** + * @see #isLookupMembers() + */ + public void setLookupMembers(boolean value) { + m_lookupMembers = value; + } + + /* + * @see flash.tools.debugger.expression.ValueExp#containsAssignment() + */ + public boolean containsAssignment() { + return containsAssignment(m_programNode); + } + + /** + * @param containsAssignment + */ + private boolean containsAssignment(IASNode node) { + if (ASSIGN_OPRATORS.contains(node.getNodeID())) { + return true; + } + for (int i = 0; i < node.getChildCount(); i++) { + if (containsAssignment(node.getChild(i))) { + return true; + } + } + return false; + } + + /* + * @see + * flash.tools.debugger.expression.ValueExp#evaluate(flash.tools.debugger + * .expression.Context) + */ + public Object evaluate(Context context) throws NumberFormatException, + NoSuchVariableException, PlayerFaultException, PlayerDebugException { + // assert m_cx.getScopeDepth() == 0; + // m_cx.pushScope(new ExpressionEvaluatorScope(context)); + try { + IExpressionEvaluator eval = new DebuggerExpressionEvaluator(); + DebuggerValue value = eval.evaluate(context, m_programNode); + + if (isLookupMembers()) { + return context.lookupMembers(value.debuggerValue); + } else { + return value.debuggerValue; + } + } catch (Exception e) { + // e.printStackTrace();//TODO : ASC3 : remove + if (e.getCause() instanceof NumberFormatException) { + throw (NumberFormatException) e.getCause(); + } else if (e.getCause() instanceof NoSuchVariableException) { + throw (NoSuchVariableException) e.getCause(); + } else if (e.getCause() instanceof PlayerFaultException) { + throw (PlayerFaultException) e.getCause(); + } else if (e.getCause() instanceof PlayerDebugException) { + throw (PlayerDebugException) e.getCause(); + } else { + e.printStackTrace(); + throw new PlayerDebugException(e.getLocalizedMessage()); + } + } finally { + // m_cx.popScope(); + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpressionEvaluator.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpressionEvaluator.java b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpressionEvaluator.java new file mode 100644 index 0000000..8536a51 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerExpressionEvaluator.java @@ -0,0 +1,76 @@ +/* + * 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 flash.tools.debugger.expression; + +import org.apache.flex.compiler.internal.projects.ASCProject; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.as.IASNode; + +/** + * @author ggv + * + */ +public class DebuggerExpressionEvaluator implements IExpressionEvaluator { + + private final ICompilerProject project; + private final IASTFolder logicalOperatorFolder; + + /** + * + */ + public DebuggerExpressionEvaluator() { + project = new ASCProject(new Workspace(), true); + logicalOperatorFolder = new LogicalOperatorsFolder(); + + } + + /** + * @param project2 + */ + public DebuggerExpressionEvaluator(ICompilerProject project2) { + logicalOperatorFolder = new LogicalOperatorsFolder(); + this.project = project2; + } + + @Override + public DebuggerValue evaluate(Context context, IASNode node) + throws Exception { + + if (node instanceof FoldedExpressionNode) { + /* + * Unfold the folded node, and if the unfolded subtree has a logical + * operator, fold the RHS of that + */ + node = logicalOperatorFolder + .unfoldOneLevel((FoldedExpressionNode) node); + } else { + /* + * Where ever it finds a logical operator, fold the rhs of that. + */ + node = logicalOperatorFolder.fold(node); + } + AS3DebuggerBURM burm = new AS3DebuggerBURM(); + burm.reducer = new AS3DebuggerReducer(context, project); + + burm.burm(node, AS3DebuggerBURM.__expression_NT); + DebuggerValue value = (DebuggerValue) burm.getResult(); + return value; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java new file mode 100644 index 0000000..c5492f2 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java @@ -0,0 +1,104 @@ +/* + * 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 flash.tools.debugger.expression; + +import java.io.FileNotFoundException; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; + +import org.apache.flex.compiler.common.SourceLocation; +import org.apache.flex.compiler.filespecs.IFileSpecification; +import org.apache.flex.compiler.internal.parsing.as.ASParser; +import org.apache.flex.compiler.internal.scopes.ASFileScope; +import org.apache.flex.compiler.internal.semantics.PostProcessStep; +import org.apache.flex.compiler.internal.tree.as.NodeBase; +import org.apache.flex.compiler.internal.tree.as.ScopedBlockNode; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.workspaces.IWorkspace; + +/** + * + * @author ggv + */ +public class DebuggerUtil +{ + + /** + * + * @param code + * @param problems + * @return + */ + public static IASNode parseExpression(String code, List<ICompilerProblem> problems) + { + IWorkspace workspace = new Workspace(); + DebuggerUtil.InMemoryFileSpecification imfs = new DebuggerUtil.InMemoryFileSpecification(code); + EnumSet<PostProcessStep> empty = EnumSet.noneOf(PostProcessStep.class); + IASNode exprAST = ASParser.parseFile(imfs, workspace, empty, null, false, false, new ArrayList<String>(), null, null, null); + + // Have to create a fake ScopedBlockNode so the expression can do things + // like resolve, which means it has to be able to find a scope. + // For parsing an expression in a file, one would hook up the expression + // AST to whatever the real scope was. + ScopedBlockNode scopedNode = new ScopedBlockNode(); + scopedNode.addChild((NodeBase)exprAST); + scopedNode.setScope(new ASFileScope(workspace, "fake")); + scopedNode.runPostProcess(EnumSet.of(PostProcessStep.CALCULATE_OFFSETS)); + + // return the first (and only child). This is essentially unwrapping the + // FileNode that was wrapped around the expression being parsed + return exprAST.getChild(0); + } + + public static class InMemoryFileSpecification implements IFileSpecification + { + public InMemoryFileSpecification(String s) + { + this.s = s; + } + + private String s; + + public String getPath() + { + return "flash.tools.debugger"; + } + + public Reader createReader() throws FileNotFoundException + { + return new StringReader(s); + } + + public long getLastModified() + { + return 0; + } + + public boolean isOpenDocument() + { + return false; + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/DebuggerValue.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerValue.java b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerValue.java new file mode 100644 index 0000000..cd647bc --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerValue.java @@ -0,0 +1,26 @@ +/* + * 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 flash.tools.debugger.expression; + +public class DebuggerValue { + public Object debuggerValue; + + public DebuggerValue(Object v) + { + debuggerValue = v; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/ECMA.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/ECMA.java b/debugger/src/main/java/flash/tools/debugger/expression/ECMA.java new file mode 100644 index 0000000..39c3308 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/ECMA.java @@ -0,0 +1,430 @@ +/* + * 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 flash.tools.debugger.expression; + +import flash.tools.debugger.Isolate; +import flash.tools.debugger.PlayerDebugException; +import flash.tools.debugger.Session; +import flash.tools.debugger.Value; +import flash.tools.debugger.VariableType; +import flash.tools.debugger.concrete.DValue; +import flash.tools.debugger.events.ExceptionFault; + +/** + * Implementations of some of the conversion functions defined by + * the ECMAScript spec ( http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf ). + * Please note, these conversion functions should not be considered to + * be 100% accurate; they handle all the cases the debugger's expression + * evaluator is likely to run into, but there are some edge cases that + * fall through the cracks. + * + * @author Mike Morearty + */ +public class ECMA +{ + /** Used by defaultValue() etc. */ + private enum PreferredType { NUMBER, STRING } + + /** + * ECMA 4.3.2 + */ + public static boolean isPrimitive(Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + Object o = v.getValueAsObject(); + return (o == Value.UNDEFINED || o == null || o instanceof Boolean + || o instanceof Double || o instanceof String); + } + + private static Value callFunction(Session session, Value v, String functionName, Value[] args, int isolateId) + { + v = safeValue(v, isolateId); + + try + { + return session.getWorkerSession(isolateId).callFunction(v, functionName, args); + } + catch (PlayerDebugException e) + { + throw new ExpressionEvaluatorException(e); + } + } + + /** + * Calls the valueOf() function of an object. + */ + private static Value callValueOf(Session session, Value v, int isolateId) + { + v = safeValue(v, isolateId); + return callFunction(session, v, "valueOf", new Value[0], isolateId); //$NON-NLS-1$ + } + + /** + * Do not confuse this with toString()! toString() represents the official + * ECMA definition of [[ToString]], as defined in ECMA section 9.8. This + * function, on the other hand, represents calling the toString() function + * of an object. + */ + private static Value callToString(Session session, Value v, int isolateId) + { + v = safeValue(v, isolateId); + return callFunction(session, v, "toString", new Value[0], isolateId); //$NON-NLS-1$ + } + + /** + * ECMA 8.6.2.6 + * + * @param v + * @param optionalPreferredType + * either NUMBER, STRING, or null. + */ + public static Value defaultValue(Session session, Value v, + PreferredType optionalPreferredType, + int isolateId) + { + v = safeValue(v, isolateId); + String typename = v.getTypeName(); + int at = typename.indexOf('@'); + if (at != -1) + typename = typename.substring(0, at); + + if (optionalPreferredType == null) + { + if (typename.equals("Date")) //$NON-NLS-1$ + optionalPreferredType = PreferredType.STRING; + else + optionalPreferredType = PreferredType.NUMBER; + } + + if (optionalPreferredType == PreferredType.NUMBER) + { + Value result = callValueOf(session, v, isolateId); + if (isPrimitive(result)) + return result; + result = callToString(session, v, isolateId); + if (isPrimitive(result)) + return result; + throw new RuntimeException(new PlayerFaultException(new ExceptionFault(ASTBuilder.getLocalizationManager().getLocalizedTextString("typeError"), false, null, isolateId))); //$NON-NLS-1$ + } + else + { + Value result = callToString(session, v, isolateId); + if (isPrimitive(result)) + return result; + result = callValueOf(session, v, isolateId); + if (isPrimitive(result)) + return result; + throw new RuntimeException(new PlayerFaultException(new ExceptionFault(ASTBuilder.getLocalizationManager().getLocalizedTextString("typeError"), false, null, isolateId))); //$NON-NLS-1$ + } + } + + /** + * ECMA 9.1 + * + * @param v + * @param optionalPreferredType + * either NUMBER_TYPE, STRING_TYPE, or null. + * @return + */ + public static Value toPrimitive(Session session, Value v, + PreferredType optionalPreferredType, int isolateId) + { + v = safeValue(v, isolateId); + switch (v.getType()) + { + case VariableType.UNDEFINED: + case VariableType.NULL: + case VariableType.BOOLEAN: + case VariableType.NUMBER: + case VariableType.STRING: + return v; + + default: + return defaultValue(session, v, optionalPreferredType, isolateId); + } + } + + /** ECMA 9.2 */ + public static boolean toBoolean(Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + switch (v.getType()) + { + case VariableType.UNDEFINED: + case VariableType.NULL: + return false; + case VariableType.BOOLEAN: + return ((Boolean) v.getValueAsObject()).booleanValue(); + case VariableType.NUMBER: + { + double d = ((Double) v.getValueAsObject()).doubleValue(); + if (d == 0 || Double.isNaN(d)) + { + return false; + } + else + { + return true; + } + } + case VariableType.STRING: + return ((String) v.getValueAsObject()).length() != 0; + default: + return true; + } + } + + /** ECMA 9.3 */ + public static double toNumber(Session session, Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + switch (v.getType()) + { + case VariableType.UNDEFINED: + return Double.NaN; + case VariableType.NULL: + return 0; + case VariableType.BOOLEAN: + return ((Boolean) v.getValueAsObject()).booleanValue() ? 1 : 0; + case VariableType.NUMBER: + return ((Double) v.getValueAsObject()).doubleValue(); + case VariableType.STRING: + { + String s = (String) v.getValueAsObject(); + if (s.length() == 0) + { + return 0; + } + else + { + try + { + return Double.parseDouble(s); + } + catch (NumberFormatException e) + { + return Double.NaN; + } + } + } + default: + return toNumber(session, toPrimitive(session, v, PreferredType.NUMBER, v.getIsolateId())); + } + } + + private static final double _2pow31 = Math.pow(2, 31); + private static final double _2pow32 = Math.pow(2, 32); + + /** ECMA 9.5 */ + public static int toInt32(Session session, Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + double d = toNumber(session, v); + if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY) + { + return 0; + } + else + { + double sign = Math.signum(d); + d = Math.floor(Math.abs(d)); + d %= _2pow32; + while (d >= _2pow31) + d -= _2pow32; + return (int) (sign*d); + } + } + + /** ECMA 9.6 */ + public static long toUint32(Session session, Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + long n = toInt32(session, v); + if (n < 0) + n = n + (long) 0x10000 * (long) 0x10000; + return n; + } + + /** ECMA 9.8 */ + public static String toString(Session session, Value v) + { + v = safeValue(v, Isolate.DEFAULT_ID); + switch (v.getType()) + { + case VariableType.UNDEFINED: + case VariableType.NULL: + case VariableType.BOOLEAN: + case VariableType.STRING: + return v.getValueAsString(); + case VariableType.NUMBER: + { + double d = ((Double) v.getValueAsObject()).doubleValue(); + if (d == (long) d) + { + return Long.toString((long) d); // avoid the ".0" on the end + } + else + { + return v.toString(); + } + } + default: + return toString(session, toPrimitive(session, v, PreferredType.STRING, v.getIsolateId())); + } + } + + /** ECMA 11.8.5. Returns true, false, or undefined. */ + public static Value lessThan(Session session, Value x, Value y) + { + x = safeValue(x, Isolate.DEFAULT_ID); + y = safeValue(y, Isolate.DEFAULT_ID); + Value px = toPrimitive(session, x, PreferredType.NUMBER, x.getIsolateId()); + Value py = toPrimitive(session, y, PreferredType.NUMBER, y.getIsolateId()); + if (px.getType() == VariableType.STRING + && py.getType() == VariableType.STRING) + { + String sx = px.getValueAsString(); + String sy = py.getValueAsString(); + return DValue.forPrimitive(new Boolean(sx.compareTo(sy) < 0), x.getIsolateId()); + } + else + { + double dx = toNumber(session, px); + double dy = toNumber(session, py); + if (Double.isNaN(dx) || Double.isNaN(dy)) + return DValue.forPrimitive(Value.UNDEFINED, x.getIsolateId()); + return DValue.forPrimitive(new Boolean(dx < dy), x.getIsolateId()); + } + } + + /** ECMA 11.9.3 */ + public static boolean equals(Session session, Value xv, Value yv) + { + xv = safeValue(xv, Isolate.DEFAULT_ID); + yv = safeValue(yv, Isolate.DEFAULT_ID); + + Object x = xv.getValueAsObject(); + Object y = yv.getValueAsObject(); + + if (xv.getType() == yv.getType()) + { + if (x == Value.UNDEFINED) + return true; + if (x == null) + return true; + if (x instanceof Double) + { + double dx = ((Double) x).doubleValue(); + double dy = ((Double) y).doubleValue(); + return dx == dy; + } + if (x instanceof String || x instanceof Boolean) + return x.equals(y); + + // see if they are the same object + if (xv.getId() != -1 || yv.getId() != -1) + return xv.getId() == yv.getId(); + return false; + } + else + { + if (x == null && y == Value.UNDEFINED) + return true; + if (x == Value.UNDEFINED && y == null) + return true; + if (x instanceof Double && y instanceof String) + { + double dx = ((Double) x).doubleValue(); + double dy = toNumber(session, yv); + return dx == dy; + } + if (x instanceof String && y instanceof Double) + { + double dx = toNumber(session, xv); + double dy = ((Double) y).doubleValue(); + return dx == dy; + } + if (x instanceof Boolean) + return equals(session, DValue.forPrimitive(new Double(toNumber(session, xv)), xv.getIsolateId()), yv); + if (y instanceof Boolean) + return equals(session, xv, DValue.forPrimitive(new Double(toNumber(session, yv)), xv.getIsolateId())); + if ((x instanceof String || x instanceof Double) && yv.getType() == VariableType.OBJECT) + { + return equals(session, xv, toPrimitive(session, yv, null, yv.getIsolateId())); + } + if (xv.getType() == VariableType.OBJECT && (y instanceof String || y instanceof Double)) + { + return equals(session, toPrimitive(session, xv, null, xv.getIsolateId()), yv); + } + return false; + } + } + + /** ECMA 11.9.6 */ + public static boolean strictEquals(Value xv, Value yv) + { + xv = safeValue(xv, Isolate.DEFAULT_ID); + yv = safeValue(yv, Isolate.DEFAULT_ID); + + Object x = xv.getValueAsObject(); + Object y = yv.getValueAsObject(); + + if (xv.getType() == yv.getType()) + { + if (x == Value.UNDEFINED) + return true; + if (x == null) + return true; + if (x instanceof Double) + { + double dx = ((Double) x).doubleValue(); + double dy = ((Double) y).doubleValue(); + return dx == dy; + } + if (x instanceof String || x instanceof Boolean) + return x.equals(y); + + // see if they are the same object + if (xv.getId() != -1 || yv.getId() != -1) + return xv.getId() == yv.getId(); + return false; + } + else + { + return false; + } + } + + /** + * Returns a "safe" (non-null) form of the specified Value -- that is, if + * the specified Value is null, returns a non-null Value that *represents* + * null. + * + * @param v + * any Value, possibly null + * @return a non-null Value + */ + public static Value safeValue(Value v, int isolateId) + { + if (v == null) + { + v = DValue.forPrimitive(null, isolateId); + assert v != null; + } + return v; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/ExpressionEvaluatorException.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/ExpressionEvaluatorException.java b/debugger/src/main/java/flash/tools/debugger/expression/ExpressionEvaluatorException.java new file mode 100644 index 0000000..d10485d --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/ExpressionEvaluatorException.java @@ -0,0 +1,39 @@ +/* + * 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 flash.tools.debugger.expression; + +/** + * An exception raised while evaluating an expression. This is a bit + * of a hack -- we need this to extend <code>RuntimeException</code> + * because the functions in the <code>Evaluator</code> interface don't + * throw anything, but our <code>DebuggerEvaluator</code> has many + * places where it needs to bail out. + * + * @author Mike Morearty + */ +public class ExpressionEvaluatorException extends RuntimeException { + private static final long serialVersionUID = -7005526599250035578L; + + public ExpressionEvaluatorException(String message) { + super(message); + } + + public ExpressionEvaluatorException(Throwable cause) { + super(cause); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/FoldedExpressionNode.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/FoldedExpressionNode.java b/debugger/src/main/java/flash/tools/debugger/expression/FoldedExpressionNode.java new file mode 100644 index 0000000..e2fbac8 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/FoldedExpressionNode.java @@ -0,0 +1,252 @@ +/* + * 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 flash.tools.debugger.expression; + +import org.apache.flex.compiler.filespecs.IFileSpecification; +import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IScopedNode; + +/** + * @author ggv + * + */ +public class FoldedExpressionNode extends ExpressionNodeBase implements + IExpressionNode { + + private final IASNode rootNode; + + /** + * + */ + public FoldedExpressionNode(IASNode rootNode) { + this.rootNode = rootNode; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getStart() + */ + @Override + public int getStart() { + return getUnderLyingNode().getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getEnd() + */ + @Override + public int getEnd() { + return getUnderLyingNode().getEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getLine() + */ + @Override + public int getLine() { + return getUnderLyingNode().getLine(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getColumn() + */ + @Override + public int getColumn() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getAbsoluteStart() + */ + @Override + public int getAbsoluteStart() { + return getUnderLyingNode().getAbsoluteStart(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.common.ISourceLocation#getAbsoluteEnd() + */ + @Override + public int getAbsoluteEnd() { + return getUnderLyingNode().getAbsoluteEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getNodeID() + */ + @Override + public ASTNodeID getNodeID() { + return ASTNodeID.FoldedExpressionID; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#contains(int) + */ + @Override + public boolean contains(int offset) { + return getUnderLyingNode().contains(offset); + } + + /* + * (non-Javadoc) + * + * @see + * com.adobe.flash.compiler.tree.as.IASNode#getAncestorOfType(java.lang. + * Class) + */ + @Override + public IASNode getAncestorOfType(Class<? extends IASNode> nodeType) { + return getUnderLyingNode().getAncestorOfType(nodeType); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getChild(int) + */ + @Override + public IASNode getChild(int i) { + return null; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getChildCount() + */ + @Override + public int getChildCount() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getContainingNode(int) + */ + @Override + public IASNode getContainingNode(int offset) { + return getUnderLyingNode().getContainingNode(offset); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getContainingScope() + */ + @Override + public IScopedNode getContainingScope() { + return getUnderLyingNode().getContainingScope(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getPackageName() + */ + @Override + public String getPackageName() { + return getUnderLyingNode().getPackageName(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getParent() + */ + @Override + public IASNode getParent() { + return getUnderLyingNode().getParent(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getFileSpecification() + */ + @Override + public IFileSpecification getFileSpecification() { + return getUnderLyingNode().getFileSpecification(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getSpanningStart() + */ + @Override + public int getSpanningStart() { + return getUnderLyingNode().getSpanningStart(); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#getSucceedingNode(int) + */ + @Override + public IASNode getSucceedingNode(int offset) { + return getUnderLyingNode().getSucceedingNode(offset); + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.tree.as.IASNode#isTerminal() + */ + @Override + public boolean isTerminal() { + return true; + } + + /** + * @return the rootNode + */ + public IASNode getUnderLyingNode() { + return rootNode; + } + + /* + * (non-Javadoc) + * + * @see com.adobe.flash.compiler.internal.tree.as.ExpressionNodeBase#copy() + */ + @Override + protected ExpressionNodeBase copy() { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/IASTBuilder.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/IASTBuilder.java b/debugger/src/main/java/flash/tools/debugger/expression/IASTBuilder.java new file mode 100644 index 0000000..ba4bb72 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/IASTBuilder.java @@ -0,0 +1,35 @@ +/* + * 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 flash.tools.debugger.expression; + +import java.io.IOException; +import java.io.Reader; +import java.text.ParseException; + +public interface IASTBuilder +{ + /** + * A parser that should do a fairly good job at + * parsing a general expression string. + * + * Exceptions: + * ParseException - a general parsing error occurred. + * + */ + public ValueExp parse(Reader in) throws IOException, ParseException; +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/IASTFolder.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/IASTFolder.java b/debugger/src/main/java/flash/tools/debugger/expression/IASTFolder.java new file mode 100644 index 0000000..30ac679 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/IASTFolder.java @@ -0,0 +1,43 @@ +/* + * 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 flash.tools.debugger.expression; + +import org.apache.flex.compiler.tree.as.IASNode; + +/** + * @author ggv + * + */ +public interface IASTFolder { + + /** + * This will perform folding of certain nodes, based on implementation + * + * @param rootNode + * @return + */ + public IASNode fold(IASNode rootNode); + + /** + * Unfolds onlevel, if required will fold the children + * + * @param rootNode + * @return + */ + public IASNode unfoldOneLevel(FoldedExpressionNode rootNode); +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/IExpressionEvaluator.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/IExpressionEvaluator.java b/debugger/src/main/java/flash/tools/debugger/expression/IExpressionEvaluator.java new file mode 100644 index 0000000..c1ffe03 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/IExpressionEvaluator.java @@ -0,0 +1,30 @@ +/* + * 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 flash.tools.debugger.expression; + +import org.apache.flex.compiler.tree.as.IASNode; + +/** + * @author ggv + * + */ +public interface IExpressionEvaluator { + + public abstract DebuggerValue evaluate(Context context, IASNode node) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/LogicalOperatorsFolder.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/LogicalOperatorsFolder.java b/debugger/src/main/java/flash/tools/debugger/expression/LogicalOperatorsFolder.java new file mode 100644 index 0000000..84709bd --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/LogicalOperatorsFolder.java @@ -0,0 +1,102 @@ +/* + * 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 flash.tools.debugger.expression; + +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorLogicalAndAssignmentNode; +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorLogicalAndNode; +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorLogicalOrAssignmentNode; +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorLogicalOrNode; +import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; + +/** + * The logical operator's right hand operands are folded into + * FoldedExperessionNode, so that they are not evaluated by the burm. + * + * This is required for shortcircuit evaluation + * + * @author ggv + * + */ +public class LogicalOperatorsFolder implements IASTFolder { + + /* + * (non-Javadoc) + * + * @see + * flash.tools.debugger.expression.IASTFolder#fold(com.adobe.flash.compiler + * .tree.as.IASNode) + */ + @Override + public IASNode fold(IASNode rootNode) { + foldLazyRHSOperandsForLogicalOperators(rootNode); + return rootNode; + } + + /** + * @param node + */ + private void foldLazyRHSOperandsForLogicalOperators(IASNode node) { + + if (node instanceof BinaryOperatorLogicalAndNode + || node instanceof BinaryOperatorLogicalAndAssignmentNode) { + + BinaryOperatorLogicalAndNode opNode = ((BinaryOperatorLogicalAndNode) node); + opNode.setRightOperandNode(fold(opNode.getRightOperandNode())); + foldLazyRHSOperandsForLogicalOperators(opNode.getLeftOperandNode()); + + } else if (node instanceof BinaryOperatorLogicalOrNode + || node instanceof BinaryOperatorLogicalOrAssignmentNode) { + + BinaryOperatorLogicalOrNode opNode = ((BinaryOperatorLogicalOrNode) node); + opNode.setRightOperandNode(fold(opNode.getRightOperandNode())); + foldLazyRHSOperandsForLogicalOperators(opNode.getLeftOperandNode()); + + } else { + int chCount = node.getChildCount(); + for (int i = 0; i < chCount; i++) { + IASNode childNode = node.getChild(i); + foldLazyRHSOperandsForLogicalOperators(childNode); + } + } + } + + /** + * @param rightOperandNode + * @return + */ + private ExpressionNodeBase fold(IExpressionNode rightOperandNode) { + return new FoldedExpressionNode(rightOperandNode); + } + + /* + * (non-Javadoc) + * + * @see + * flash.tools.debugger.expression.IASTFolder#unfoldOneLevel(flash.tools + * .debugger.expression.FoldedExpressionNode) + */ + @Override + public IASNode unfoldOneLevel(FoldedExpressionNode foldedExpressionNode) { + IASNode node = foldedExpressionNode.getUnderLyingNode(); + fold(node); + return node; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/NoSuchVariableException.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/NoSuchVariableException.java b/debugger/src/main/java/flash/tools/debugger/expression/NoSuchVariableException.java new file mode 100644 index 0000000..05e69ca --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/NoSuchVariableException.java @@ -0,0 +1,40 @@ +/* + * 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 flash.tools.debugger.expression; + +import java.util.HashMap; +import java.util.Map; + +/** + * Thrown when a variable name cannot be resolved in the current scope + */ +public class NoSuchVariableException extends Exception +{ + private static final long serialVersionUID = -400396588945206074L; + + public NoSuchVariableException(String s) { super(s); } + public NoSuchVariableException(Object o) { super(o.toString()); } + + @Override + public String getLocalizedMessage() + { + Map<String, String> args = new HashMap<String, String>(); + args.put("arg2", getMessage() ); //$NON-NLS-1$ + return ASTBuilder.getLocalizationManager().getLocalizedTextString("noSuchVariable", args); //$NON-NLS-1$ + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/PlayerFaultException.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/PlayerFaultException.java b/debugger/src/main/java/flash/tools/debugger/expression/PlayerFaultException.java new file mode 100644 index 0000000..5cec3a1 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/PlayerFaultException.java @@ -0,0 +1,48 @@ +/* + * 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 flash.tools.debugger.expression; + +import flash.tools.debugger.events.FaultEvent; + +/** + * Thrown when the player generates a fault. For example, if + * an attempt to assign a value to a variable results in the player + * generating a fault because that value has no setter, or because + * the setter throws an exception for any other reason, then this + * exception will be generated. + */ +public class PlayerFaultException extends Exception { + private static final long serialVersionUID = 7754580337597815207L; + private FaultEvent m_event; + + public PlayerFaultException(FaultEvent event) + { + m_event = event; + } + + public FaultEvent getFaultEvent() + { + return m_event; + } + + @Override + public String getMessage() + { + return m_event.information; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/expression/ValueExp.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/expression/ValueExp.java b/debugger/src/main/java/flash/tools/debugger/expression/ValueExp.java new file mode 100644 index 0000000..988bf3f --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/expression/ValueExp.java @@ -0,0 +1,79 @@ +/* + * 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 flash.tools.debugger.expression; + +import flash.tools.debugger.PlayerDebugException; + +/** + * All objects in the abstract syntax tree must provide + * this interface. It allows the tree to resolve down + * to a single value. + * + * The tree nodes are terminal and non-terminal. Terminals + * are constants or variables, non-terminals are everything + * else. Each non-terminal is an operation which takes + * its left hand child and right hand child as input + * and produces a result. Performing evaluate() at the root of + * the tree results in a single Object being returned. + */ +public interface ValueExp +{ + /** + * Evaluates the expression. For example, if this node is a "+" node, with a + * 2 left child and a 2 right child, then the return value will be a long + * (that is, a java.lang.Long) with the value 4. + * + * @param context + * the context in which the expression should be evaluated; + * primarily used for looking up variables. For example, when + * evaluating the expression "myvar", the context looks at + * locals, members of "this", etc.; when evaluating "myfield" + * node of the expression "myvar.myfield", the context looks at + * members of the variable "myvar". + * @return the value of the expression. This might be a literal Java + * constant (e.g. a Boolean, Integer, String, etc.); or it might be + * an UndefinedExp, representing the value 'undefined'; or it might + * be a Value; or it might be a Variable. + * + * @see Context#lookup(Object) + */ + public Object evaluate(Context context) throws NumberFormatException, NoSuchVariableException, + PlayerFaultException, PlayerDebugException; + + /** + * Returns whether the expression contains any assignments (= or ++ or --). + * Note, there are other kinds of expressions that can have side effects as + * well, such as function calls, or even simple expressions like "foo" if + * foo is a getter. + */ + public boolean containsAssignment(); + + /** + * Returns whether <code>evaluate()</code> will return an object that + * explicitly shows the values of all members of the expression. For + * example, in fdb, if the user writes "print myvar", then isLookupMembers + * will be false, and the debugger will show just the value of + * <code>myvar</code>, but not the values of its members; but if the user + * writes "print myvar." (with a "." at the end), then the debugger will + * show the values of all of the members of <code>myvar</code>. + * + * @see ASTBuilder#ASTBuilder(boolean) + * @see ASTBuilder#isIndirectionOperatorAllowed() + */ + public boolean isLookupMembers(); +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeASTBuilder.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeASTBuilder.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeASTBuilder.java new file mode 100644 index 0000000..7c3f15d --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeASTBuilder.java @@ -0,0 +1,64 @@ +/* + * 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 flash.tools.debugger.threadsafe; + +import java.io.IOException; +import java.io.Reader; +import java.text.ParseException; + +import flash.tools.debugger.expression.IASTBuilder; +import flash.tools.debugger.expression.ValueExp; + +/** + * @author Mike Morearty + */ +public class ThreadSafeASTBuilder extends ThreadSafeDebuggerObject implements IASTBuilder +{ + private final IASTBuilder m_astBuilder; + + /** + * @param syncObj + */ + public ThreadSafeASTBuilder(Object syncObj, IASTBuilder astBuilder) + { + super(syncObj); + m_astBuilder = astBuilder; + } + + /** + * Wraps an IASTBuilder inside a ThreadSafeASTBuilder. If the passed-in + * IASTBuilder is null, then this function returns null. + */ + public static ThreadSafeASTBuilder wrap(Object syncObj, IASTBuilder astBuilder) { + if (astBuilder != null) + return new ThreadSafeASTBuilder(syncObj, astBuilder); + else + return null; + } + + /* + * @see flash.tools.debugger.expression.IASTBuilder#parse(java.io.Reader) + */ + public ValueExp parse(Reader in) throws IOException, ParseException + { + synchronized (getSyncObject()) { + return ThreadSafeValueExp.wrap(getSyncObject(), m_astBuilder.parse(in)); + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeBootstrap.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeBootstrap.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeBootstrap.java new file mode 100644 index 0000000..37d016d --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeBootstrap.java @@ -0,0 +1,39 @@ +/* + * 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 flash.tools.debugger.threadsafe; + +import flash.tools.debugger.Bootstrap; + +/** + * Thread-safe wrapper for flash.tools.debugger.Bootstrap + * @author Mike Morearty + */ +public class ThreadSafeBootstrap { + + private static ThreadSafeSessionManager fMgr; + + private ThreadSafeBootstrap() {} // prevent instantiation + + public static synchronized ThreadSafeSessionManager sessionManager() + { + if (fMgr == null) { + fMgr = ThreadSafeSessionManager.wrap(Bootstrap.sessionManager()); + } + return fMgr; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeDebuggerObject.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeDebuggerObject.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeDebuggerObject.java new file mode 100644 index 0000000..02511ff --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeDebuggerObject.java @@ -0,0 +1,36 @@ +/* + * 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 flash.tools.debugger.threadsafe; + +/** + * Intended to be subclassed. + * + * @author Mike Morearty + */ +class ThreadSafeDebuggerObject { + + private Object fSyncObj; + + protected ThreadSafeDebuggerObject(Object syncObj) { + fSyncObj = syncObj; + } + + public final Object getSyncObject() { + return fSyncObj; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeFrame.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeFrame.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeFrame.java new file mode 100644 index 0000000..c39b2df --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeFrame.java @@ -0,0 +1,140 @@ +/* + * 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 flash.tools.debugger.threadsafe; + +import flash.tools.debugger.Frame; +import flash.tools.debugger.Location; +import flash.tools.debugger.NoResponseException; +import flash.tools.debugger.NotConnectedException; +import flash.tools.debugger.NotSuspendedException; +import flash.tools.debugger.Session; +import flash.tools.debugger.Variable; + +/** + * Thread-safe wrapper for flash.tools.debugger.Frame + * @author Mike Morearty + */ +public class ThreadSafeFrame extends ThreadSafeDebuggerObject implements Frame { + + private Frame fFrame; + + private ThreadSafeFrame(Object syncObj, Frame frame) { + super(syncObj); + fFrame = frame; + } + + /** + * Wraps a Frame inside a ThreadSafeFrame. If the passed-in Frame + * is null, then this function returns null. + */ + public static ThreadSafeFrame wrap(Object syncObj, Frame frame) { + if (frame != null) + return new ThreadSafeFrame(syncObj, frame); + else + return null; + } + + /** + * Wraps an array of Frames inside an array of ThreadSafeFrames. + */ + public static ThreadSafeFrame[] wrapArray(Object syncObj, Frame[] frames) { + ThreadSafeFrame[] threadSafeFrames = new ThreadSafeFrame[frames.length]; + for (int i=0; i<frames.length; ++i) { + threadSafeFrames[i] = wrap(syncObj, frames[i]); + } + return threadSafeFrames; + } + + public static Object getSyncObject(Frame f) { + return ((ThreadSafeFrame)f).getSyncObject(); + } + + @Override + public int hashCode() { + synchronized (getSyncObject()) { + return fFrame.hashCode(); + } + } + + @Override + public boolean equals(Object other) { + synchronized (getSyncObject()) { + if (other == null) + return false; + if (other instanceof ThreadSafeFrame) { + return (fFrame.equals(((ThreadSafeFrame)other).fFrame)); + } + if (other instanceof Frame) { + return (fFrame.equals(other)); + } + return false; + } + } + + @Override + public String toString() { + synchronized (getSyncObject()) { + return fFrame.toString(); + } + } + + // -- beginning of delegate functions -- + + public Variable[] getArguments(Session s) throws NoResponseException, NotSuspendedException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeVariable.wrapArray(getSyncObject(), fFrame.getArguments(ThreadSafeSession.getRaw(s))); + } + } + + public String getCallSignature() { + synchronized (getSyncObject()) { + return fFrame.getCallSignature(); + } + } + + public Variable[] getLocals(Session s) throws NoResponseException, NotSuspendedException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeVariable.wrapArray(getSyncObject(), fFrame.getLocals(ThreadSafeSession.getRaw(s))); + } + } + + public Location getLocation() { + synchronized (getSyncObject()) { + return ThreadSafeLocation.wrap(getSyncObject(), fFrame.getLocation()); + } + } + + public Variable getThis(Session s) throws NoResponseException, NotSuspendedException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeVariable.wrap(getSyncObject(), fFrame.getThis(ThreadSafeSession.getRaw(s))); + } + } + + public Variable[] getScopeChain(Session s) throws NoResponseException, NotSuspendedException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeVariable.wrapArray(getSyncObject(), fFrame.getScopeChain(ThreadSafeSession.getRaw(s))); + } + } + + @Override + public int getIsolateId() { + synchronized (getSyncObject()) { + return fFrame.getIsolateId(); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolate.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolate.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolate.java new file mode 100644 index 0000000..0cc5619 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolate.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 flash.tools.debugger.threadsafe; + +import flash.tools.debugger.Isolate; + +/** + * Thread-safe wrapper for flash.tools.debugger.Isolate + * @author Anirudh Sasikumar + */ +public class ThreadSafeIsolate extends ThreadSafeDebuggerObject implements Isolate { + + private Isolate fIsolate; + + private ThreadSafeIsolate(Object syncObj, Isolate isolate) { + super(syncObj); + fIsolate = isolate; + } + + /** + * Wraps a Watch inside a ThreadSafeWatch. If the passed-in Watch + * is null, then this function returns null. + */ + public static ThreadSafeIsolate wrap(Object syncObj, Isolate isolate) { + if (isolate != null) + return new ThreadSafeIsolate(syncObj, isolate); + else + return null; + } + + /** + * Wraps an array of Locations inside an array of ThreadSafeLocations. + */ + public static ThreadSafeIsolate[] wrapArray(Object syncObj, Isolate[] isolates) { + ThreadSafeIsolate[] threadSafeIsolates = new ThreadSafeIsolate[isolates.length]; + for (int i=0; i<isolates.length; ++i) { + threadSafeIsolates[i] = wrap(syncObj, isolates[i]); + } + return threadSafeIsolates; + } + + public int getId() { + synchronized (getSyncObject()) { + return fIsolate.getId(); + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolateSession.java ---------------------------------------------------------------------- diff --git a/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolateSession.java b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolateSession.java new file mode 100644 index 0000000..57f0820 --- /dev/null +++ b/debugger/src/main/java/flash/tools/debugger/threadsafe/ThreadSafeIsolateSession.java @@ -0,0 +1,285 @@ +/* + * 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 flash.tools.debugger.threadsafe; + +import flash.tools.debugger.Frame; +import flash.tools.debugger.IsolateSession; +import flash.tools.debugger.Location; +import flash.tools.debugger.NoResponseException; +import flash.tools.debugger.NotConnectedException; +import flash.tools.debugger.NotSupportedException; +import flash.tools.debugger.NotSuspendedException; +import flash.tools.debugger.PlayerDebugException; +import flash.tools.debugger.SuspendedException; +import flash.tools.debugger.SwfInfo; +import flash.tools.debugger.Value; +import flash.tools.debugger.Variable; +import flash.tools.debugger.VersionException; +import flash.tools.debugger.Watch; +import flash.tools.debugger.expression.PlayerFaultException; + +/** + * Thread-safe wrapper for flash.tools.debugger.IsolateSession + * @author Anirudh Sasikumar + */ +public class ThreadSafeIsolateSession extends ThreadSafeDebuggerObject + implements IsolateSession { + + private IsolateSession fSession; + + private ThreadSafeIsolateSession(Object syncObj, IsolateSession session) { + super(syncObj); + fSession = session; + } + + /** + * Wraps a Value inside a ThreadSafeValue. If the passed-in Value + * is null, then this function returns null. + */ + public static ThreadSafeIsolateSession wrap(Object syncObj, IsolateSession session) { + if (session != null) + return new ThreadSafeIsolateSession(syncObj, session); + else + return null; + } + + @Override + public void resume() throws NotSuspendedException, NotConnectedException, + NoResponseException { + synchronized (getSyncObject()) { + fSession.resume(); + } + } + + @Override + public void suspend() throws SuspendedException, NotConnectedException, + NoResponseException { + synchronized (getSyncObject()) { + fSession.suspend(); + } + + } + + @Override + public boolean isSuspended() throws NotConnectedException { + synchronized (getSyncObject()) { + return fSession.isSuspended(); + } + } + + @Override + public int suspendReason() throws NotConnectedException { + synchronized (getSyncObject()) { + return fSession.suspendReason(); + } + } + + public void stepOver() throws NotSuspendedException, NoResponseException, + NotConnectedException { + synchronized (getSyncObject()) { + fSession.stepOver(); + } + } + + public void stepContinue() throws NotSuspendedException, + NoResponseException, NotConnectedException { + synchronized (getSyncObject()) { + fSession.stepContinue(); + } + } + + public void stepInto() throws NotSuspendedException, NoResponseException, + NotConnectedException { + synchronized (getSyncObject()) { + fSession.stepInto(); + } + } + + public void stepOut() throws NotSuspendedException, NoResponseException, + NotConnectedException { + synchronized (getSyncObject()) { + fSession.stepOut(); + } + } + + @Override + public Frame[] getFrames() throws NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeFrame.wrapArray(getSyncObject(), fSession.getFrames()); + } + } + + @Override + public boolean evalIs(Value value, Value type) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return fSession.evalIs(value, type); + } + } + + @Override + public boolean evalIs(Value value, String type) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return fSession.evalIs(value, type); + } + } + + @Override + public boolean evalInstanceof(Value value, Value type) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return fSession.evalInstanceof(value, type); + } + } + + @Override + public boolean evalInstanceof(Value value, String type) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return fSession.evalInstanceof(value, type); + } + } + + @Override + public boolean evalIn(Value property, Value object) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return fSession.evalIn(property, object); + } + } + + @Override + public Value evalAs(Value value, Value type) + throws PlayerDebugException, PlayerFaultException { + synchronized (getSyncObject()) { + return ThreadSafeValue.wrap(getSyncObject(), fSession.evalAs(value, type)); + } + } + + @Override + public Value callConstructor(String classname, Value[] args) + throws PlayerDebugException { + synchronized (getSyncObject()) { + return ThreadSafeValue.wrap(getSyncObject(), fSession.callConstructor(classname, args)); + } + } + + @Override + public Watch[] getWatchList() + throws NoResponseException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeWatch.wrapArray(getSyncObject(), fSession.getWatchList()); + } + } + + /** @deprecated */ + public Variable[] getVariableList() throws NotSuspendedException, + NoResponseException, NotConnectedException, VersionException { + synchronized (getSyncObject()) { + return ThreadSafeVariable.wrapArray(getSyncObject(), fSession.getVariableList()); + } + } + + public Value callFunction(Value thisObject, String functionName, Value[] args) + throws PlayerDebugException { + synchronized (getSyncObject()) { + return ThreadSafeValue.wrap(getSyncObject(), fSession.callFunction(thisObject, functionName, args)); + } + } + + public Value getGlobal(String name) throws NotSuspendedException, NoResponseException, NotConnectedException + { + synchronized (getSyncObject()) + { + return ThreadSafeValue.wrap(getSyncObject(), fSession.getGlobal(name)); + } + } + + public SwfInfo[] getSwfs() throws NoResponseException { + synchronized (getSyncObject()) { + return ThreadSafeSwfInfo.wrapArray(getSyncObject(), fSession.getSwfs()); + } + } + + public Value getValue(long valueId) throws NotSuspendedException, + NoResponseException, NotConnectedException + { + synchronized (getSyncObject()) { + return ThreadSafeValue.wrap(getSyncObject(), fSession.getValue(valueId)); + } + } + + public Location setBreakpoint(int fileId, int lineNum) + throws NoResponseException, NotConnectedException { + synchronized (getSyncObject()) { + return ThreadSafeLocation.wrap(getSyncObject(), fSession.setBreakpoint(fileId, lineNum)); + } + } + + @Override + public boolean setExceptionBreakpoint(String exceptionClass) + throws NoResponseException, NotConnectedException { + synchronized (getSyncObject()) { + return fSession.setExceptionBreakpoint(exceptionClass); + } + } + + @Override + public boolean clearExceptionBreakpoint(String exceptionClass) + throws NoResponseException, NotConnectedException { + synchronized (getSyncObject()) { + return fSession.clearExceptionBreakpoint(exceptionClass); + } + } + + @Override + public void breakOnCaughtExceptions(boolean b) + throws NotSupportedException, NoResponseException { + synchronized (getSyncObject()) { + fSession.breakOnCaughtExceptions(b); + } + } + + @Override + public boolean supportsWatchpoints() { + synchronized (getSyncObject()) { + return fSession.supportsWatchpoints(); + } + } + + @Override + public boolean playerCanBreakOnAllExceptions() { + synchronized (getSyncObject()) { + return fSession.playerCanBreakOnAllExceptions(); + } + } + + @Override + public boolean supportsWideLineNumbers() { + synchronized (getSyncObject()) { + return fSession.supportsWideLineNumbers(); + } + } + + @Override + public boolean playerCanCallFunctions() { + synchronized (getSyncObject()) { + return fSession.playerCanCallFunctions(); + } + } +}
