| /******************************************************************************* |
| * 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; |
| } |
| |
| } |