blob: 39274677e9331df652e64ff3f678d19bfc4a87e1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* $RCSfile: ParseTreeAllocationInstantiationVisitor.java,v $
* $Revision: 1.9 $ $Date: 2005/10/28 22:56:46 $
*/
package org.eclipse.jem.internal.instantiation.base;
import java.text.MessageFormat;
import java.util.List;
import org.eclipse.jem.internal.instantiation.*;
import org.eclipse.jem.internal.proxy.core.*;
import org.eclipse.jem.internal.proxy.initParser.tree.*;
/**
* This is the standard parse visitor for instantiating a bean proxy from a java parse tree allocation.
* It can be reused, but is not thread-safe.
*
* @since 1.0.0
*/
public class ParseTreeAllocationInstantiationVisitor extends ParseVisitor {
/**
* The expression that is being created and evaluated.
*/
private IExpression expression;
/*
* The next expression type that should be used. It is used when one expression is sending the
* visitation to the next expression. It will set this to what that expression should be using. This
* is necessary because the next expression doesn't know what it should be.
*/
private ForExpression nextExpression = ForExpression.ROOTEXPRESSION;
/**
* An exception occurred during processing. It is a RuntimeException because
* it can be thrown at any time. It wrappers another exception. That exception
* can be retrieved from the cause of the ProcessingException.
*
* @see Throwable#getCause()
* @since 1.0.0
*/
public static class ProcessingException extends RuntimeException {
/**
* Comment for <code>serialVersionUID</code>
*
* @since 1.1.0
*/
private static final long serialVersionUID = 1268624222490406643L;
/**
* @param cause
*
* @since 1.0.0
*/
public ProcessingException(Throwable cause) {
super(cause);
}
}
static final InfixOperator[] INFIXTOPROXY;
static {
INFIXTOPROXY = new InfixOperator[PTInfixOperator.VALUES.size()];
INFIXTOPROXY[PTInfixOperator.AND] = InfixOperator.IN_AND;
INFIXTOPROXY[PTInfixOperator.CONDITIONAL_AND] = InfixOperator.IN_CONDITIONAL_AND;
INFIXTOPROXY[PTInfixOperator.CONDITIONAL_OR] = InfixOperator.IN_CONDITIONAL_OR;
INFIXTOPROXY[PTInfixOperator.DIVIDE] = InfixOperator.IN_DIVIDE;
INFIXTOPROXY[PTInfixOperator.EQUALS] = InfixOperator.IN_EQUALS;
INFIXTOPROXY[PTInfixOperator.GREATER] = InfixOperator.IN_GREATER;
INFIXTOPROXY[PTInfixOperator.GREATER_EQUALS] = InfixOperator.IN_GREATER_EQUALS;
INFIXTOPROXY[PTInfixOperator.LEFT_SHIFT] = InfixOperator.IN_LEFT_SHIFT;
INFIXTOPROXY[PTInfixOperator.LESS] = InfixOperator.IN_LESS;
INFIXTOPROXY[PTInfixOperator.LESS_EQUALS] = InfixOperator.IN_LESS_EQUALS;
INFIXTOPROXY[PTInfixOperator.MINUS] = InfixOperator.IN_MINUS;
INFIXTOPROXY[PTInfixOperator.NOT_EQUALS] = InfixOperator.IN_NOT_EQUALS;
INFIXTOPROXY[PTInfixOperator.OR] = InfixOperator.IN_OR;
INFIXTOPROXY[PTInfixOperator.PLUS] = InfixOperator.IN_PLUS;
INFIXTOPROXY[PTInfixOperator.REMAINDER] = InfixOperator.IN_REMAINDER;
INFIXTOPROXY[PTInfixOperator.RIGHT_SHIFT_SIGNED] = InfixOperator.IN_RIGHT_SHIFT_SIGNED;
INFIXTOPROXY[PTInfixOperator.RIGHT_SHIFT_UNSIGNED] = InfixOperator.IN_RIGHT_SHIFT_UNSIGNED;
INFIXTOPROXY[PTInfixOperator.TIMES] = InfixOperator.IN_TIMES;
INFIXTOPROXY[PTInfixOperator.XOR] = InfixOperator.IN_XOR;
}
/**
* A helper method to convert the parse tree's infix operator to the Proxy infix operator.
*
* @param operator
* @return
*
* @since 1.0.0
*/
public static InfixOperator convertPTInfixOperatorToProxyInfixOperator(PTInfixOperator operator) {
return INFIXTOPROXY[operator.getValue()];
}
static final PrefixOperator[] PREFIXTOPROXY;
static {
PREFIXTOPROXY = new PrefixOperator[PTPrefixOperator.VALUES.size()];
PREFIXTOPROXY[PTPrefixOperator.COMPLEMENT] = PrefixOperator.PRE_COMPLEMENT;
PREFIXTOPROXY[PTPrefixOperator.MINUS] = PrefixOperator.PRE_MINUS;
PREFIXTOPROXY[PTPrefixOperator.NOT] = PrefixOperator.PRE_NOT;
PREFIXTOPROXY[PTPrefixOperator.PLUS] = PrefixOperator.PRE_PLUS;
}
/**
* A helper method to convert the parse tree's prefix operator to the Proxy prefix operator.
*
* @param operator
* @return
*
* @since 1.0.0
*/
public static PrefixOperator convertPTPrefixOperatorToProxyPrefixOperator(PTPrefixOperator operator) {
return PREFIXTOPROXY[operator.getValue()];
}
/**
* Create the visitor with the given registry.
*
* @param registry
*
* @since 1.0.0
*/
public ParseTreeAllocationInstantiationVisitor() {
}
/**
* Get the current registry.
*
* @return
*
* @since 1.0.0
*/
protected final ProxyFactoryRegistry getRegistry() {
return expression.getRegistry();
}
/**
* Get the current expression.
*
* @return
*
* @since 1.0.0
*/
protected final IExpression getExpression() {
return expression;
}
/**
* Get the beanproxy for the given expression and registry. It will evaluate immediately.
*
* @param expression
* @param registry
* @return
* @throws IllegalStateException
* @throws ThrowableProxy
* @throws NoExpressionValueException
* @throws ProcessingException
*
* @since 1.0.0
*/
public IBeanProxy getBeanProxy(PTExpression expression, ProxyFactoryRegistry registry) throws IllegalStateException, IllegalArgumentException, ThrowableProxy, NoExpressionValueException, ProcessingException {
this.expression = registry.getBeanProxyFactory().createExpression();
setNextExpression(ForExpression.ROOTEXPRESSION);
try {
expression.accept(this);
} catch (ProcessingException e) {
// Handle the most common that make sense to be know distinctly and throw them instead of ProcessingException.
Throwable t = e.getCause();
if (t instanceof NoExpressionValueException)
throw (NoExpressionValueException) t;
else if (t instanceof IllegalStateException)
throw (IllegalStateException) t;
else
throw e;
}
return getExpression().getExpressionValue();
}
/**
* Using the given expression processor allocate the proxy. It will not evaluate immediately, but just push onto the expression.
* @param expression
* @param expressionProcessor
* @return the ExpressionProxy for the allocation.
* @throws IllegalStateException
* @throws IllegalArgumentException
* @throws ProcessingException
*
* @since 1.1.0
*/
public ExpressionProxy getProxy(PTExpression expression, IExpression expressionProcessor) throws IllegalStateException, IllegalArgumentException, ProcessingException {
this.expression = expressionProcessor;
try {
ExpressionProxy proxy = expressionProcessor.createProxyAssignmentExpression(ForExpression.ROOTEXPRESSION);
setNextExpression(ForExpression.ASSIGNMENT_RIGHT);
expression.accept(this);
return proxy;
} catch (ProcessingException e) {
// Handle the most common that make sense to be know distinctly and throw them instead of ProcessingException.
Throwable t = e.getCause();
if (t instanceof IllegalStateException)
throw (IllegalStateException) t;
else
throw e;
}
}
/**
* Set the next expression type. (i.e. the <code>forExpression</code> field of most of the create expression methods.
*
* @param nextExpression
*
* @see IExpression#createInfixExpression(int, int, int)
* @since 1.0.0
*/
protected final void setNextExpression(ForExpression nextExpression) {
this.nextExpression = nextExpression;
}
/**
* Get the next expression type. (i.e. the <code>forExpression</code> field of most of the create expression methods.
*
* @return
*
* @see IExpression#createInfixExpression(int, int, int)
* @since 1.0.0
*/
protected final ForExpression getNextExpression() {
return nextExpression;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTAnonymousClassDeclaration)
*/
public boolean visit(PTAnonymousClassDeclaration node) {
throw new IllegalArgumentException(MessageFormat.format(InstantiationBaseMessages.ParseTreeAllocationInstantiationVisitor_CannotProcessAnonymousDeclarations_EXC_, new Object[] {node.getDeclaration()}));
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTArrayAccess)
*/
public boolean visit(PTArrayAccess node) {
getExpression().createArrayAccess(getNextExpression(), node.getIndexes().size());
setNextExpression(ForExpression.ARRAYACCESS_ARRAY);
node.getArray().accept(this);
List idx = node.getIndexes();
int s = idx.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.ARRAYACCESS_INDEX);
((PTExpression) idx.get(i)).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTArrayCreation)
*/
public boolean visit(PTArrayCreation node) {
getExpression().createArrayCreation(getNextExpression(), node.getType(), node.getDimensions().size());
if (node.getDimensions().isEmpty()) {
node.getInitializer().accept(this); // Array initializer doesn't require a next expression.
} else {
List dims = node.getDimensions();
int s = dims.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.ARRAYCREATION_DIMENSION);
((PTExpression) dims.get(i)).accept(this);
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTArrayInitializer)
*/
public boolean visit(PTArrayInitializer node) {
getExpression().createArrayInitializer(node.getExpressions().size());
List exps = node.getExpressions();
int s = exps.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.ARRAYINITIALIZER_EXPRESSION);
((PTExpression) exps.get(i)).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTBooleanLiteral)
*/
public boolean visit(PTBooleanLiteral node) {
getExpression().createPrimitiveLiteral(getNextExpression(), node.isBooleanValue());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTCastExpression)
*/
public boolean visit(PTCastExpression node) {
getExpression().createCastExpression(getNextExpression(), node.getType());
setNextExpression(ForExpression.CAST_EXPRESSION);
node.getExpression().accept(this);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTCharacterLiteral)
*/
public boolean visit(PTCharacterLiteral node) {
getExpression().createPrimitiveLiteral(getNextExpression(), node.getCharValue());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTClassInstanceCreation)
*/
public boolean visit(PTClassInstanceCreation node) {
getExpression().createClassInstanceCreation(getNextExpression(), node.getType(), node.getArguments().size());
List args = node.getArguments();
int s = args.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.CLASSINSTANCECREATION_ARGUMENT);
((PTExpression) args.get(i)).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTConditionalExpression)
*/
public boolean visit(PTConditionalExpression node) {
getExpression().createConditionalExpression(getNextExpression());
setNextExpression(ForExpression.CONDITIONAL_CONDITION);
node.getCondition().accept(this);
setNextExpression(ForExpression.CONDITIONAL_TRUE);
node.getTrue().accept(this);
setNextExpression(ForExpression.CONDITIONAL_FALSE);
node.getFalse().accept(this);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTFieldAccess)
*/
public boolean visit(PTFieldAccess node) {
getExpression().createFieldAccess(getNextExpression(), node.getField(), node.getReceiver() != null);
if (node.getReceiver() != null) {
setNextExpression(ForExpression.FIELD_RECEIVER);
node.getReceiver().accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTInfixExpression)
*/
public boolean visit(PTInfixExpression node) {
getExpression().createInfixExpression(getNextExpression(), convertPTInfixOperatorToProxyInfixOperator(node.getOperator()), node.getExtendedOperands().size());
setNextExpression(ForExpression.INFIX_LEFT);
node.getLeftOperand().accept(this);
setNextExpression(ForExpression.INFIX_RIGHT);
node.getRightOperand().accept(this);
List extended = node.getExtendedOperands();
int s = extended.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.INFIX_EXTENDED);
((PTExpression) extended.get(i)).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTInstanceof)
*/
public boolean visit(PTInstanceof node) {
getExpression().createInstanceofExpression(getNextExpression(), node.getType());
setNextExpression(ForExpression.INSTANCEOF_VALUE);
node.getOperand().accept(this);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTInvalidExpression)
*/
public boolean visit(PTInvalidExpression node) {
throw new IllegalArgumentException(node.getMessage());
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTMethodInvocation)
*/
public boolean visit(PTMethodInvocation node) {
getExpression().createMethodInvocation(getNextExpression(), node.getName(), node.getReceiver() != null, node.getArguments().size());
if (node.getReceiver() != null) {
setNextExpression(ForExpression.METHOD_RECEIVER);
node.getReceiver().accept(this);
}
List args = node.getArguments();
int s = args.size();
for (int i = 0; i < s; i++) {
setNextExpression(ForExpression.METHOD_ARGUMENT);
((PTExpression) args.get(i)).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTName)
*/
public boolean visit(PTName node) {
// This is special in the PTName can only be used as a type receiver at this time.
getExpression().createTypeReceiver(node.getName());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTNullLiteral)
*/
public boolean visit(PTNullLiteral node) {
// This is special in the PTName can only be used as a type receiver at this time.
getExpression().createNull(getNextExpression());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTNumberLiteral)
*/
public boolean visit(PTNumberLiteral node) {
// It is assumed the tokens are trimmed.
String lit = node.getToken();
char lastChar = lit.charAt(lit.length()-1);
if (lastChar == 'l' || lastChar == 'L' ) {
// It is definitely a long.
// Using decode so that things like 0x3 will be parsed. parseLong won't recognize those.
getExpression().createPrimitiveLiteral(getNextExpression(), Long.decode(lit.substring(0, lit.length()-1)).longValue());
} else if (lastChar == 'F' || lastChar == 'f') {
// It is definitely a float.
getExpression().createPrimitiveLiteral(getNextExpression(), Float.parseFloat(lit.substring(0, lit.length()-1)));
} else if (lastChar == 'D' || lastChar == 'd') {
// It is definitely a double.
getExpression().createPrimitiveLiteral(getNextExpression(), Double.parseDouble(lit.substring(0, lit.length()-1)));
} else if (lit.indexOf('.') != -1 || lit.indexOf('e') != -1 || lit.indexOf('E') != -1) {
// It is definitely a double. (has a period or an exponent, but does not have an 'f' on the end is always a double).
getExpression().createPrimitiveLiteral(getNextExpression(), Double.parseDouble(lit.substring(0, lit.length())));
} else {
// Using decode so that things like 0x3 will be parsed. parseInt won't recognize those.
getExpression().createPrimitiveLiteral(getNextExpression(), Integer.decode(lit).intValue());
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTParenthesizedExpression)
*/
public boolean visit(PTParenthesizedExpression node) {
node.getExpression().accept(this); // For instantiation purposes, the parenthesis can be ignored.
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTPrefixExpression)
*/
public boolean visit(PTPrefixExpression node) {
getExpression().createPrefixExpression(getNextExpression(), convertPTPrefixOperatorToProxyPrefixOperator(node.getOperator()));
setNextExpression(ForExpression.PREFIX_OPERAND);
node.getExpression().accept(this);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTStringLiteral)
*/
public boolean visit(PTStringLiteral node) {
getExpression().createProxyExpression(getNextExpression(), getRegistry().getBeanProxyFactory().createBeanProxyWith(node.getLiteralValue()));
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTThisLiteral)
*/
public boolean visit(PTThisLiteral node) {
throw new IllegalArgumentException(InstantiationBaseMessages.ParseTreeAllocationInstantiationVisitor_CurrentlyThisNotSupported_EXC_);
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.instantiation.ParseVisitor#visit(org.eclipse.jem.internal.instantiation.PTTypeLiteral)
*/
public boolean visit(PTTypeLiteral node) {
getExpression().createTypeLiteral(getNextExpression(), node.getType());
return false;
}
}