blob: 611c5784c8314684754e1d04802c977611d8eaea [file] [log] [blame]
/*
* 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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import com.adobe.flash.abc3.ABCConstants;
import com.adobe.flash.compiler.constants.IASLanguageConstants;
import com.adobe.flash.compiler.definitions.IDefinition;
import com.adobe.flash.compiler.definitions.ITypeDefinition;
import com.adobe.flash.compiler.internal.definitions.NamespaceDefinition;
import com.adobe.flash.compiler.internal.semantics.AS3SemanticUtils;
import com.adobe.flash.compiler.internal.tree.as.IdentifierNode;
import com.adobe.flash.compiler.internal.tree.as.MemberAccessExpressionNode;
import com.adobe.flash.compiler.internal.tree.as.NumericLiteralNode;
import com.adobe.flash.compiler.internal.tree.as.RegExpLiteralNode;
import com.adobe.flash.compiler.projects.ICompilerProject;
import com.adobe.flash.compiler.tree.ASTNodeID;
import com.adobe.flash.compiler.tree.INumericValue;
import com.adobe.flash.compiler.tree.as.IASNode;
import com.adobe.flash.compiler.tree.as.IExpressionNode;
import com.adobe.flash.compiler.tree.as.IIdentifierNode;
import flash.tools.debugger.IsolateSession;
import flash.tools.debugger.PlayerDebugException;
import flash.tools.debugger.Session;
import flash.tools.debugger.Variable;
import flash.tools.debugger.VariableType;
import flash.tools.debugger.concrete.DValue;
/**
* Reducer for the debugger - equivalent to the old DebuggerEvaluator
*/
public class AS3DebuggerReducer {
private final ContextStack contextStack;
private final ICompilerProject project;
public static class ContextStack {
private final List<Context> ctxStckInternal;
public ContextStack(Context context) {
ctxStckInternal = new ArrayList<Context>();
pushScope(context);
}
public Context scope(int i) {
return ctxStckInternal.get(i);
}
public void pushScope(Context scope) {
ctxStckInternal.add(scope);
}
public void popScope() {
assert (!ctxStckInternal.isEmpty());
ctxStckInternal.remove(ctxStckInternal.size() - 1);
}
public Context scope() {
return ctxStckInternal.get(ctxStckInternal.size() - 1);
}
}
public AS3DebuggerReducer(Context context, ICompilerProject project) {
super();
this.contextStack = new ContextStack(context);
this.project = project;
}
static final int ERROR_TRAP = 268435456;
private Object callFunction(Context cx, boolean isConstructor,
Object function, Object[] args) throws PlayerDebugException {
Session session = cx.getSession();
flash.tools.debugger.Value thisObject = cx.toValue();
if (thisObject == null)
thisObject = DValue.forPrimitive(null, cx.getIsolateId());
flash.tools.debugger.Value[] valueArgs = new flash.tools.debugger.Value[args.length];
for (int i = 0; i < args.length; ++i) {
/**
* context.toValue() may return null while
* PlayerSession::buildCallFunctionMessage expects the Value to be a
* value that depicts null. For example,
* xmlVar.childNode[nonexistentornullvar] will run into this case.
* (Came to notice via bug FB-25660)
*/
flash.tools.debugger.Value tempValue = cx.toValue(args[i]);
if (tempValue == null) {
tempValue = DValue.forPrimitive(null, cx.getIsolateId());
}
valueArgs[i] = tempValue;
}
String functionName;
if (function instanceof Variable) {
// Sometimes, the function will show up as a Variable. This happens,
// for example, if the user wrote "MyClass.myFunction = function() {
// ... }";
// String.fromCharCode(), for example, is defined that way.
functionName = ((Variable) function).getQualifiedName();
} else {
functionName = function.toString();
}
IsolateSession workerSession = session.getWorkerSession(cx
.getIsolateId());
if (isConstructor) {
return workerSession.callConstructor(functionName, valueArgs);
} else {
return workerSession.callFunction(thisObject, functionName,
valueArgs);
}
}
Object compoundBinaryAssignmentBracketExpr(IASNode iNode, Object stem,
Object index, Object r, int opcode) {
Object leftVariable = reduce_arrayIndexExpr(iNode, stem, false, index);
DebuggerValue operationValue = (DebuggerValue) binaryOp(iNode,
leftVariable, r, opcode);
return reduce_assignToBracketExpr_to_expression(iNode, stem, index,
operationValue, false);
}
Object compoundBinaryAssignmentMemberExpr(IASNode iNode, Object stem,
Object member, Object r, int opcode) {
Object leftVariable = reduce_memberAccessExpr(iNode, stem, member, -1);
DebuggerValue operationValue = (DebuggerValue) binaryOp(iNode,
leftVariable, r, opcode);
return reduce_assignToMemberExpr_to_expression(iNode, stem, member,
operationValue);
}
Object compoundBinaryAssignmentNameExpr(IASNode iNode, Object l, Object r,
int opcode) {
Object leftVariable = transform_name_to_expression(iNode, l);
DebuggerValue operationValue = (DebuggerValue) binaryOp(iNode,
leftVariable, r, opcode);
return reduce_assignToNameExpr_to_expression(iNode, l, operationValue);
}
/**
* Generate a binary operator.
*
* @param l
* - the left-hand operand.
* @param r
* - the right-hand operand.
* @param opcode
* - the operator's opcode.
* @return the combined instruction sequence with the operator appended.
*/
Object binaryOp(IASNode iNode, Object l, Object r, int opcode) {
// REFER : ASC : public Value evaluate(macromedia.asc.util.Context cx,
// BinaryExpressionNode node)
switch (opcode) {
case ABCConstants.OP_add:
break;
}
DebuggerValue lhs = (DebuggerValue) l;
DebuggerValue rhs = (DebuggerValue) r;
Context eeContext = contextStack.scope();
Session session = eeContext.getSession();
switch (opcode) {
case ABCConstants.OP_multiply: {
// ECMA 11.5
double d1 = ECMA.toNumber(session,
eeContext.toValue(lhs.debuggerValue));
double d2 = ECMA.toNumber(session,
eeContext.toValue(rhs.debuggerValue));
return new DebuggerValue(new Double(d1 * d2));
}
case ABCConstants.OP_divide: {
// ECMA 11.5
double d1 = ECMA.toNumber(session,
eeContext.toValue(lhs.debuggerValue));
double d2 = ECMA.toNumber(session,
eeContext.toValue(rhs.debuggerValue));
return new DebuggerValue(new Double(d1 / d2));
}
case ABCConstants.OP_modulo: {
// ECMA 11.5
double d1 = ECMA.toNumber(session,
eeContext.toValue(lhs.debuggerValue));
double d2 = ECMA.toNumber(session,
eeContext.toValue(rhs.debuggerValue));
return new DebuggerValue(new Double(d1 % d2));
}
case ABCConstants.OP_add: {
// E4X 11.4.1 and ECMA 11.6.1
flash.tools.debugger.Value v1 = eeContext
.toValue(lhs.debuggerValue);
flash.tools.debugger.Value v2 = eeContext
.toValue(rhs.debuggerValue);
boolean isXMLConcat = false;
if (v1.getType() == VariableType.OBJECT
&& v2.getType() == VariableType.OBJECT) {
String type1 = v1.getTypeName();
String type2 = v2.getTypeName();
int at;
at = type1.indexOf('@');
if (at != -1)
type1 = type1.substring(0, at);
at = type2.indexOf('@');
if (at != -1)
type2 = type2.substring(0, at);
if (type1.equals("XML") || type1.equals("XMLList")) //$NON-NLS-1$ //$NON-NLS-2$
if (type2.equals("XML") || type2.equals("XMLList")) //$NON-NLS-1$ //$NON-NLS-2$
isXMLConcat = true;
}
if (isXMLConcat) {
try {
IsolateSession workerSession = session.getWorkerSession(v1
.getIsolateId());
flash.tools.debugger.Value xml1 = workerSession
.callFunction(
v1,
"toXMLString", new flash.tools.debugger.Value[0]); //$NON-NLS-1$
flash.tools.debugger.Value xml2 = session.getWorkerSession(
v2.getIsolateId()).callFunction(v2,
"toXMLString", new flash.tools.debugger.Value[0]); //$NON-NLS-1$
String allXML = xml1.getValueAsString()
+ xml2.getValueAsString();
flash.tools.debugger.Value allXMLValue = DValue
.forPrimitive(allXML, v1.getIsolateId());
flash.tools.debugger.Value retval = workerSession
.callConstructor(
"XMLList", new flash.tools.debugger.Value[] { allXMLValue }); //$NON-NLS-1$
return new DebuggerValue(retval);
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
}
} else {
v1 = ECMA.toPrimitive(session, v1, null,
eeContext.getIsolateId());
v2 = ECMA.toPrimitive(session, v2, null,
eeContext.getIsolateId());
if (v1.getType() == VariableType.STRING
|| v2.getType() == VariableType.STRING) {
return new DebuggerValue(ECMA.toString(session, v1)
+ ECMA.toString(session, v2));
} else {
return new DebuggerValue(new Double(ECMA.toNumber(session,
v1) + ECMA.toNumber(session, v2)));
}
}
}
case ABCConstants.OP_subtract: {
// ECMA 11.6.2
double d1 = ECMA.toNumber(session,
eeContext.toValue(lhs.debuggerValue));
double d2 = ECMA.toNumber(session,
eeContext.toValue(rhs.debuggerValue));
return new DebuggerValue(new Double(d1 - d2));
}
case ABCConstants.OP_lshift: {
// ECMA 11.7.1
int n1 = ECMA
.toInt32(session, eeContext.toValue(lhs.debuggerValue));
int n2 = (int) (ECMA.toUint32(session,
eeContext.toValue(rhs.debuggerValue)) & 0x1F);
return new DebuggerValue(new Double(n1 << n2));
}
case ABCConstants.OP_rshift: {
// ECMA 11.7.1
int n1 = ECMA
.toInt32(session, eeContext.toValue(lhs.debuggerValue));
int n2 = (int) (ECMA.toUint32(session,
eeContext.toValue(rhs.debuggerValue)) & 0x1F);
return new DebuggerValue(new Double(n1 >> n2));
}
case ABCConstants.OP_urshift: {
// ECMA 11.7.1
long n1 = ECMA.toUint32(session,
eeContext.toValue(lhs.debuggerValue));
long n2 = (ECMA.toUint32(session,
eeContext.toValue(rhs.debuggerValue)) & 0x1F);
return new DebuggerValue(new Double(n1 >>> n2));
}
case ABCConstants.OP_lessthan: {
// ECMA 11.8.1
flash.tools.debugger.Value lessThan = ECMA.lessThan(session,
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue));
boolean result;
if (lessThan.getType() == VariableType.UNDEFINED) {
result = false;
} else {
result = ECMA.toBoolean(lessThan);
}
return new DebuggerValue(result);
}
case ABCConstants.OP_greaterthan: {
// ECMA 11.8.2
flash.tools.debugger.Value greaterThan = ECMA.lessThan(session,
eeContext.toValue(rhs.debuggerValue),
eeContext.toValue(lhs.debuggerValue));
boolean result;
if (greaterThan.getType() == VariableType.UNDEFINED) {
result = false;
} else {
result = ECMA.toBoolean(greaterThan);
}
return new DebuggerValue(result);
}
case ABCConstants.OP_lessequals: {
// ECMA 11.8.3
flash.tools.debugger.Value lessThan = ECMA.lessThan(session,
eeContext.toValue(rhs.debuggerValue),
eeContext.toValue(lhs.debuggerValue));
boolean result;
if (lessThan.getType() == VariableType.UNDEFINED) {
result = false;
} else {
result = !ECMA.toBoolean(lessThan);
}
return new DebuggerValue(result);
}
case ABCConstants.OP_greaterequals: {
// ECMA 11.8.4
flash.tools.debugger.Value lessThan = ECMA.lessThan(session,
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue));
boolean result;
if (lessThan.getType() == VariableType.UNDEFINED) {
result = false;
} else {
result = !ECMA.toBoolean(lessThan);
}
return new DebuggerValue(result);
}
case ABCConstants.OP_instanceof: {
try {
return new DebuggerValue(session.getWorkerSession(
eeContext.getIsolateId()).evalInstanceof(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue)));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
}
case ABCConstants.OP_in: {
try {
return new DebuggerValue(session.getWorkerSession(
eeContext.getIsolateId()).evalIn(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue)));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
}
case ABCConstants.OP_istypelate: {
try {
return new DebuggerValue(session.getWorkerSession(
eeContext.getIsolateId()).evalIs(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue)));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
}
case ABCConstants.OP_astypelate: {
try {
return new DebuggerValue(session.getWorkerSession(
eeContext.getIsolateId()).evalAs(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue)));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
}
case ABCConstants.OP_equals: {
// ECMA 11.9.1
return new DebuggerValue(new Boolean(ECMA.equals(session,
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue))));
}
// ASC3 notequals is a sepearate reducer nequals
// case ABCConstants.op_Tokens.NOTEQUALS_TOKEN:
// {
// // ECMA 11.9.2
// return new DebuggerValue(new Boolean(!ECMA.equals(session,
// eeContext.toValue(lhs.debuggerValue), eeContext
// .toValue(rhs.debuggerValue))));
// }
case ABCConstants.OP_strictequals: {
// ECMA 11.9.4
return new DebuggerValue(new Boolean(ECMA.strictEquals(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue))));
}
// ASC3 notequals is a sepearate reducer nequals
/*
* case Tokens.STRICTNOTEQUALS_TOKEN: { // ECMA 11.9.5 return new
* DebuggerValue(new
* Boolean(!ECMA.strictEquals(eeContext.toValue(lhs.debuggerValue),
* eeContext .toValue(rhs.debuggerValue)))); }
*/
case ABCConstants.OP_bitand: {
// ECMA 11.10
return new DebuggerValue(new Double(ECMA.toInt32(session,
eeContext.toValue(lhs.debuggerValue))
& ECMA.toInt32(session,
eeContext.toValue(rhs.debuggerValue))));
}
case ABCConstants.OP_bitxor: {
// ECMA 11.10
return new DebuggerValue(new Double(ECMA.toInt32(session,
eeContext.toValue(lhs.debuggerValue))
^ ECMA.toInt32(session,
eeContext.toValue(rhs.debuggerValue))));
}
case ABCConstants.OP_bitor: {
// ECMA 11.10
return new DebuggerValue(new Double(ECMA.toInt32(session,
eeContext.toValue(lhs.debuggerValue))
| ECMA.toInt32(session,
eeContext.toValue(rhs.debuggerValue))));
}
/*
* ASC3 reduce_logicalAndExpr & reduce_logicalOrExpr sepearate reducers
* case Tokens.LOGICALAND_TOKEN: { // ECMA 11.11
* flash.tools.debugger.Value result =
* eeContext.toValue(lhs.debuggerValue); if (ECMA.toBoolean(result)) {
* rhs = (DebuggerValue) node.rhs.evaluate(cx, this); result =
* eeContext.toValue(rhs.debuggerValue); } return new
* DebuggerValue(result); } case Tokens.LOGICALOR_TOKEN: { // ECMA 11.11
* flash.tools.debugger.Value result =
* eeContext.toValue(lhs.debuggerValue); if (!ECMA.toBoolean(result)) {
* rhs = (DebuggerValue) node.rhs.evaluate(cx, this); result =
* eeContext.toValue(rhs.debuggerValue); } return new
* DebuggerValue(result); }
*/
// case Tokens.EMPTY_TOKEN:
// // do nothing, already been folded
// return new DebuggerValue(null);
default:
//cx.internalError(ASTBuilder.getLocalizationManager().getLocalizedTextString("unrecognizedBinaryOperator")); //$NON-NLS-1$
return new DebuggerValue(null);
}
}
/**
* Resolve a dotted name, e.g., foo.bar.baz
*/
Object dottedName(IASNode iNode, String qualifiers, String base_name) {
return qualifiers + "." + base_name;
}
/**
* Error trap.
*/
public Object error_namespaceAccess(IASNode iNode, IASNode raw_qualifier,
Object qualified_name) {
return null;
}
/**
* Error trap.
*/
public Object error_reduce_Op_AssignId(IASNode iNode, Object non_lvalue,
Object rvalue) {
return null;
}
/**
* @return the double content of a numeric literal.
* @param iNode
* - the literal node.
*/
Double getDoubleContent(IASNode iNode) {
return AS3SemanticUtils.getDoubleContent(iNode, project);
}
/**
* @return the double content of a numeric literal.
* @param iNode
* - the literal node.
*/
Float getFloatContent(IASNode iNode) {
return AS3SemanticUtils.getFloatContent(iNode, project);
}
/**
* @return the name of an identifier.
* @param iNode
* - the IIdentifier node.
*/
String getIdentifierContent(IASNode iNode) {
return AS3SemanticUtils.getIdentifierContent(iNode);
}
/**
* @return the int content of a numeric literal.
* @param iNode
* - the literal node.
*/
Integer getIntegerContent(IASNode iNode) {
return AS3SemanticUtils.getIntegerContent(iNode, project);
}
/**
* @return always zero.
* @param iNode
* - the literal node.
*/
Integer getIntegerZeroContent(IASNode iNode) {
return 0;
}
/**
* @return always zero.
* @param iNode
* - the literal node.
*/
Long getIntegerZeroContentAsLong(IASNode iNode) {
return 0L;
}
/**
* @return the string content of a literal.
* @param iNode
* - the literal node.
*/
String getStringLiteralContent(IASNode iNode) {
return AS3SemanticUtils.getStringLiteralContent(iNode);
}
/**
* @return the uint content of a numeric literal.
* @param iNode
* - the literal node.
*/
Long getUintContent(IASNode iNode) {
return AS3SemanticUtils.getUintContent(iNode, project);
}
/*
* *******************************
* ** Cost/Decision Functions ** *******************************
*/
public int isIntLiteral(IASNode iNode) {
if (iNode.getNodeID() == ASTNodeID.LiteralNumberID) {
INumericValue numericVal = ((NumericLiteralNode) iNode)
.getNumericValue(project);
if (numericVal.getAssumedType() == IASLanguageConstants.BuiltinType.INT) {
return 1;
}
}
return Integer.MAX_VALUE;
}
public int isUintLiteral(IASNode iNode) {
if (iNode.getNodeID() == ASTNodeID.LiteralNumberID) {
INumericValue numericVal = ((NumericLiteralNode) iNode)
.getNumericValue(project);
if (numericVal.getAssumedType() == IASLanguageConstants.BuiltinType.UINT) {
return 1;
}
}
return Integer.MAX_VALUE;
}
public int isDoubleLiteral(IASNode iNode) {
if (iNode.getNodeID() == ASTNodeID.LiteralNumberID) {
return 2;
}
return Integer.MAX_VALUE;
}
public int isFloatLiteral(IASNode iNode) {
if (iNode.getNodeID() == ASTNodeID.LiteralNumberID) {
INumericValue numericVal = ((NumericLiteralNode) iNode)
.getNumericValue(project);
if (numericVal.getAssumedType() == IASLanguageConstants.BuiltinType.FLOAT) {
return 1;
}
return Integer.MAX_VALUE;
}
return Integer.MAX_VALUE;
}
/**
* Explore a MemberAccessNode and decide if its stem is a reference to a
* package. This method will always return a result greater than what
* isPackageName will return, as package name must "win" over dotted name.
*/
int isDottedName(IASNode n) {
int result = Integer.MAX_VALUE;
if (n instanceof MemberAccessExpressionNode) {
MemberAccessExpressionNode ma = (MemberAccessExpressionNode) n;
if (ma.stemIsPackage())
// This needs to be greater than the value returned from
// isPackageName,
// so that isPackageName wins
result = 2;
}
return result;
}
/**
* Explore a MemberAccessNode and decide if it is a reference to a package.
* This method will always return a result less than what isDottedName will
* return, as package name must "win" over dotted name.
*/
int isPackageName(IASNode n) {
int result = Integer.MAX_VALUE;
if (n instanceof MemberAccessExpressionNode) {
MemberAccessExpressionNode ma = (MemberAccessExpressionNode) n;
if (ma.isPackageReference())
// This needs to be less than the value returned from
// isDottedName,
// so that isPackageName wins
result = 1;
}
return result;
}
/**
* Get the definition associated with a node's qualifier and decide if the
* qualifier is a compile-time constant.
*
* @param iNode
* - the node to check.
* @pre - the node has an IdentifierNode 0th child.
* @return an attractive cost if the child has a known namespace, i.e., it's
* a compile-time constant qualifier.
*/
int qualifierIsCompileTimeConstant(IASNode iNode) {
IdentifierNode qualifier = (IdentifierNode) AS3SemanticUtils
.getNthChild(iNode, 0);
IDefinition def = qualifier.resolve(project);
int result = def instanceof NamespaceDefinition ? 1 : Integer.MAX_VALUE;
return result;
}
/**
* @return a feasible cost if a node has a compile-time constant defintion.
*/
int isCompileTimeConstant(IASNode iNode) {
if (AS3SemanticUtils.transformNameToConstantValue(iNode, project) != null)
return 1;
else
return Integer.MAX_VALUE;
}
/**
* @return a feasible cost if a node has a compile-time constant defintion.
*/
int isCompileTimeConstantFunction(IASNode iNode) {
if (AS3SemanticUtils.isConstantFunction(project, iNode))
return 1;
else
return Integer.MAX_VALUE;
}
/**
* @return a feasible cost if the parameterized type's base and parameter
* types are compile-time constants, ERROR_TRAP if not.
*/
int parameterTypeIsConstant(IASNode iNode) {
return Math.max(isKnownType(AS3SemanticUtils.getNthChild(iNode, 0)),
isKnownType(AS3SemanticUtils.getNthChild(iNode, 1)));
}
/**
* @return a feasible cost if the given node is a known type, ERROR_TRAP
* otherwise.
*/
int isKnownType(IASNode iNode) {
boolean isConstant = false;
if (iNode instanceof IExpressionNode) {
isConstant = ((IExpressionNode) iNode).resolve(project) instanceof ITypeDefinition;
}
return isConstant ? 1 : ERROR_TRAP;
}
/**
* Reduce a function call to a constant value. This is only possible for a
* limited set of function calls, and you should call
* isCompileTimeConstantFunction first to make sure this is possible.
*
* @param iNode
* the IFunctionCallNode
* @param method
* the Object of the method to call
* @param constant_args
* the constant_values used as arguments to the function call
* @return A constant value that that would be the result of calling the
* function at runtime with the specified arguments
*/
public Object transform_constant_function_to_value(IASNode iNode,
Object method, Vector<Object> constant_args) {
return null;
}
/**
* @return a feasible cost if the node is a BinaryExpression, and the type
* of the left or right side of the expressions resolves to "float"
*/
int isFloatBinOp(IASNode iNode) {
return 0;
}
/**
* @return a feasible cost (1) if the node is for 'new Array()'
*/
int isEmptyArrayConstructor(IASNode iNode) {
IIdentifierNode identifierNode = (IIdentifierNode) AS3SemanticUtils
.getNthChild(iNode, 1);
if (identifierNode.resolve(project) == project
.getBuiltinType(IASLanguageConstants.BuiltinType.ARRAY))
return 1;
return Integer.MAX_VALUE;
}
/**
* @return a feasible cost (1) if the node is for 'new Object()'
*/
int isEmptyObjectConstructor(IASNode iNode) {
IIdentifierNode identifierNode = (IIdentifierNode) AS3SemanticUtils
.getNthChild(iNode, 1);
if (identifierNode.resolve(project) == project
.getBuiltinType(IASLanguageConstants.BuiltinType.OBJECT))
return 1;
return Integer.MAX_VALUE;
}
/*
* *************************
* ** Reduction actions ** *************************
*/
public Object reduce_arrayIndexExpr(IASNode iNode, Object stem,
boolean is_super, Object index) {
return reduce_memberAccessExpr(iNode, stem, index, -1);
}
public Object reduce_arrayLiteral(IASNode iNode, Vector<Object> elements) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_assignToBracketExpr_to_expression(IASNode iNode,
Object stem, Object index, Object r, boolean is_super) {
Context eeContext = contextStack.scope();
Context newContext = eeContext
.createContext(((DebuggerValue) stem).debuggerValue);
contextStack.pushScope(newContext);
try {
return reduce_assignToNameExpr_to_expression(iNode, index, r);
} finally {
contextStack.popScope();
}
}
public Object reduce_assignToMemberExpr_to_expression(IASNode iNode,
Object stem, Object member, Object r) {
Context eeContext = contextStack.scope();
Context newContext = eeContext
.createContext(((DebuggerValue) stem).debuggerValue);
contextStack.pushScope(newContext);
try {
return reduce_assignToNameExpr_to_expression(iNode, member, r);
} finally {
contextStack.popScope();
}
}
public Object reduce_assignToDescendantsExpr(IASNode iNode, Object stem,
Object member, Object r, boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_assignToNameExpr_to_expression(IASNode iNode,
Object lvalue, Object r) {
// ASC : Refer : evaluate(macromedia.asc.util.Context cx,
// SetExpressionNode node)
Context eeContext = contextStack.scope();
DebuggerValue lhs = (DebuggerValue) lvalue;
Object variableToAssignTo;
// if (node.getMode() == Tokens.LEFTBRACKET_TOKEN || node.getMode() ==
// Tokens.EMPTY_TOKEN)
{
variableToAssignTo = ECMA.toString(eeContext.getSession(),
eeContext.toValue(lhs.debuggerValue));
}
// else
// {
// variableToAssignTo = rhs.debuggerValue;
// }
DebuggerValue newValue = (DebuggerValue) r;
try {
eeContext.assign(variableToAssignTo,
eeContext.toValue(newValue.debuggerValue));
} catch (NoSuchVariableException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
return newValue;
}
// Not supported :: //throw error
public Object reduce_assignToQualifiedMemberExpr(IASNode iNode,
Object stem, Object qualifier, Object member, Object rhs,
boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
// Not supported :: //throw error
public Object reduce_assignToQualifiedRuntimeMemberExpr(IASNode iNode,
Object stem, Object qualifier, Object runtime_member_selector,
Object rhs, boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
// Not supported :: //throw error
public Object reduce_assignToQualifiedAttributeExpr(IASNode iNode,
Object stem, Object qualifier, Object member, Object rhs,
boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_assignToRuntimeNameExpr(IASNode iNode, Object lval,
Object r, final boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_assignToUnqualifiedRuntimeAttributeExpr(IASNode iNode,
Object stem, Object rt_attr, Object rhs, boolean need_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$;
}
public Object reduce_attributeName(IASNode iNode, Object attr_name) {
return new DebuggerValue("@"
+ ((DebuggerValue) attr_name).debuggerValue);
}
public Boolean reduce_booleanLiteral(IASNode iNode) {
return AS3SemanticUtils.getBooleanContent(iNode);
}
public String reduce_by_concatenation(IASNode iNode, String first,
String second) {
return first + "." + second;
}
public Object reduce_commaExpr(IASNode iNode, Object payload_expr,
Vector<Object> exprs) {
Object result = null;
return result;
}
/**
* Reduce expression like:<br>
* {@code delete o[p]}
*
* @param iNode
* Tree node for the {@code delete} statement.
* @param stem
* Instructions for creating a {@code DynamicAccessNode}.
* @param index
* Instructions for initializing the index expression.
* @return Instructions for executing a {@code delete} statement.
*/
public Object reduce_deleteBracketExpr(IASNode iNode, Object stem,
Object index) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
/**
* Reduce E4X expression like:<br>
* {@code delete x.@[foo]}
*
* @param iNode
* Tree node for the {@code delete} statement.
* @param stem
* Instructions for creating a {@code MemberAccessExpressionNode}
* .
* @param index
* Instructions for initializing the array index expression.
* @return Instructions for executing a {@code delete} statement.
*/
public Object reduce_deleteAtBracketExpr(IASNode iNode, Object stem,
Object index) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_deleteDescendantsExpr(IASNode iNode, Object stem,
Object field) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_deleteExprExprExpr(IASNode iNode, Object expr) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_deleteMemberExpr(IASNode iNode, Object stem,
Object field) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_deleteRuntimeNameExpr(IASNode iNode, Object stem,
Object rt_name) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_deleteNameExpr(IASNode iNode, Object n) {
throw new ExpressionEvaluatorException(keywordNotAllowed("delete")); //$NON-NLS-1$
}
public Object reduce_e4xFilter(IASNode iNode, Object stem, Object filter) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_embed(IASNode iNode) {
Object result = null;
return result;
}
/**
* Reduce expression like:<br>
* {@code a[i]()}
*
* @param iNode
* Tree node for the function call.
* @param stem
* Instructions for creating a {@code DynamicAccessNode}.
* @param index
* Instructions for initializing the index expression.
* @return Instructions for executing a {@code function call} statement.
*/
public Object reduce_functionAsBracketExpr(IASNode iNode, Object stem,
Object index, Vector<Object> args) {
Object result = null;
return result;
}
public Object reduce_functionAsMemberExpr(IASNode iNode, Object stem,
Object method_name, Vector<Object> args) {
try {
Context context = contextStack.scope();
DebuggerValue lhs = (DebuggerValue) stem;
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
return reduce_functionCall_common(iNode, method_name, args, true,
false);
} finally {
contextStack.popScope();
}
}
public Object reduce_functionAsRandomExpr(IASNode iNode,
Object random_expr, Vector<Object> args) {
return reduce_functionCall_common(iNode, random_expr, args, true, false);
}
public Object reduce_functionCallExpr_to_expression(IASNode iNode,
Object method_name, Vector<Object> args) {
return reduce_functionCall_common(iNode, method_name, args, true, false);
}
private Object reduce_functionCall_common(IASNode iNode,
Object method_name, Vector<Object> args, boolean need_result,
boolean isConstructor) {
Context context = contextStack.scope();
DebuggerValue func = (DebuggerValue) method_name;
try {
Object[] argValues = new Object[args.size()];
for (int i = 0; i < args.size(); i++) {
DebuggerValue dv = (DebuggerValue) args.get(i);
argValues[i] = dv.debuggerValue;
}
return new DebuggerValue(callFunction(context, isConstructor,
func.debuggerValue, argValues));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
}
}
public Object reduce_functionCallOfSuperclassMethod_to_expression(
IASNode iNode, Object stem, Object method_name, Vector<Object> args) {
throw new ExpressionEvaluatorException(keywordNotAllowed("super")); //$NON-NLS-1$
}
public Object reduce_logicalAndExpr(IASNode iNode, Object l, Object r) {
// REFER : ASC : public Value evaluate(macromedia.asc.util.Context cx,
// BinaryExpressionNode node)
// ECMA 11.11
Context eeContext = contextStack.scope();
DebuggerValue lhs = (DebuggerValue) l;
flash.tools.debugger.Value result = eeContext
.toValue(lhs.debuggerValue);
if (ECMA.toBoolean(result)) {
DebuggerValue rhs = null;
if (r instanceof DebuggerValue) {
rhs = (DebuggerValue) r;
} else {
rhs = ((UnEvaluatedDebugExpression) r).evaluate(eeContext);
}
result = eeContext.toValue(rhs.debuggerValue);
}
return new DebuggerValue(result);
}
public Object reduce_logicalNotExpr(IASNode iNode, Object expr) {
Context eeContext = contextStack.scope();
DebuggerValue arg = (DebuggerValue) expr;
// ECMA 11.4.9
return new DebuggerValue(new Boolean(!ECMA.toBoolean(eeContext
.toValue(arg.debuggerValue))));
}
public Object reduce_logicalOrExpr(IASNode iNode, Object l, Object r) {
// REFER : ASC : public Value evaluate(macromedia.asc.util.Context cx,
// BinaryExpressionNode node)
// ECMA 11.11
Context eeContext = contextStack.scope();
DebuggerValue lhs = (DebuggerValue) l;
flash.tools.debugger.Value result = eeContext
.toValue(lhs.debuggerValue);
if (!ECMA.toBoolean(result)) {
DebuggerValue rhs = null;
if (rhs instanceof DebuggerValue) {
rhs = (DebuggerValue) r;
} else {
rhs = ((UnEvaluatedDebugExpression) r).evaluate(eeContext);
}
result = eeContext.toValue(rhs.debuggerValue);
}
return new DebuggerValue(result);
}
/**
* reduce a MemberAccessExpression. This example just concats the stem and
* member together
*/
public Object reduce_memberAccessExpr(IASNode iNode, Object stem,
Object member, int opcode) {
DebuggerValue lhs = (DebuggerValue) stem;
Context context = contextStack.scope();
boolean pushedScope = false;
if (lhs != null) {
flash.tools.debugger.Value lhsValue = context
.toValue(lhs.debuggerValue);
if (ECMA.equals(context.getSession(), lhsValue,
context.toValue(null)))
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"nullPointerException")); //$NON-NLS-1$
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
pushedScope = true;
}
try {
DebuggerValue rhs = (DebuggerValue) transform_name_to_expression(
iNode, member);
return rhs;// node.selector.evaluate(cx, this);
} finally {
if (pushedScope)
contextStack.popScope();
}
// return stem + "." + member;
}
public Object reduce_qualifiedMemberAccessExpr(IASNode iNode, Object stem,
Object qualifier, Object member, int opcode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_qualifiedAttributeRuntimeMemberExpr(IASNode iNode,
Object stem, Object qualifier, Object runtime_member_selector,
int opcode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_qualifiedMemberRuntimeNameExpr(IASNode iNode,
Object stem, Object qualifier, Object runtime_member_selector) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$;
}
public Object reduce_qualifiedAttributeExpr(IASNode iNode, Object stem,
Object qualifier, Object member, int opcode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_unqualifiedAttributeExpr(IASNode iNode, Object stem,
Object rt_attr, int opcode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$ }
}
/**
* Reduce runtime attribute expression, such as {@code @[exp]}.
*
* @param iNode
* Node for {@code @[...]}. It is a
* {@code ArrayIndexExpressionID(Op_AtID, ...)}.
* @param rt_attr
* Instructions generated for the runtime name expression.
* @return Instructions to get the value of an attribute described with a
* runtime name.
*/
public Object reduce_runtimeAttributeExp(IASNode iNode, Object rt_attr) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceAccess(IASNode iNode, IASNode qualifier,
Object qualified_name) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceAsName_to_expression(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceAsName_to_multinameL(IASNode iNode,
final boolean is_attribute) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceAsName_to_name(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceMultinameL(IASNode iNode,
IASNode qualifier_node, Object expr) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceRTQName(IASNode iNode, Object qualifier,
Object qualified_name) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_namespaceRTQNameL(IASNode iNode, Object qualifier,
Object expr) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_neqExpr(IASNode iNode, Object l, Object r) {
Object result = null;
return result;
}
public Object reduce_nameToTypeName(Object name, boolean check_name) {
return name;
}
public Object reduce_newMemberProperty(IASNode iNode, Object stem,
Object member, Vector<Object> args) {
Object result = null;
return result;
}
public Object reduce_newAsRandomExpr(IASNode iNode, Object random_expr,
Vector<Object> args) {
Object result = null;
return result;
}
public Object reduce_newEmptyArray(IASNode iNode) {
Object result = null;
return result;
}
public Object reduce_newEmptyObject(IASNode iNode) {
Object result = null;
return result;
}
public Object reduce_newExpr(IASNode iNode, Object class_Object,
Vector<Object> args) {
return reduce_functionCall_common(iNode, class_Object, args, true, true);
}
public Object reduce_newVectorLiteral(IASNode iNode, Object literal) {
return literal;
}
public Object reduce_nilExpr_to_expression(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_nullLiteral_to_constant_value(IASNode iNode) {
return new DebuggerValue(null);
}
public Object reduce_nullLiteral_to_object_literal(IASNode iNode) {
return new DebuggerValue(null);
}
public Object reduce_objectLiteral(IASNode iNode, Vector<Object> elements) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_objectLiteralElement(IASNode iNode, Object id,
Object value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_parameterizedTypeName(IASNode iNode, Object base,
Object param) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_parameterizedTypeExpression(IASNode iNode,
Object base, Object param) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_postDecBracketExpr(IASNode iNode, Object stem,
Object index, boolean need_result) {
return reduce_postDecMemberExpr(iNode, stem, index, need_result);
}
public Object reduce_postDecMemberExpr(IASNode iNode, Object stem,
Object field, boolean need_result) {
try {
DebuggerValue lhs = (DebuggerValue) stem;
Context context = contextStack.scope();
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
return reduce_prePostIncDecExpr(iNode, field, true, false);
} finally {
contextStack.popScope();
}
}
public Object reduce_postDecNameExpr(IASNode iNode, Object unary,
boolean need_result) {
return reduce_prePostIncDecExpr(iNode, unary, true, false);
}
public Object reduce_postIncBracketExpr(IASNode iNode, Object stem,
Object index, boolean need_result) {
return reduce_postIncMemberExpr(iNode, stem, index, need_result);
}
public Object reduce_postIncMemberExpr(IASNode iNode, Object stem,
Object field, boolean need_result) {
try {
DebuggerValue lhs = (DebuggerValue) stem;
Context context = contextStack.scope();
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
return reduce_prePostIncDecExpr(iNode, field, true, true);
} finally {
contextStack.popScope();
}
}
public Object reduce_postIncNameExpr(IASNode iNode, Object unary,
boolean need_result) {
return reduce_prePostIncDecExpr(iNode, unary, true, true);
}
public Object reduce_preDecBracketExpr(IASNode iNode, Object stem,
Object index, boolean need_result) {
return reduce_preDecMemberExpr(iNode, stem, index, need_result);
}
public Object reduce_preDecMemberExpr(IASNode iNode, Object stem,
Object field, boolean need_result) {
try {
DebuggerValue lhs = (DebuggerValue) stem;
Context context = contextStack.scope();
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
return reduce_prePostIncDecExpr(iNode, field, false, false);
} finally {
contextStack.popScope();
}
}
public Object reduce_preDecNameExpr(IASNode iNode, Object unary,
boolean need_result) {
return reduce_prePostIncDecExpr(iNode, unary, false, false);
}
public Object reduce_preIncBracketExpr(IASNode iNode, Object stem,
Object index, boolean need_result) {
return reduce_preIncMemberExpr(iNode, stem, index, need_result);
}
public Object reduce_preIncMemberExpr(IASNode iNode, Object stem,
Object field, boolean need_result) {
try {
DebuggerValue lhs = (DebuggerValue) stem;
Context context = contextStack.scope();
Context newContext = context.createContext(lhs.debuggerValue);
contextStack.pushScope(newContext);
return reduce_prePostIncDecExpr(iNode, field, false, true);
} finally {
contextStack.popScope();
}
}
public Object reduce_preIncNameExpr(IASNode iNode, Object unary,
boolean need_result) {
return reduce_prePostIncDecExpr(iNode, unary, false, true);
}
public Object reduce_prePostIncDecExpr(IASNode iNode, Object unary,
boolean isPostFix, boolean isIncrement) {
try {
DebuggerValue expr = (DebuggerValue) unary;
Context debuggerContext = contextStack.scope();
String memberName = ECMA.toString(debuggerContext.getSession(),
debuggerContext.toValue(expr.debuggerValue));
Object lookupResult = debuggerContext.lookup(memberName);
double before = ECMA.toNumber(debuggerContext.getSession(),
debuggerContext.toValue(lookupResult));
double after;
if (isIncrement) {
after = before + 1;
} else {
after = before - 1;
}
debuggerContext.assign(memberName,
debuggerContext.toValue(new Double(after)));
Object result;
if (isPostFix) {
result = new Double(before);
} else {
result = new Double(after);
}
return new DebuggerValue(result);
} catch (NoSuchVariableException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
}
public Object reduce_regexLiteral(IASNode iNode) {
if (iNode instanceof RegExpLiteralNode) {
RegExpLiteralNode rgXNode = (RegExpLiteralNode) iNode;
String val = rgXNode.getValue(true);
String flags;
String re;
if (val.length() > 0 && val.charAt(0) == '/') {
int lastSlash = val.lastIndexOf('/');
re = val.substring(1, lastSlash);
flags = val.substring(lastSlash + 1);
} else {
re = val;
flags = ""; //$NON-NLS-1$
}
Context eeContext = contextStack.scope();
try {
return new DebuggerValue(callFunction(eeContext, true,
"RegExp", new Object[] { re, flags })); //$NON-NLS-1$
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
}
}
throw new ExpressionEvaluatorException("Unable to resolve regex");
}
public Object reduce_runtimeNameExpression(IASNode iNode, Object expr) {
return expr;
}
/**
* Reduce an identifier node This just returns the name of the name
* currently.
*/
public Object reduce_simpleName(IASNode iNode) {
return new DebuggerValue(((IdentifierNode) iNode).getName());
}
public Object reduce_declName(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_strictneqExpr(IASNode iNode, Object l, Object r) {
Context eeContext = contextStack.scope();
DebuggerValue lhs = (DebuggerValue) l;
DebuggerValue rhs = (DebuggerValue) r;
// ECMA 11.9.5
return new DebuggerValue(new Boolean(!ECMA.strictEquals(
eeContext.toValue(lhs.debuggerValue),
eeContext.toValue(rhs.debuggerValue))));
}
public Object reduce_superAccess(IASNode iNode, Object qualified_name) {
throw new ExpressionEvaluatorException(keywordNotAllowed("super")); //$NON-NLS-1$
}
public Object reduce_ternaryExpr(IASNode iNode, Object test,
Object when_true, Object when_false) {
DebuggerValue condition = (DebuggerValue) test;
Context eeContext = contextStack.scope();
boolean b = ECMA.toBoolean(eeContext.toValue(condition.debuggerValue));
if (b) {
return when_true;
} else {
return when_false;
}
}
public Object reduce_typedVariableExpression(IASNode iNode,
Object var_name, Object var_type) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
// transform_name_to_expression
public Object reduce_typeof_expr(IASNode iNode, Object operand) {
// ECMA 11.4.3
Context eeContext = contextStack.scope();
DebuggerValue arg = (DebuggerValue) operand;
flash.tools.debugger.Value value = eeContext.toValue(arg.debuggerValue);
switch (value.getType()) {
case VariableType.UNDEFINED:
return new DebuggerValue("undefined"); //$NON-NLS-1$
case VariableType.NULL:
return new DebuggerValue("object"); //$NON-NLS-1$
case VariableType.BOOLEAN:
return new DebuggerValue("boolean"); //$NON-NLS-1$
case VariableType.NUMBER:
return new DebuggerValue("number"); //$NON-NLS-1$
case VariableType.STRING:
return new DebuggerValue("string"); //$NON-NLS-1$
case VariableType.OBJECT: {
String typeName = value.getTypeName();
int at = typeName.indexOf('@');
if (at != -1)
typeName = typeName.substring(0, at);
if (typeName.equals("XML") || typeName.equals("XMLList")) //$NON-NLS-1$ //$NON-NLS-2$
return new DebuggerValue("xml"); //$NON-NLS-1$
}
default:
return new DebuggerValue("object"); //$NON-NLS-1$
}
}
public Object reduce_typeof_name(IASNode iNode, Object object) {
Object exprObject = transform_name_to_expression(iNode, object);
return reduce_typeof_expr(iNode, exprObject);
}
public Object reduce_typeNameParameterAsType(IASNode iNode,
Object type_param) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_vectorLiteral(IASNode iNode, Object type_param,
Vector<Object> elements) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_voidExpr_to_type_name(IASNode node) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_void0Literal_to_constant_value(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_void0Literal_to_object_literal(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_void0Operator(IASNode iNode) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_voidOperator_to_constant_value(IASNode iNode,
Object constant_value) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object reduce_voidOperator_to_expression(IASNode iNode, Object expr) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
/**
* The enumeration of states that the code generator finds interesting in an
* XML literal. There are states here than the reducer, below, doesn't
* consider especially interesting; see computeXMLContentStateMatrix() for
* their usage.
*/
@SuppressWarnings("unused")
private enum XMLContentState {
};
public Object reduce_XMLContent(IASNode iNode, Vector<Object> exprs) {
Object result = null;
return result;
}
public Object reduce_XMLList(IASNode iNode, Vector<Object> exprs) {
Object result = null;
return result;
}
public Object reduce_XMLListConst(IASNode iNode, Vector<String> elements) {
Object result = null;
return result;
}
/*
* ******************************
* ** Transformation routines ** ******************************
*/
public Object transform_boolean_constant(IASNode iNode,
Boolean boolean_constant) {
Object result = new DebuggerValue(boolean_constant);
return result;
}
public Object transform_double_constant(IASNode iNode,
Double double_constant) {
Object result = new DebuggerValue(double_constant);
return result;
}
public Object transform_numeric_constant(IASNode iNode,
Number numeric_constant) {
Object result = new DebuggerValue(numeric_constant);
;
return result;
}
/**
* Transform any constant_value into an expression, so we can constant fold
* all sorts of expressions.
*
* @param iNode
* the node that generated the constant_value
* @param constant_value
* the constant value
* @return an Object that contains instructions to push the constant_value
* onto the stack.
*/
public Object transform_constant_value(IASNode iNode, Object constant_value) {
return constant_value;
}
public Object transform_float_constant(IASNode iNode, Float float_constant) {
Object result = new DebuggerValue(float_constant);
return result;
}
/**
* transform a string_constant to a constant_value - essentially a no-op,
* but need a reduction so we can assign it a cost
*/
public Object transform_string_constant_to_constant(IASNode iNode,
String string_constant) {
return string_constant;
}
/**
* transform a boolean_constant to a constant_value - essentially a no-op,
* but need a reduction so we can assign it a cost
*/
public Object transform_boolean_constant_to_constant(IASNode iNode,
Boolean boolean_constant) {
return boolean_constant;
}
/**
* transform a numeric_constant to a constant_value - essentially a no-op,
* but need a reduction so we can assign it a cost
*/
public Object transform_numeric_constant_to_constant(IASNode iNode,
Number numeric_constant) {
if (numeric_constant instanceof Float) {
return new DebuggerValue(new Double((Float) numeric_constant));
} else {
return new DebuggerValue(new Double((Double) numeric_constant));
}
}
public Object transform_expression_to_constant_value(IASNode iNode,
Object expression) {
// return null - something higher up will report any appropriate
// diagnostics.
return null;
}
public Object transform_integer_constant(IASNode iNode,
Integer integer_constant) {
DebuggerValue result = new DebuggerValue(new Double(integer_constant));
return result;
}
public Object transform_name_to_constant_value(IASNode iNode) {
Object result = null;
return result;
}
/**
* Transform a name into an expression. In the Code generator this generates
* code to get the name and put it on the stack, but for the debugger we
* probably just want to return the name.
*/
public Object transform_name_to_expression(IASNode iNode, Object name) {
// ASC REFER : public Value evaluate(macromedia.asc.util.Context cx,
// GetExpressionNode node)
DebuggerValue identifier = (DebuggerValue) name;
Context eeContext = contextStack.scope();
String nameStr = ECMA.toString(eeContext.getSession(),
eeContext.toValue(identifier.debuggerValue));
flash.tools.debugger.Value contextValue = eeContext.toValue();
/**
* When contextValue is XMLList and a child node has been accessed, the
* context used to resolve variables within [] operator will be a
* FlashValueContext while rhs.debuggerValue will be a
* FlexLocalVariable. The fix for FB-25660 makes sure
* FlashValueContext.toValue(o) checks this case and returns
* getFlashVariable().getValue(). We still need to check if this Value
* is of type Number so that the if check below behaves correctly.
*/
if (contextValue != null && isXMLType(contextValue)
&& !isNumericIndex(iNode, identifier.debuggerValue, eeContext)) {
String function;
Object arg;
if (nameStr.length() > 0 && nameStr.charAt(0) == '@') {
// expression is node.@attr, so we call node.attribute("attr")
function = "attribute"; //$NON-NLS-1$
arg = nameStr.substring(1);
} else {
arg = identifier.debuggerValue;
boolean isDecendentsOpr = (iNode.getNodeID() == ASTNodeID.Op_DescendantsID);
if (isDecendentsOpr) {// node.getMode() ==
// Tokens.DOUBLEDOT_TOKEN) {
// expression is node..tag, so we call
// node.descendants("tag")
function = "descendants"; //$NON-NLS-1$
} else {
// expression is node.tag, so we call node.child("tag")
function = "child"; //$NON-NLS-1$
}
}
try {
return new DebuggerValue(callFunction(eeContext, false,
function, new Object[] { arg }));
} catch (PlayerDebugException e) {
throw new ExpressionEvaluatorException(e);
}
} else if (contextValue != null
&& contextValue.getType() == VariableType.STRING
&& ((DebuggerValue) name).debuggerValue.equals("length")) //$NON-NLS-1$
{
String valuestr = contextValue.getValueAsString();
return new DebuggerValue(new Double(valuestr.length()));
} else {
Object lookupResult;
try {
lookupResult = eeContext.lookup(ECMA.toString(
eeContext.getSession(),
eeContext.toValue(identifier.debuggerValue)));
} catch (NoSuchVariableException e) {
throw new ExpressionEvaluatorException(e);
} catch (PlayerFaultException e) {
throw new ExpressionEvaluatorException(e);
}
return new DebuggerValue(lookupResult);
}
}
public Object transform_non_resolving_identifier(IASNode iNode,
String non_resolving_identifier) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object transform_runtime_name_expression(IASNode iNode,
Object runtime_name_expression) {
throw new ExpressionEvaluatorException(ASTBuilder
.getLocalizationManager().getLocalizedTextString(
"unsupportedExpression")); //$NON-NLS-1$
}
public Object transform_string_constant(IASNode iNode,
String string_constant) {
return new DebuggerValue(string_constant);
}
public Object transform_uint_constant(IASNode iNode, Long uint_constant) {
Object result = new DebuggerValue(uint_constant);
return result;
}
/**
* Generate a unary operator.
*
* @param operand
* - the operand expression.
* @param opcode
* - the operator's opcode.
* @return an Object that applies the operator to the operand.
*/
Object unaryOp(IASNode iNode, Object operand, int opcode) {
// REFER ASC public Value evaluate(macromedia.asc.util.Context cx,
// UnaryExpressionNode node)
DebuggerValue arg = (DebuggerValue) operand;
Context eeContext = contextStack.scope();
switch (opcode) {
case ABCConstants.OP_returnvoid:
// ECMA 11.4.2
eeContext.toValue(arg.debuggerValue);
return new DebuggerValue(flash.tools.debugger.Value.UNDEFINED);
case ABCConstants.OP_typeof: {
return reduce_typeof_expr(iNode, operand);
}
case ABCConstants.OP_convert_d:
case ABCConstants.OP_unplus: {
// ECMA 11.4.6
return new DebuggerValue(new Double(ECMA.toNumber(
eeContext.getSession(),
eeContext.toValue(arg.debuggerValue))));
}
case ABCConstants.OP_negate: {
// ECMA 11.4.7
return new DebuggerValue(new Double(-ECMA.toNumber(
eeContext.getSession(),
eeContext.toValue(arg.debuggerValue))));
}
case ABCConstants.OP_bitnot: {
// ECMA 11.4.8
return new DebuggerValue(new Double(~ECMA.toInt32(
eeContext.getSession(),
eeContext.toValue(arg.debuggerValue))));
}
case ABCConstants.OP_not: {
// ECMA 11.4.9
return new DebuggerValue(new Boolean(!ECMA.toBoolean(eeContext
.toValue(arg.debuggerValue))));
}
default:
throw new UnsupportedOperationException();
}
}
Object errorPackageName(IASNode iNode, String qualifiers, String base_name) {
return null;
}
// myxml[3] or myxml["3"] is handled differently from myxml["childtag"].
// This function takes the part in the brackets, and returns true if it
// is a number or a string that can be converted to a number.
private boolean isNumericIndex(IASNode node, Object index, Context context) {
// if (node.getMode() != Tokens.LEFTBRACKET_TOKEN)
if (node.getNodeID() != ASTNodeID.ArrayIndexExpressionID)
return false; // it is node.member or node..member or whatever, but
// not node[member]
if (index instanceof Double) {
return true; // it is node[number]
} else if (index instanceof String) {
String s = (String) index;
if (s.length() == 0) {
return false;
} else {
try {
Double.parseDouble(s);
return true; // it is node["number"]
} catch (NumberFormatException e) {
return false;
}
}
} else if (context != null && index != null) {
// Resolve the Value to see if it is a Number
flash.tools.debugger.Value value = context.toValue(index);
if (value != null && value.getType() == VariableType.NUMBER) {
return true;
}
return false;
} else {
return false;
}
}
private boolean isXMLType(flash.tools.debugger.Value value) {
String typename = value.getTypeName();
int at = typename.indexOf('@');
if (at != -1)
typename = typename.substring(0, at);
return typename.equals("XML") || typename.equals("XMLList"); //$NON-NLS-1$ //$NON-NLS-2$
}
private String keywordNotAllowed(String keyword) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("keyword", keyword); //$NON-NLS-1$
return ASTBuilder.getLocalizationManager().getLocalizedTextString(
"keywordNotAllowed", parameters); //$NON-NLS-1$
}
/**
* @param expressionNode
* @param expression
* @return
*/
public Object reduceLazyExpression(final IASNode expressionNode) {
UnEvaluatedDebugExpression delayedEvaluator = new UnEvaluatedDebugExpression() {
@Override
public DebuggerValue evaluate(Context eeContext) {
try {
IExpressionEvaluator evalutor = new DebuggerExpressionEvaluator(
project);
return evalutor.evaluate(eeContext, expressionNode);
} catch (Exception e) {
throw new ExpressionEvaluatorException(e);
}
}
};
return delayedEvaluator;
}
private static abstract class UnEvaluatedDebugExpression {
public abstract DebuggerValue evaluate(Context eeContext);
}
}