| /******************************************************************************* |
| * 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: Expression.java,v $ |
| * $Revision: 1.15 $ $Date: 2005/11/11 15:49:30 $ |
| */ |
| package org.eclipse.jem.internal.proxy.core; |
| |
| import java.text.MessageFormat; |
| import java.util.*; |
| |
| import org.eclipse.jem.internal.proxy.initParser.tree.*; |
| |
| /** |
| * This is implementation of IExpression. It encapsulates much of the processing required |
| * into a common form that will be turned into simple push/pop/evaluate type of interaction with the |
| * actual other side. All registry specific implementations of IExpression must subclass this class. |
| * <p> |
| * It will maintain a stack of the expressions. As the expressions come in they will be stacked if not |
| * able to be executed immediately. The expressions come to this class in an outside to inside order, |
| * but they need to be processed in an inside-out order instead. |
| * <p> |
| * Subclasses will be used for the different types of proxy interfaces. The abstract methods will |
| * then be the simple interface. |
| * <p> |
| * It is not meant for subclasses to override the actual create expression methods because the processing the stack |
| * is very sensitive and must execute in the proper sequence. So the create methods are final for this reason. |
| * <p> |
| * This class is not thread-safe. |
| * <p> |
| * This class also has API of its own and can be used by customers for advanced usage. Those advanced API are |
| * listed on each method as to whether it is customer API or implementers API (i.e. API for implementers of |
| * expression subclasses to use). |
| * |
| * |
| * @since 1.0.0 |
| */ |
| public abstract class Expression implements IExpression { |
| |
| /* |
| * We have stack here, but rather than create a class that does the |
| * stack protocol, will simply have some private methods to do |
| * the same thing for the stack. (Note: Can't use java.util.Stack |
| * because that is a synchronized class, and don't want the overhead). |
| * |
| * The purpose of the stack is to stack up expressions that have not yet |
| * been evaluated. |
| * |
| * Each expression type will control the content of what it pushes and pops. |
| * The expression type will be the last thing it pushes so that on popping |
| * we know what kind of expression is now completed and ready for evaluation. |
| */ |
| private ArrayList controlStack = new ArrayList(30); |
| |
| protected final ProxyFactoryRegistry registry; |
| protected final IStandardBeanProxyFactory beanProxyFactory; |
| protected Boolean traceFlag; |
| |
| /** |
| * Answer whether trace has been explicitly set. |
| * This is not in the IExpression interface because it is for advanced users. |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| public boolean isTraceSet() { |
| return traceFlag != null; |
| } |
| |
| /** |
| * Answer if trace is on. If not explicitly set this will answer false. |
| * Use {@link Expression#isTraceSet()} first to determine if this |
| * should be called or not. |
| * This is not in the IExpression interface because it is for advanced users. |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| public boolean isTrace() { |
| return traceFlag != null ? traceFlag.booleanValue() : false; |
| } |
| |
| /** |
| * Explicitly set the trace flag. This will only be honoured before any |
| * expressions have been created. After that this will be ignored. |
| * The trace is initially set to use default. Once set it cannot be unset. |
| * This is not in the IExpression interface because it is for advanced users. |
| * @param trace |
| * |
| * @since 1.1.0 |
| */ |
| public void setTrace(boolean trace) { |
| traceFlag = Boolean.valueOf(trace); |
| } |
| |
| /** |
| * Push an object onto the control stack. |
| * |
| * @param o |
| * |
| * @since 1.0.0 |
| */ |
| protected final void push(Object o) { |
| controlStack.add(o); |
| } |
| |
| /** |
| * Pop an object off of the control stack |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| protected final Object pop() { |
| return controlStack.remove(controlStack.size()-1); |
| } |
| |
| /** |
| * Peek at an object from the control stack. <code>fromTop</code> is how far from the top of the stack to look. |
| * If it one, then it is the top entry, two is the next one down. Zero is an invalid value for the parameter. |
| * @param fromTop How far from the top to peek. <code>1</code> is the top, not zero. |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| protected final Object peek(int fromTop) { |
| // 1 means the top, 2 is the next one down. |
| return controlStack.get(controlStack.size()-fromTop); |
| } |
| |
| /* |
| * Expression type constants. |
| */ |
| |
| /* |
| * ARRAY ACCESS expression. |
| * The expression stack will have: |
| * IExpression.ARRAYACCESS_ARRAY |
| * IExpression.ARRAYACCESS_INDEX (for 1 to n times depending on index count) |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have |
| * ARRAYACCESS |
| * Integer(index count) |
| */ |
| private static final Integer ARRAYACCESS_INDEX_1 = new Integer(1); // Use in normal case of one index count. Saves object creation. |
| |
| /* |
| * ARRAY CREATION expression. |
| * The expression stack will have: |
| * ARRAYCREATION_INITIALIZER - if hasInitializer |
| * IExpression.ARRAYCREATION_DIMENSION (for 0 to n times depending on dimension count) |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have |
| * ARRAYCREATION |
| * type (either a string representing the type, or an IBeanProxyType representing the type). |
| * Integer(dimension count) (if zero then there is an initializer) |
| * |
| * |
| * Note: Array Initializer works with this in that it will peek into the value stack two entries down |
| * to find the type of array it should be creating. |
| */ |
| private static final Integer ARRAY_CREATION_DIMENSION_1 = new Integer(1); // Use in normal case of one dimension. Save object creation. |
| private static final Integer ARRAY_CREATION_DIMENSION_0 = new Integer(0); // Use in normal case of initializer. Save object creation. |
| private static final ForExpression ARRAY_INITIALIZER = new ExpressionEnum(Integer.MIN_VALUE+1, "Array Initializer Internal"); //$NON-NLS-1$ |
| |
| /* |
| * ARRAY INITIALIZER expression |
| * The expression stack will have: |
| * IExpression.ARRAYINITIALIZER_EXPRESSION (for n times depending on number of expressions count) |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have |
| * ARRAYINITIALIZER |
| * type (either a string representing the type, or an IBeanProxyType representing the type). |
| * I.e. if array being created is int[][], the value pushed here will be int[]. This is because when created |
| * the array will wind up with int[expressioncount][] in the end. |
| * Integer (expression count) |
| * |
| * Note: Imbedded Array Initializers works with this in that it will peek into the value stack two entries down |
| * to find the type of array it should be creating. |
| */ |
| private static final Integer ARRAYINITIALIZER_COUNT_0 = new Integer(0); // Use in normal case of empty array. Save object creation. |
| private static final Integer ARRAYINITIALIZER_COUNT_1 = new Integer(1); // Use in normal case of one element array. Save object creation. |
| private static final Integer ARRAYINITIALIZER_COUNT_2 = new Integer(2); // Use in normal case of two element array. Save object creation. |
| |
| /* |
| * CAST expression. |
| * The expression stack will have: |
| * IExpression.CAST_EXPRESSION |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * CAST |
| * type (either a string representing the type, or an IBeanProxyType representing the type). |
| */ |
| |
| /* |
| * CLASS INSTANCE CREATION expression. |
| * The expression stack will have: |
| * IExpression.CLASSINSTANCECREATION_ARGUMENT (for 0 to n times depending on argument count) |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have |
| * CLASSINSTANCECREATION |
| * type (either a string representing the type, or an IBeanProxyType representing the type). |
| * Integer(argument count) |
| * |
| * |
| * Note: Array Initializer works with this in that it will peek into the value stack two entries down |
| * to find the type of array it should be creating. |
| */ |
| private static final Integer CLASS_INSTANCE_CREATION_ARGUMENTS_1 = new Integer(1); // Use in normal case of one argument. Save object creation. |
| private static final Integer CLASS_INSTANCE_CREATION_ARGUMENTS_0 = new Integer(0); // Use in normal case of no arguments (default ctor). Save object creation. |
| |
| /* |
| * CONDITIONAL expression. |
| * Since this can cause skipping of expressions (e.g. if condition is false, then the true condition should not be evaluated), |
| * we need to have a process expression and process call to the other side for each expression so that it can |
| * determine if it should be ignored or not. |
| * |
| * The expression stack will have: |
| * IExpression.CONDITIONAL_CONDITION |
| * PROCESS_EXPRESSION |
| * IExpression.CONDITIONAL_TRUE |
| * PROCESS_EXPRESSION |
| * IExpression.CONDITIONAL_FALSE |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * CONDITIONAL |
| * CONDITIONAL_CONDITION |
| * CONDITIONAL |
| * CONDITIONAL_TRUE |
| * CONDITIONAL |
| * CONDITIONAL_FALSE |
| * |
| */ |
| |
| /* |
| * PREFIX expression. |
| * The expression stack will have: |
| * IExpression.PREFIX_OPERAND |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * PREFIX |
| * operator (using Integer prefix operator constants defined here) |
| */ |
| |
| /* |
| * INFIX expression. |
| * Since two types of infix operators (conditional and AND or) can cause skipping of expressions (e.g. once |
| * conditional and sees a false expression, the rest of the expressions are skipped and should not be evaluated), |
| * we need to have a process expression and process call to the other side for each expression so that it can |
| * determine if it should be ignored or not. |
| * |
| * The expression stack will have: |
| * IExpression.INFIX_LEFT |
| * PROCESS_EXPRESSION |
| * IExpression.INFIX_RIGHT |
| * PROCESS_EXPRESSION |
| * (for 0 to n times depending upon extended count) |
| * IExpression.INFIX_EXTENDED |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * INFIX |
| * operator (using Integer infix operator constants defined here) |
| * IN_LEFT |
| * (for (extendedCount) times) This will cover the right one and all but last extended |
| * INFIX |
| * operator (using Integer infix operator constants defined here) |
| * IN_OTHER |
| * INFIX |
| * operator (using Integer infix operator constants defined here) |
| * IN_LAST (this is covers either the right one if no extended, or the last extended) |
| */ |
| |
| /* |
| * INSTANCEOF expression. |
| * The expression stack will have: |
| * IExpression.INSTANCEOF_EXPRESSION |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * INSTANCEOF |
| * type (either a string representing the type, or an IBeanProxyType representing the type). |
| */ |
| |
| /* |
| * Field access expression. |
| * The expression stack will have: |
| * IExpression.FIELD_RECEIVER (if hasReceiver is true) |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * FIELDACCESS |
| * name (the name of the field) |
| * Boolean (true if has receiver) |
| */ |
| |
| /* |
| * Method invocation expression. |
| * The expression stack will have: |
| * IExpression.METHOD_RECEIVER (if hasReceiver is true) |
| * IExpression.METHOD_ARGUMENT (0 to n times for how many arguments). |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * METHODINVOCATION |
| * name (the name of the method) |
| * Boolean (true if has receiver) |
| * argCount (the number of arguments). |
| */ |
| private static final Integer METHOD_ARGUMENTS_1 = new Integer(1); // Use in normal case of one argument. Save object creation. |
| private static final Integer METHOD_ARGUMENTS_0 = new Integer(0); // Use in normal case of no arguments. Save object creation. |
| |
| |
| /* |
| * Assignment expression |
| * The expression stack will have: |
| * IExpression.ASSIGNMENT_RIGHT |
| * IExpression.ASSIGNMENT_LEFT |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * ASSIGNMENT |
| * left expression (variable reference) |
| * right expression |
| */ |
| |
| /* |
| * Assignment proxy expression |
| * The expression stack will have: |
| * IExpression.ASSIGNMENT_RIGHT |
| * PROCESS_EXPRESSION |
| * |
| * The value stack will have: |
| * ASSIGNMENT_PROXY |
| * expression proxy (an expression proxy) |
| */ |
| |
| /* |
| * Next valid for expression stack. This is kept as a stack also. |
| * As the expressions come in, the appropriate order (in reverse) |
| * of expression types will be pushed, and then popped as they |
| * come in. |
| * |
| * Since we can't have an array list of ints, will simulate the |
| * stack here. |
| */ |
| private ForExpression[] nextForExpressionStack = new ForExpression[30]; |
| private int nextForExpressionStackPos = -1; // Position of top entry in stack. |
| private boolean expressionValid = true; // Is the expression currently valid. |
| private String invalidMsg = null; // Msg for being invalid if default msg not sufficient. |
| private List expressionProxies; // List of expression proxies. The index of the proxy is its id. This list must never shrink in size. |
| |
| // A MarkEntry. To allow restore in case of error. |
| private static class MarkEntry { |
| public int markID; |
| public int controlStackPos; // Position of control stack at time of mark. |
| public int nextExpressionStackPos; // Position of nextForExpression stack at time of mark. |
| public int expressionProxiesPos; // Position of expressionProxies list at time of mark. |
| } |
| |
| private int highestMarkID = 0; // Next mark id. '0' is invalid, as in no marks. This is incremented for each new mark. Never decremented. |
| private MarkEntry currentMarkEntry; // Just a convienence to the current mark entry so no need to look into the list every time. |
| private List markEntries; // Stack of mark entries. |
| |
| // This class is here so we can add our special internal ForExpression: PROCESS_EXPRESSION. These are never used outside Expression. |
| private static class ExpressionEnum extends ForExpression { |
| |
| public ExpressionEnum(int value, String name) { |
| super(value, name); |
| } |
| |
| } |
| |
| // This is pushed onto the next expression stack, and when it is popped, then the expression is complete and ready to be pushed to the proxy side. |
| private static final ForExpression PROCESS_EXPRESSION = new ExpressionEnum(Integer.MIN_VALUE, "Process Expression"); //$NON-NLS-1$ |
| |
| // This is pushed onto the next expression stack for end block and will test if this there to make sure that it is being called correctly. |
| private static final ForExpression BLOCKEND_EXPRESSION = new ExpressionEnum(PROCESS_EXPRESSION.getValue()-2, "End Block Expression"); //$NON-NLS-1$ |
| |
| // This is pushed onto the next expression stack for end try and will test if this there to make sure that it is being called correctly. |
| private static final ForExpression TRYEND_EXPRESSION = new ExpressionEnum(BLOCKEND_EXPRESSION.getValue()-1, "End Try Expression"); //$NON-NLS-1$ |
| |
| // This is pushed onto the next expression stack for catch and will test if this there to make sure that it is being called correctly. |
| private static final ForExpression TRYCATCH_EXPRESSION = new ExpressionEnum(TRYEND_EXPRESSION.getValue()-1, "Catch Expression"); //$NON-NLS-1$ |
| |
| |
| // This is pushed onto the next expression stack for begin thread transfer and will test if this there to make sure that it is being called correctly. |
| private static final ForExpression THREADTRANSFER_EXPRESSION = new ExpressionEnum(TRYCATCH_EXPRESSION.getValue()-1, "Catch Expression"); //$NON-NLS-1$ |
| |
| // This is pushed onto the next expression stack for end subexpression and will test if this there to make sure that it is being called correctly. |
| private static final ForExpression SUBEXPRESSIONEND_EXPRESSION = new ExpressionEnum(THREADTRANSFER_EXPRESSION.getValue()-2, "End Subexpression"); //$NON-NLS-1$ |
| |
| /** |
| * Check the for expression, and if legal, set to the next valid for expression type, |
| * if it can. If the stack entry is ROOTEXPRESSION, and the forExpression is ROOTEXPRESSION, |
| * then the expression is allowed, but it is not popped. It must be popped later when appropriate. |
| * <p> |
| * This is for "block" expressions. We don't want to pop down the stack passed the ROOTEXPRESSION |
| * that got added by the create block until we get an end block. That allows root expressions to |
| * be added to the block without the stack popping up past the block start in the stack. |
| * |
| * @param forExpression |
| * @throws IllegalStateException |
| * |
| * @since 1.0.0 |
| */ |
| protected final void checkForExpression(ForExpression forExpression) throws IllegalStateException { |
| if (expressionValid) { |
| if (nextForExpressionStackPos == -1) |
| if (forExpression == ForExpression.ROOTEXPRESSION) |
| return; // valid. We are at the root (i.e. nothing is waiting). |
| else |
| ; // invalid. drop through |
| else if (nextForExpressionStack[nextForExpressionStackPos] == forExpression) { |
| // Valid, either the root expression matched (We don't implicitly pop those. That needs to be done explicitly). |
| // Or we matched non-root, those will be popped. |
| if (forExpression != ForExpression.ROOTEXPRESSION) { |
| popForExpression(); // Pop the stack since stack not a root expression. |
| } |
| return; |
| } |
| } else { |
| String expMsg = invalidMsg != null ? MessageFormat.format(ProxyMessages.Expression_InInvalidStateDueTo_EXC_, new Object[] {invalidMsg}) : ProxyMessages.Expression_InInvalidState_EXC_; |
| throw new IllegalStateException(expMsg); |
| } |
| |
| // If we got here, then invalid. |
| ForExpression expected = nextForExpressionStackPos >= 0 ? nextForExpressionStack[nextForExpressionStackPos] : ForExpression.ROOTEXPRESSION; |
| expressionValid = false; |
| throw new IllegalStateException(MessageFormat.format(ProxyMessages.Expression_TypeSentInInvalidOrder_EXC_, new Object[] {forExpression, expected})); |
| } |
| |
| /** |
| * Pop the top for expression, whatever it is. |
| * @throws IllegalStateException thrown if try to pop through through the current mark entry. The endMark is the only one who can do this. |
| * @since 1.1.0 |
| */ |
| protected final void popForExpression() throws IllegalStateException { |
| if (expressionValid && nextForExpressionStackPos >= 0) { |
| nextForExpressionStackPos--; |
| if (currentMarkEntry != null && nextForExpressionStackPos < currentMarkEntry.nextExpressionStackPos) { |
| nextForExpressionStackPos++; // Restore to what it was |
| throwInvalidMarkNesting(); |
| } |
| } |
| } |
| |
| /* |
| * @throws IllegalStateException |
| * |
| * @since 1.1.0 |
| */ |
| private void throwInvalidMarkNesting() throws IllegalStateException { |
| expressionValid = false; |
| throw new IllegalStateException(MessageFormat.format(ProxyMessages.Expression_InvalidMarkNesting, new Object[] {new Integer(currentMarkEntry != null ? currentMarkEntry.markID : 0)})); |
| } |
| |
| /** |
| * Peek into the for expression stack to see if the top entry is the passed in value. It will |
| * not pop the stack nor throw any exceptions. |
| * |
| * @param forExpression The top expression flag will be compared against this value. |
| * @return <code>true</code> if the top expression equals the parameter passed in. |
| * |
| * @since 1.0.0 |
| */ |
| protected final boolean peekForExpression(ForExpression forExpression) { |
| if (expressionValid) { |
| if (nextForExpressionStackPos == -1) |
| if (forExpression == ForExpression.ROOTEXPRESSION) |
| return true; // valid. We are at the root (i.e. nothing is waiting). |
| else |
| ; // invalid. drop through |
| else if (nextForExpressionStack[nextForExpressionStackPos] == forExpression) |
| return true; // Valid, the top expression matched. |
| } |
| return false; |
| } |
| |
| /** |
| * Mark this expression as now invalid. |
| */ |
| protected final void markInvalid() { |
| expressionValid = false; |
| } |
| |
| /** |
| * Mark this expression as now invalid, but supply a message to go with it. |
| * |
| * @param msg |
| * |
| * @since 1.0.0 |
| */ |
| protected final void markInvalid(String msg) { |
| invalidMsg = msg; |
| markInvalid(); |
| } |
| |
| public void close() { |
| nextForExpressionStackPos = -1; |
| controlStack.clear(); |
| if (expressionProxies != null) |
| markAllProxiesNotResolved(expressionProxies); // They weren't processed, close must of been called early. |
| expressionProxies = null; |
| markEntries = null; |
| expressionValid = false; |
| closeProxy(); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#isValid() |
| */ |
| public boolean isValid() { |
| return expressionValid; |
| } |
| |
| /* |
| * Check if the pending expression is ready for evaluation. |
| * It is complete if the next entry on the stack is a PROCESS_EXPRESSION |
| */ |
| private boolean expressionReady() { |
| if (nextForExpressionStackPos >= 0 && nextForExpressionStack[nextForExpressionStackPos] == PROCESS_EXPRESSION) { |
| checkForExpression(PROCESS_EXPRESSION); // pop it |
| return true; |
| } else |
| return false; |
| } |
| |
| /* |
| * Push the next expression type. |
| */ |
| private void pushForExpression(ForExpression nextExpression) { |
| if (++nextForExpressionStackPos >= nextForExpressionStack.length) { |
| // Increase stack size. |
| ForExpression[] newStack = new ForExpression[nextForExpressionStackPos*2]; // So room to grow without excessive allocations. |
| System.arraycopy(nextForExpressionStack, 0, newStack, 0, nextForExpressionStack.length); |
| nextForExpressionStack = newStack; |
| } |
| nextForExpressionStack[nextForExpressionStackPos] = nextExpression; |
| } |
| |
| /* |
| * Check if expression is complete, and if it is, process it. |
| */ |
| private void processExpression() { |
| while (expressionReady()) { |
| try { |
| // We've received all of the expressions for the expression, so process it. |
| int expType = ((InternalExpressionTypes) pop()).getValue(); |
| switch (expType) { |
| case InternalExpressionTypes.CAST_EXPRESSION_VALUE: |
| pushCastToProxy((IProxyBeanType) pop()); |
| break; |
| case InternalExpressionTypes.INSTANCEOF_EXPRESSION_VALUE: |
| pushInstanceofToProxy((IProxyBeanType) pop()); |
| break; |
| case InternalExpressionTypes.PREFIX_EXPRESSION_VALUE: |
| pushPrefixToProxy((PrefixOperator)pop()); |
| break; |
| case InternalExpressionTypes.INFIX_EXPRESSION_VALUE: |
| pushInfixToProxy((InfixOperator) pop(), (InternalInfixOperandType) pop()); |
| break; |
| case InternalExpressionTypes.ARRAY_ACCESS_EXPRESSION_VALUE: |
| pushArrayAccessToProxy(((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.ARRAY_CREATION_EXPRESSION_VALUE: |
| pushArrayCreationToProxy((IProxyBeanType) pop(), ((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.ARRAY_INITIALIZER_EXPRESSION_VALUE: |
| pushArrayInitializerToProxy((IProxyBeanType) pop(), ((Integer) pop()).intValue(), ((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.CLASS_INSTANCE_CREATION_EXPRESSION_VALUE: |
| pushClassInstanceCreationToProxy((IProxyBeanType) pop(), ((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.FIELD_ACCESS_EXPRESSION_VALUE: |
| pushFieldAccessToProxy(pop(), ((Boolean) pop()).booleanValue()); |
| break; |
| case InternalExpressionTypes.METHOD_EXPRESSION_VALUE: |
| pushMethodInvocationToProxy(pop(), ((Boolean) pop()).booleanValue(), ((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.CONDITIONAL_EXPRESSION_VALUE: |
| pushConditionalToProxy((InternalConditionalOperandType) pop()); |
| break; |
| case InternalExpressionTypes.ASSIGNMENT_PROXY_EXPRESSION_VALUE: |
| pushAssignmentToProxy((ExpressionProxy) pop()); |
| break; |
| case InternalExpressionTypes.ASSIGNMENT_EXPRESSION_VALUE: |
| pushAssignmentToProxy(); |
| break; |
| case InternalExpressionTypes.BLOCK_END_EXPRESSION_VALUE: |
| pushBlockEndToProxy(((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.TRY_END_EXPRESSION_VALUE: |
| pushTryEndToProxy(((Integer) pop()).intValue()); |
| break; |
| case InternalExpressionTypes.THROW_EXPRESSION_VALUE: |
| pushThrowToProxy(); |
| break; |
| case InternalExpressionTypes.IF_TEST_EXPRESSION_VALUE: |
| pushIfTestToProxy(); |
| break; |
| case InternalExpressionTypes.IF_ELSE_EXPRESSION_VALUE: |
| pushIfElseToProxy((InternalIfElseOperandType) pop()); |
| break; |
| case InternalExpressionTypes.SUBEXPRESSION_END_EXPRESSION_VALUE: |
| pushSubexpressionEndToProxy(((Integer) pop()).intValue()); |
| break; |
| default: |
| internalProcessUnknownExpressionType(expType); |
| break; |
| } |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| } |
| |
| |
| private void internalProcessUnknownExpressionType(int expressionType) throws IllegalArgumentException { |
| if (!processUnknownExpressionType(expressionType)) |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * An unknown expression type was found in the processing of expression stack. Subclasses can override |
| * to process new types of expressions. |
| * <p> |
| * Overrides must return <code>true</code> if they processed the expression type. If they return <code>false</code> |
| * it means they didn't understand it either and we should do default processing for unknow type. |
| * @param expressionType |
| * @return <code>true</code> if type was processed, <code>false</code> if not known by subclass either. |
| * |
| * @since 1.0.0 |
| */ |
| protected boolean processUnknownExpressionType(int expressionType) { |
| return false; |
| } |
| |
| /** |
| * Create the expression. |
| * |
| * @param registry |
| * |
| * @since 1.0.0 |
| */ |
| protected Expression(ProxyFactoryRegistry registry) { |
| this.registry = registry; |
| this.beanProxyFactory = this.registry.getBeanProxyFactory(); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#getRegistry() |
| */ |
| public ProxyFactoryRegistry getRegistry() { |
| return registry; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#invokeExpression() |
| */ |
| public final void invokeExpression() throws ThrowableProxy, IllegalStateException, NoExpressionValueException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); // We are at the root. |
| popForExpression(); // Get rid of any intermediate roots. |
| checkForExpression(ForExpression.ROOTEXPRESSION); // We should be at true root now. We don't have more than one intermediate root pushed in sequence. |
| List proxies = expressionProxies; |
| expressionProxies = null; |
| pushInvoke(processExpressionProxyCallbacks(proxies), proxies); |
| } finally { |
| markInvalid(); // Mark invalid so any new calls after this will fail. |
| close(); |
| } |
| } |
| |
| /* |
| * Process the expression proxy callbacks, if any. |
| * @return the number of proxies that have callbacks. |
| */ |
| private int processExpressionProxyCallbacks(List proxies) { |
| if (proxies != null) { |
| // Strip list down to only those with callbacks and send on. |
| int proxiesWithCallbacks = 0; |
| for (ListIterator eps = proxies.listIterator(); eps.hasNext();) { |
| ExpressionProxy proxy = (ExpressionProxy) eps.next(); |
| if (!proxy.hasListeners()) |
| eps.set(null); // Remove it from the list. No one cares. |
| else |
| proxiesWithCallbacks++; |
| } |
| return proxiesWithCallbacks; |
| } |
| return 0; |
| } |
| |
| /** |
| * Called to validate this is a valid proxy for this expression. This could happen |
| * if a proxy from another expression is sent to this expression. If the proxy |
| * is a bean proxy or is an expression proxy for this expression, then this |
| * just returns. Else it will throw the {@link IllegalArgumentException}. |
| * @param proxy |
| * @throws IllegalArgumentException if the proxy is an expression proxy for another expression. |
| * |
| * @since 1.1.0.1 |
| */ |
| private void validateProxy(IProxy proxy) throws IllegalArgumentException { |
| if (proxy != null && (proxy.isExpressionProxy() && ((ExpressionProxy) proxy).getExpression() != this)) |
| throw new IllegalArgumentException(ProxyMessages.Expression_InvalidProxy); |
| } |
| |
| /** |
| * Called by subclass to fill in the value of an expression proxy. See {@link Expression#pullProxyValue(int, List))} for an example of who would call it. |
| * @param ep |
| * @param beanproxy |
| * |
| * @since 1.1.0 |
| */ |
| protected void fireProxyResolved(ExpressionProxy ep, IBeanProxy beanproxy) { |
| ep.fireResolved(beanproxy); |
| } |
| |
| /** |
| * Called by subclass to fire proxy was not resolved. See {@link Expression#pullProxyValue(int, List))} for an example of who would call it. |
| * @param ep |
| * |
| * @since 1.1.0 |
| */ |
| protected void fireProxyNotResolved(ExpressionProxy ep) { |
| ep.fireNotResolved(); |
| } |
| |
| /** |
| * Called by subclass to fire proxy resolved to a void return type. See {@link Expression#pullProxyValue(int, List))} for an example of who would call it. |
| * @param ep |
| * |
| * @since 1.1.0 |
| */ |
| protected void fireProxyVoid(ExpressionProxy ep) { |
| ep.fireVoidResolved(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#getExpressionValue() |
| */ |
| public final IBeanProxy getExpressionValue() throws ThrowableProxy, NoExpressionValueException, IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); // We are at the root. |
| popForExpression(); // Get rid of any intermediate roots. |
| checkForExpression(ForExpression.ROOTEXPRESSION); // We should be at true root now. We don't have more than one intermediate root pushed in sequence. |
| List proxies = expressionProxies; |
| expressionProxies = null; |
| return pullProxyValue(processExpressionProxyCallbacks(proxies), proxies); // Get the top value. |
| } finally { |
| markInvalid(); // Mark invalid so any new calls after this will fail. |
| close(); |
| } |
| } |
| |
| |
| /** |
| * Mark the list of proxies as not resolved. |
| * |
| * @since 1.1.0 |
| */ |
| protected void markAllProxiesNotResolved(List proxies) { |
| if (proxies != null) { |
| for (ListIterator eps = proxies.listIterator(); eps.hasNext();) { |
| ExpressionProxy proxy = (ExpressionProxy) eps.next(); |
| if (proxy != null && proxy.hasListeners()) |
| fireProxyNotResolved(proxy); |
| } |
| } |
| } |
| |
| private int blockNumber = -1; // Current block number. This is always incrementing. |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createBlockBegin() |
| */ |
| public final int createBlockBegin() throws IllegalStateException { |
| try { |
| // Blocks are special, they can be anywhere at root, of could be the true or else clause of an if/else. |
| if (peekForExpression(ForExpression.ROOTEXPRESSION)) |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| else if (peekForExpression(ForExpression.IF_TRUE)) |
| checkForExpression(ForExpression.IF_TRUE); |
| else |
| checkForExpression(ForExpression.IF_ELSE); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(BLOCKEND_EXPRESSION); |
| pushForExpression(ForExpression.ROOTEXPRESSION); |
| |
| pushBlockBeginToProxy(++blockNumber); |
| push(new Integer(blockNumber)); |
| push(InternalExpressionTypes.BLOCK_END_EXPRESSION); |
| processExpression(); |
| return blockNumber; |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createBlockBreak(int) |
| */ |
| public final void createBlockBreak(int blockNumber) throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| pushBlockBreakToProxy(blockNumber); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createBlockEnd() |
| */ |
| public final void createBlockEnd() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since block is done. |
| checkForExpression(BLOCKEND_EXPRESSION); // This needs to be next for it to be valid. |
| processExpression(); // Now let it handle the previously pushed end block, containing the block number being ended. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createArrayAccess(int, int) |
| */ |
| public final void createArrayAccess(ForExpression forExpression, int indexCount) { |
| try { |
| checkForExpression(forExpression); |
| pushForExpression(PROCESS_EXPRESSION); |
| int i = indexCount; |
| while (i-- > 0) |
| pushForExpression(ForExpression.ARRAYACCESS_INDEX); |
| pushForExpression(ForExpression.ARRAYACCESS_ARRAY); |
| |
| push(indexCount == 1 ? ARRAYACCESS_INDEX_1 : new Integer(indexCount)); |
| push(InternalExpressionTypes.ARRAY_ACCESS_EXPRESSION); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createArrayCreation(int, java.lang.String, int) |
| */ |
| public final void createArrayCreation(ForExpression forExpression, String type, int dimensionExpressionCount) |
| throws IllegalStateException { |
| pushArrayCreation(forExpression, getProxyBeanType(type), dimensionExpressionCount); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createArrayCreation(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyBeanType, int) |
| */ |
| public final void createArrayCreation(ForExpression forExpression, IProxyBeanType type, int dimensionExpressionCount) |
| throws IllegalStateException, IllegalArgumentException { |
| pushArrayCreation(forExpression, type, dimensionExpressionCount); |
| } |
| |
| private void pushArrayCreation(ForExpression forExpression, IProxyBeanType type, int dimensionExpressionCount) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| validateProxy(type); |
| switch (dimensionExpressionCount) { |
| case 0: |
| push(ARRAY_CREATION_DIMENSION_0); |
| break; |
| case 1: |
| push(ARRAY_CREATION_DIMENSION_1); |
| break; |
| default: |
| push(new Integer(dimensionExpressionCount)); |
| break; |
| } |
| push(type); |
| push(InternalExpressionTypes.ARRAY_CREATION_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| if (dimensionExpressionCount == 0) |
| pushForExpression(ARRAY_INITIALIZER); |
| else { |
| while (dimensionExpressionCount-- > 0) |
| pushForExpression(ForExpression.ARRAYCREATION_DIMENSION); |
| } |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createArrayInitializer(int) |
| */ |
| public final void createArrayInitializer(int expressionCount) throws IllegalStateException { |
| try { |
| // This is special, we could be waiting for an array initializer or an array initializer expression. |
| // We will peek to see what it is and handle it. |
| if (peekForExpression(ARRAY_INITIALIZER)) |
| checkForExpression(ARRAY_INITIALIZER); |
| else |
| checkForExpression(ForExpression.ARRAYINITIALIZER_EXPRESSION); |
| |
| // At this point in time that stack may either have: |
| // array_type, array_creation |
| // strip_count, array_type, array_initializer |
| // So we can get the array type from peek(2), and get the command type from peek(1). |
| // Then if the command type is array_creation, strip_count will be inited to 0, while |
| // else it will be inited to peek(3). From that we can increment the strip_count to |
| // use for this initializer. |
| // |
| // We need to peek here because we will be adding various pushes to the stack and we |
| // need to get the info while it is still at the top of the stack. |
| Object arrayType = peek(2); |
| int stripCount = 0; |
| if (peek(1) == InternalExpressionTypes.ARRAY_INITIALIZER_EXPRESSION) |
| stripCount = ((Integer) peek(3)).intValue(); |
| |
| switch (expressionCount) { |
| case 0: |
| push(ARRAYINITIALIZER_COUNT_0); |
| break; |
| case 1: |
| push(ARRAYINITIALIZER_COUNT_1); |
| break; |
| case 2: |
| push(ARRAYINITIALIZER_COUNT_2); |
| break; |
| default: |
| push(new Integer(expressionCount)); |
| break; |
| } |
| |
| if (arrayType instanceof String) { |
| String at = (String) arrayType; |
| int i = at.lastIndexOf("[]"); //$NON-NLS-1$ |
| if (i == -1) |
| throw new IllegalArgumentException(MessageFormat.format( |
| ProxyMessages.Expression_ArrayTypeNotAnArray_EXC_, new Object[] { arrayType})); |
| arrayType = getProxyBeanType(at); |
| } else if (!(arrayType instanceof IProxyBeanType)) { |
| throw new IllegalArgumentException(MessageFormat.format( |
| ProxyMessages.Expression_ArrayTypeNotAnArray_EXC_, new Object[] { arrayType})); |
| } |
| push(new Integer(++stripCount)); |
| push(arrayType); |
| push(InternalExpressionTypes.ARRAY_INITIALIZER_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| while (expressionCount-- > 0) |
| pushForExpression(ForExpression.ARRAYINITIALIZER_EXPRESSION); |
| |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createCastExpression(int, java.lang.String) |
| * A cast expression has one nested expression. |
| */ |
| public final void createCastExpression(ForExpression forExpression, String type) throws IllegalStateException { |
| pushCast(forExpression, getProxyBeanType(type)); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createCastExpression(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyBeanType) |
| */ |
| public final void createCastExpression(ForExpression forExpression, IProxyBeanType type) throws IllegalStateException, IllegalArgumentException { |
| pushCast(forExpression, type); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * Push for a cast. |
| */ |
| private void pushCast(ForExpression forExpression, IProxyBeanType type) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| validateProxy(type); |
| push(type); |
| push(InternalExpressionTypes.CAST_EXPRESSION); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.CAST_EXPRESSION); // The next expression must be for the cast expression. |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createClassInstanceCreation(int, java.lang.String, int) |
| */ |
| public final void createClassInstanceCreation(ForExpression forExpression, String type, int argumentCount) |
| throws IllegalStateException { |
| pushClassInstanceCreation(forExpression, getProxyBeanType(type), argumentCount); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createClassInstanceCreation(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyBeanType, int) |
| */ |
| public final void createClassInstanceCreation(ForExpression forExpression, IProxyBeanType type, int argumentCount) |
| throws IllegalStateException, IllegalArgumentException { |
| pushClassInstanceCreation(forExpression, type, argumentCount); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * Push for a class instance creation |
| */ |
| private void pushClassInstanceCreation(ForExpression forExpression, IProxyBeanType type, int argumentCount) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| validateProxy(type); |
| switch (argumentCount) { |
| case 0: |
| push(CLASS_INSTANCE_CREATION_ARGUMENTS_0); |
| break; |
| case 1: |
| push(CLASS_INSTANCE_CREATION_ARGUMENTS_1); |
| break; |
| default: |
| push(new Integer(argumentCount)); |
| break; |
| } |
| push(type); |
| push(InternalExpressionTypes.CLASS_INSTANCE_CREATION_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| while (argumentCount-- > 0) |
| pushForExpression(ForExpression.CLASSINSTANCECREATION_ARGUMENT); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createConditionalExpression(int) |
| */ |
| public final void createConditionalExpression(ForExpression forExpression) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.CONDITIONAL_FALSE); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.CONDITIONAL_TRUE); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.CONDITIONAL_CONDITION); |
| |
| push(InternalConditionalOperandType.CONDITIONAL_FALSE); |
| push(InternalExpressionTypes.CONDITIONAL_EXPRESSION); |
| push(InternalConditionalOperandType.CONDITIONAL_TRUE); |
| push(InternalExpressionTypes.CONDITIONAL_EXPRESSION); |
| push(InternalConditionalOperandType.CONDITIONAL_TEST); |
| push(InternalExpressionTypes.CONDITIONAL_EXPRESSION); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createFieldAccess(int, java.lang.String, boolean) |
| */ |
| public final void createFieldAccess(ForExpression forExpression, String fieldName, boolean hasReceiver) throws IllegalStateException, IllegalArgumentException { |
| try { |
| // Only for string fieldnames is this invalid when no receiver because no way to determine receiver. (Don't handle implicit "this" yet for fields). |
| // For the accessor that takes a IFieldProxy we can get away with no receiver because the field proxy can determine if static or not, and if not |
| // static it will fail at evaluation time. |
| if (!hasReceiver) |
| throw new IllegalArgumentException(MessageFormat.format( |
| ProxyMessages.Expression_CannotHandleNoReceiveOnFieldAccess_EXC_, new Object[] { fieldName})); |
| pushFieldAccess(forExpression, fieldName, hasReceiver); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createIfElse(boolean) |
| */ |
| public final void createIfElse(boolean hasElseClause) throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| if (hasElseClause) { |
| pushForExpression(ForExpression.IF_ELSE); |
| } |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.IF_TRUE); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.IF_CONDITION); |
| |
| // We still push an else clause so that we know when finished. We don't have a pushForExpression for it because there |
| // won't be any. But the else clause processing will be on the push stack so that we can clean up when end of if stmt occurs. |
| push(InternalIfElseOperandType.ELSE_CLAUSE); |
| push(InternalExpressionTypes.IF_ELSE_EXPRESSION); |
| |
| push(InternalIfElseOperandType.TRUE_CLAUSE); |
| push(InternalExpressionTypes.IF_ELSE_EXPRESSION); |
| push(InternalExpressionTypes.IF_TEST_EXPRESSION); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * Push the field access. |
| * @param forExpression |
| * @param field String if field name, or IProxyField. |
| * @param hasReceiver |
| * @throws IllegalAccessException |
| * |
| * @since 1.1.0 |
| */ |
| private void pushFieldAccess(ForExpression forExpression, Object field, boolean hasReceiver) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| push(hasReceiver ? Boolean.TRUE : Boolean.FALSE); // We have a receiver |
| push(field); |
| push(InternalExpressionTypes.FIELD_ACCESS_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| if (hasReceiver) |
| pushForExpression(ForExpression.FIELD_RECEIVER); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createInfixExpression(int, int, int) |
| */ |
| public final void createInfixExpression(ForExpression forExpression, InfixOperator operator, int extendedOperandCount) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| push(InternalInfixOperandType.INFIX_LAST_OPERAND); |
| push(operator); |
| push(InternalExpressionTypes.INFIX_EXPRESSION); |
| int i = extendedOperandCount; |
| while (i-- > 0) { |
| push(InternalInfixOperandType.INFIX_OTHER_OPERAND); |
| push(operator); |
| push(InternalExpressionTypes.INFIX_EXPRESSION); |
| } |
| push(InternalInfixOperandType.INFIX_LEFT_OPERAND); |
| push(operator); |
| push(InternalExpressionTypes.INFIX_EXPRESSION); |
| |
| i = extendedOperandCount; |
| while (i-- > 0) { |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.INFIX_EXTENDED); |
| } |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.INFIX_RIGHT); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.INFIX_LEFT); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createInstanceofExpression(int, java.lang.String) |
| */ |
| public final void createInstanceofExpression(ForExpression forExpression, String type) throws IllegalStateException { |
| pushInstanceof(forExpression, getProxyBeanType(type)); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createInstanceofExpression(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyBeanType) |
| */ |
| public final void createInstanceofExpression(ForExpression forExpression, IProxyBeanType type) throws IllegalStateException, IllegalArgumentException { |
| pushInstanceof(forExpression, type); // Push this onto the local stack to wait for completion. |
| } |
| |
| /* |
| * Push for a cast. |
| */ |
| private void pushInstanceof(ForExpression forExpression, IProxyBeanType type) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| validateProxy(type); |
| push(type); |
| push(InternalExpressionTypes.INSTANCEOF_EXPRESSION); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.INSTANCEOF_VALUE); // The next expression must be for the instance of expression. |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createMethodInvocation(int, java.lang.String, boolean, int) |
| */ |
| public final void createMethodInvocation(ForExpression forExpression, String name, boolean hasReceiver, int argumentCount) |
| throws IllegalStateException, IllegalArgumentException { |
| try { |
| // Only for string methodnames is this invalid when no receiver because no way to determine receiver. (Don't handle implicit "this" yet for methods). |
| // For the accessor that takes a IFieldProxy we can get away with no receiver because the field proxy can determine if static or not, and if not |
| // static it will fail at evaluation time. |
| if (!hasReceiver) |
| throw new IllegalArgumentException(MessageFormat.format( |
| ProxyMessages.Expression_MethodsNeedReceiver_EXC_, new Object[] { name})); |
| |
| pushMethodInvocation(forExpression, name, hasReceiver, argumentCount); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /** |
| * @param forExpression |
| * @param method String for method name, IMethodProxy otherwise. |
| * @param hasReceiver |
| * @param argumentCount |
| * @throws ThrowableProxy |
| * @throws NoExpressionValueException |
| * |
| * @since 1.1.0 |
| */ |
| private void pushMethodInvocation(ForExpression forExpression, Object method, boolean hasReceiver, int argumentCount) throws IllegalArgumentException, IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| switch (argumentCount) { |
| case 0: |
| push(METHOD_ARGUMENTS_0); |
| break; |
| case 1: |
| push(METHOD_ARGUMENTS_1); |
| break; |
| default: |
| push(new Integer(argumentCount)); |
| break; |
| } |
| push(hasReceiver ? Boolean.TRUE : Boolean.FALSE); |
| push(method); |
| push(InternalExpressionTypes.METHOD_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| while (argumentCount-- > 0) |
| pushForExpression(ForExpression.METHOD_ARGUMENT); |
| if (hasReceiver) |
| pushForExpression(ForExpression.METHOD_RECEIVER); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrefixExpression(int, org.eclipse.jem.internal.proxy.initParser.tree.PrefixOperator) |
| */ |
| public final void createPrefixExpression(ForExpression forExpression, PrefixOperator operator) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| push(operator); |
| push(InternalExpressionTypes.PREFIX_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.PREFIX_OPERAND); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /** |
| * Create a new instance using the initialization string. The result must be compatible with the |
| * given type. This is not on the IExpression interface because it is not for use of regular |
| * customers. It is here for the allocation processer to create entries that are just strings. |
| * <p> |
| * This is not customer advanced API. This API for the implementers of registries and expression subclasses. |
| * |
| * @param forExpression |
| * @param initializationString |
| * @param type |
| * @throws IllegalStateException |
| * @throws IllegalArgumentException |
| * |
| * @since 1.1.0 |
| */ |
| public final void createNewInstance(ForExpression forExpression, String initializationString, IProxyBeanType type) throws IllegalStateException, IllegalArgumentException{ |
| try { |
| checkForExpression(forExpression); |
| validateProxy(type); |
| pushNewInstanceToProxy(initializationString, type); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createNull(int) |
| */ |
| public final void createNull(ForExpression forExpression) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(null); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTypeLiteral(int, java.lang.String) |
| */ |
| public final void createTypeLiteral(ForExpression forExpression, String type) throws IllegalStateException { |
| createProxyExpression(forExpression, getProxyBeanType(type)); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTypeReceiver(java.lang.String) |
| */ |
| public final void createTypeReceiver(String type) throws IllegalStateException { |
| pushTypeReceiver(getProxyBeanType(type)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTypeReceiver(org.eclipse.jem.internal.proxy.core.IProxyBeanType) |
| */ |
| public final void createTypeReceiver(IProxyBeanType type) throws IllegalStateException, IllegalArgumentException { |
| validateProxy(type); |
| pushTypeReceiver(type); |
| } |
| |
| /* |
| * Push for a type receiver. |
| * @param type |
| * |
| * @since 1.0.0 |
| */ |
| private void pushTypeReceiver(IProxyBeanType type) throws IllegalStateException { |
| try { |
| // This is special because type receivers are only valid as the receiver for a field access or a method access. |
| // Since each has a different forExpression we need to test for one or the other. It doesn't make any difference |
| // which one it is, but it must be one or the other. |
| if (peekForExpression(ForExpression.FIELD_RECEIVER)) |
| checkForExpression(ForExpression.FIELD_RECEIVER); |
| else |
| checkForExpression(ForExpression.METHOD_RECEIVER); |
| |
| pushTypeReceiverToProxy(type); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * For all of the primitive types we will be creating a IBeanProxy for them. That is because that |
| * would be the expected result of the expression, and no need to get the other side involved. |
| */ |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, boolean) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, boolean value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, char) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, char value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, byte) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, byte value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, double) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, double value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, float) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, float value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, int) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, int value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, long) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, long value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createPrimitiveLiteral(int, short) |
| */ |
| public final void createPrimitiveLiteral(ForExpression forExpression, short value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createStringLiteral(int, java.lang.String) |
| */ |
| public final void createStringLiteral(ForExpression forExpression, String value) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| pushToProxy(beanProxyFactory.createBeanProxyWith(value)); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createProxyExpression(int, org.eclipse.jem.internal.proxy.core.IProxy) |
| */ |
| public final void createProxyExpression(ForExpression forExpression, IProxy proxy) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| validateProxy(proxy); |
| pushToProxy(proxy); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createAssignmentExpression(int) |
| */ |
| public final void createAssignmentExpression(ForExpression forExpression) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| push(InternalExpressionTypes.ASSIGNMENT_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.ASSIGNMENT_RIGHT); |
| pushForExpression(ForExpression.ASSIGNMENT_LEFT); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createAssignmentExpression(int) |
| */ |
| public final ExpressionProxy createProxyAssignmentExpression(ForExpression forExpression) throws IllegalStateException { |
| try { |
| checkForExpression(forExpression); |
| ExpressionProxy proxy = allocateExpressionProxy(NORMAL_EXPRESSION_PROXY); |
| push(proxy); |
| push(InternalExpressionTypes.ASSIGNMENT_PROXY_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.ASSIGNMENT_RIGHT); |
| processExpression(); // See if previous expression is ready for processing. |
| return proxy; |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /** |
| * Called by registries to create an expression proxy for a bean type. It is not in the interface because it should |
| * only be called by the proxy registry to create an expression proxy. It shouldn't be called outside of the registries |
| * because there may already exist in the registry the true IBeanTypeProxy, and that one should be used instead. |
| * <p> |
| * This is not customer advanced API. This API for the implementers of registries and expression subclasses. |
| * |
| * @param typeName |
| * @return expression proxy that is hooked up and will notify when resolved. It can be called at any time. The resolution will occur at this point in the |
| * execution stack, but since it will not interfere with the stack this is OK, other than it could throw a ClassNotFoundException on the |
| * execution. |
| * |
| * @since 1.1.0 |
| */ |
| public final IProxyBeanType createBeanTypeExpressionProxy(String typeName) { |
| IBeanTypeExpressionProxy proxy = (IBeanTypeExpressionProxy) allocateExpressionProxy(BEANTYPE_EXPRESSION_PROXY); |
| proxy.setTypeName(typeName); |
| // This can be sent at any time. It doesn't matter what is on the expression stack. It will be sent to be resolved immediately. |
| pushBeanTypeToProxy(proxy); |
| return proxy; |
| } |
| |
| /** |
| * Called by registries to create an expression proxy for a method. It is not in the interface because it should |
| * only be called by the proxy registry to create an expression proxy. It shouldn't be called outside of the registries |
| * because there may already exist in the registry the true IMethodProxy, and that one should be used instead. |
| * <p> |
| * This is not customer advanced API. This API for the implementers of registries and expression subclasses. |
| * |
| * @param declaringType |
| * @param methodName |
| * @param parameterTypes parameter types or <code>null</code> if no parameter types. |
| * @return |
| * |
| * @throws IllegalArgumentException |
| * @since 1.1.0 |
| */ |
| public final IProxyMethod createMethodExpressionProxy(IProxyBeanType declaringType, String methodName, IProxyBeanType[] parameterTypes) throws IllegalArgumentException{ |
| validateProxy(declaringType); |
| if (parameterTypes != null && parameterTypes.length > 0) { |
| for (int i = 0; i < parameterTypes.length; i++) { |
| validateProxy(parameterTypes[i]); |
| } |
| } |
| ExpressionProxy proxy = allocateExpressionProxy(METHOD_EXPRESSION_PROXY); |
| // This can be sent at any time. It doesn't matter what is on the expression stack. It will be sent to be resolved immediately. |
| pushMethodToProxy(proxy, declaringType, methodName, parameterTypes); |
| return (IProxyMethod) proxy; |
| } |
| |
| /** |
| * Called by registries to create an expression proxy for a field. It is not in the interface because it should |
| * only be called by the proxy registry to create an expression proxy. It shouldn't be called outside of the registries |
| * because there may already exist in the registry the true IFieldProxy, and that one should be used instead. |
| * <p> |
| * This is not customer advanced API. This API for the implementers of registries and expression subclasses. |
| * |
| * @param declaringType |
| * @param fieldName |
| * @return |
| * |
| * @throws IllegalArgumentException |
| * @since 1.1.0 |
| */ |
| public final IProxyField createFieldExpressionProxy(IProxyBeanType declaringType, String fieldName) throws IllegalArgumentException { |
| validateProxy(declaringType); |
| ExpressionProxy proxy = allocateExpressionProxy(FIELD_EXPRESSION_PROXY); |
| // This can be sent at any time. It doesn't matter what is on the expression stack. It will be sent to be resolved immediately. |
| pushFieldToProxy(proxy, declaringType, fieldName); |
| return (IProxyField) proxy; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createProxyReassignmentExpression(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.ExpressionProxy) |
| */ |
| public final void createProxyReassignmentExpression(ForExpression forExpression, ExpressionProxy proxy) throws IllegalStateException, IllegalArgumentException { |
| try { |
| checkForExpression(forExpression); |
| if (!proxy.isValidForReassignment()) |
| throw new IllegalArgumentException(MessageFormat.format(ProxyMessages.Expression_CreateProxyReassignmentExpression_InvalidForReassignment_EXC_, new Object[]{proxy.toString()})); |
| push(proxy); |
| push(InternalExpressionTypes.ASSIGNMENT_PROXY_EXPRESSION); |
| |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.ASSIGNMENT_RIGHT); |
| processExpression(); // See if previous expression is ready for processing. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| protected static final int NORMAL_EXPRESSION_PROXY = 0; |
| protected static final int BEANTYPE_EXPRESSION_PROXY = 1; |
| protected static final int METHOD_EXPRESSION_PROXY = 2; |
| protected static final int FIELD_EXPRESSION_PROXY = 3; |
| /** |
| * Allocate a new ExpressionProxy |
| * @return new ExpressionProxy. |
| * |
| * @since 1.1.0 |
| */ |
| protected final ExpressionProxy allocateExpressionProxy(int proxyType) { |
| if (expressionProxies == null) |
| expressionProxies = new ArrayList(); |
| // It is very important that this always creates a proxy id that is greater than all previous. This is |
| // so that it can be assured that proxies will be resolved in order of creation. |
| // Currently this is done here by using expressionProxies.size(). |
| ExpressionProxy proxy = createExpressionProxy(proxyType, expressionProxies.size()); |
| expressionProxies.add(proxy); |
| return proxy; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createFieldAccess(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyField, boolean) |
| */ |
| public final void createFieldAccess(ForExpression forExpression, IProxyField fieldProxy, boolean hasReceiver) throws IllegalStateException, IllegalArgumentException { |
| validateProxy(fieldProxy); |
| pushFieldAccess(forExpression, fieldProxy, hasReceiver); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createMethodInvocation(org.eclipse.jem.internal.proxy.initParser.tree.ForExpression, org.eclipse.jem.internal.proxy.core.IProxyMethod, boolean, int) |
| */ |
| public final void createMethodInvocation(ForExpression forExpression, IProxyMethod methodProxy, boolean hasReceiver, int argumentCount) throws IllegalArgumentException, |
| IllegalStateException { |
| validateProxy(methodProxy); |
| pushMethodInvocation(forExpression, methodProxy, hasReceiver, argumentCount); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createSimpleFieldAccess(org.eclipse.jem.internal.proxy.core.IProxyField, org.eclipse.jem.internal.proxy.core.IProxy) |
| */ |
| public final ExpressionProxy createSimpleFieldAccess(IProxyField field, IProxy receiver) throws IllegalStateException, IllegalArgumentException { |
| validateProxy(field); |
| validateProxy(receiver); |
| ExpressionProxy result = createProxyAssignmentExpression(ForExpression.ROOTEXPRESSION); |
| createFieldAccess(ForExpression.ASSIGNMENT_RIGHT, field, receiver != null); |
| if (receiver != null) |
| createProxyExpression(ForExpression.FIELD_RECEIVER, receiver); |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createSimpleFieldSet(org.eclipse.jem.internal.proxy.core.IProxyField, org.eclipse.jem.internal.proxy.core.IProxy, org.eclipse.jem.internal.proxy.core.IProxy, boolean) |
| */ |
| public final ExpressionProxy createSimpleFieldSet(IProxyField field, IProxy receiver, IProxy value, boolean wantResult) throws IllegalStateException, IllegalArgumentException { |
| validateProxy(field); |
| validateProxy(receiver); |
| ExpressionProxy result = null; |
| ForExpression forExpression = ForExpression.ROOTEXPRESSION; |
| if (wantResult) { |
| result = createProxyAssignmentExpression(forExpression); |
| forExpression = ForExpression.ASSIGNMENT_RIGHT; |
| } |
| createAssignmentExpression(forExpression); |
| createFieldAccess(ForExpression.ASSIGNMENT_LEFT, field, receiver != null); |
| if (receiver != null) |
| createProxyExpression(ForExpression.FIELD_RECEIVER, receiver); |
| createProxyExpression(ForExpression.ASSIGNMENT_RIGHT, value); |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createSimpleMethodInvoke(org.eclipse.jem.internal.proxy.core.IMethodProxy, org.eclipse.jem.internal.proxy.core.IProxy, org.eclipse.jem.internal.proxy.core.IProxy[], boolean) |
| */ |
| public final ExpressionProxy createSimpleMethodInvoke(IProxyMethod method, IProxy receiver, IProxy[] arguments, boolean wantResult) |
| throws IllegalStateException, IllegalArgumentException { |
| validateProxy(method); |
| validateProxy(receiver); |
| if (arguments != null && arguments.length > 0) { |
| for (int i = 0; i < arguments.length; i++) { |
| validateProxy(arguments[i]); |
| } |
| } |
| ForExpression nextExpression = ForExpression.ROOTEXPRESSION; |
| ExpressionProxy result = null; |
| if (wantResult) { |
| result = createProxyAssignmentExpression(nextExpression); |
| nextExpression = ForExpression.ASSIGNMENT_RIGHT; |
| } |
| createMethodInvocation(nextExpression, method, receiver != null, arguments != null ? arguments.length : 0); |
| if (receiver != null) |
| createProxyExpression(ForExpression.METHOD_RECEIVER, receiver); |
| if (arguments != null) { |
| for (int i = 0; i < arguments.length; i++) { |
| createProxyExpression(ForExpression.METHOD_ARGUMENT, arguments[i]); |
| } |
| } |
| return result; |
| } |
| |
| private int subexpressionNumber = -1; // Current subexpression number. This is always incrementing. |
| |
| public void createSubexpression() throws IllegalStateException { |
| try { |
| // Subexpressions are special, they can be anywhere. |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(SUBEXPRESSIONEND_EXPRESSION); |
| pushForExpression(ForExpression.ROOTEXPRESSION); |
| |
| pushSubexpressionBeginToProxy(++subexpressionNumber); |
| push(new Integer(subexpressionNumber)); |
| push(InternalExpressionTypes.SUBEXPRESSION_END_EXPRESSION); |
| processExpression(); |
| return; |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| public void createSubexpressionEnd() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since block is done. |
| checkForExpression(SUBEXPRESSIONEND_EXPRESSION); // This needs to be next for it to be valid. |
| processExpression(); // Now let it handle the previously pushed end subexpression, containing the subexpression number being ended. |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| private int tryNumber = -1; // Current try number. This is always incrementing. |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTry() |
| */ |
| public final void createTry() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| pushForExpression(PROCESS_EXPRESSION); // Set up so that when reached we can process the TRY_END that we've pushed data for later in this method. |
| pushForExpression(TRYEND_EXPRESSION); // Must get a try end before we can process it. |
| pushForExpression(TRYCATCH_EXPRESSION); // Must get a catch/finally clause (or try end, which knows how to handle this). |
| pushForExpression(ForExpression.ROOTEXPRESSION); // Expecting root expressions for the try clause. |
| |
| pushTryBeginToProxy(++tryNumber); |
| push(new Integer(tryNumber)); |
| push(InternalExpressionTypes.TRY_END_EXPRESSION); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTryCatchClause(org.eclipse.jem.internal.proxy.core.IProxyBeanType, boolean) |
| */ |
| public final ExpressionProxy createTryCatchClause(IProxyBeanType exceptionType, boolean wantExceptionReturned) |
| throws IllegalStateException, IllegalArgumentException { |
| validateProxy(exceptionType); |
| return pushTryCatch(exceptionType, wantExceptionReturned); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTryCatchClause(java.lang.String, boolean) |
| */ |
| public final ExpressionProxy createTryCatchClause(String exceptionType, boolean wantExceptionReturned) |
| throws IllegalStateException { |
| return pushTryCatch(getProxyBeanType(exceptionType), wantExceptionReturned); |
| } |
| |
| /** |
| * @param exceptionType |
| * @param wantExceptionReturned |
| * @return |
| * @throws IllegalStateException |
| * |
| * @since 1.1.0 |
| */ |
| private ExpressionProxy pushTryCatch(IProxyBeanType exceptionType, boolean wantExceptionReturned) throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since try or previous catch clause is done. |
| checkForExpression(TRYCATCH_EXPRESSION); // This needs to be next for it to be valid. |
| pushForExpression(TRYCATCH_EXPRESSION); // Set up for a following catch/finally clause. |
| pushForExpression(ForExpression.ROOTEXPRESSION); // Root expressions are next for the catch clause. |
| |
| int tryNumber = ((Integer) peek(2)).intValue(); // Get the try#. It should be in this place on the stack. |
| |
| ExpressionProxy ep = null; |
| if (wantExceptionReturned) |
| ep = allocateExpressionProxy(NORMAL_EXPRESSION_PROXY); |
| pushTryCatchClauseToProxy(tryNumber, exceptionType, ep); |
| |
| processExpression(); |
| return ep; |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTryEnd() |
| */ |
| public final void createTryEnd() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since try or previous catch clause is done. |
| if (peekForExpression(TRYCATCH_EXPRESSION)) |
| checkForExpression(TRYCATCH_EXPRESSION); // This may of been next if no finally clause was added. If a finally clause was added this would not be here. |
| checkForExpression(TRYEND_EXPRESSION); // And this needs to be after that to be valid. |
| |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createTryFinallyClause() |
| */ |
| public final void createTryFinallyClause() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since try or previous catch clause is done. |
| checkForExpression(TRYCATCH_EXPRESSION); // This needs to be next for it to be valid. |
| pushForExpression(ForExpression.ROOTEXPRESSION); // Root expressions are next for the finally clause. |
| |
| int tryNumber = ((Integer) peek(2)).intValue(); // Get the try#. It should be in this place on the stack. |
| |
| pushTryFinallyClauseToProxy(tryNumber); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createRethrow() |
| */ |
| public final void createRethrow() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| popForExpression(); // Remove the root expression since try or previous catch clause is done. |
| checkForExpression(TRYCATCH_EXPRESSION); // This needs to be next for it to be valid. |
| // It is in a valid state, so put the catch and root back on so that things work correctly. |
| pushForExpression(TRYCATCH_EXPRESSION); |
| pushForExpression(ForExpression.ROOTEXPRESSION); |
| |
| int tryNumber = ((Integer) peek(2)).intValue(); // Get the try#. It should be in this place on the stack. |
| |
| pushRethrowToProxy(tryNumber); |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IExpression#createThrow() |
| */ |
| public final void createThrow() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| push(InternalExpressionTypes.THROW_EXPRESSION); |
| pushForExpression(PROCESS_EXPRESSION); |
| pushForExpression(ForExpression.THROW_OPERAND); // The next expression must be for the throw value. |
| processExpression(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| public final int mark() throws IllegalStateException { |
| try { |
| checkForExpression(ForExpression.ROOTEXPRESSION); |
| ++highestMarkID; |
| currentMarkEntry = new MarkEntry(); |
| currentMarkEntry.markID = highestMarkID; |
| currentMarkEntry.controlStackPos = controlStack.size() - 1; |
| currentMarkEntry.nextExpressionStackPos = nextForExpressionStackPos; |
| currentMarkEntry.expressionProxiesPos = expressionProxies != null ? expressionProxies.size() - 1 : -1; |
| if (markEntries == null) |
| markEntries = new ArrayList(5); |
| markEntries.add(currentMarkEntry); |
| pushMarkToProxy(highestMarkID); |
| return highestMarkID; |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| public void endMark(int markNumber) throws IllegalStateException { |
| if (isValid()) { |
| // Can only do a valid end mark if we are at root. If not at root, we fall through and treat as invalid. |
| if (peekForExpression(ForExpression.ROOTEXPRESSION)) { |
| checkForExpression(ForExpression.ROOTEXPRESSION); // Now remove it if it should be removed. |
| // If the current mark number is not the same as the incoming mark number, we have improper nesting. |
| if (currentMarkEntry == null || currentMarkEntry.markID != markNumber) |
| throwInvalidMarkNesting(); // We have improper nesting. |
| // We are popping the current mark. Since we are valid, just move up one in the mark stack. |
| MarkEntry me = (MarkEntry) markEntries.remove(markEntries.size()-1); |
| if (!markEntries.isEmpty()) |
| currentMarkEntry = (MarkEntry) markEntries.get(markEntries.size()-1); |
| else |
| currentMarkEntry = null; |
| pushEndmarkToProxy(markNumber, false); |
| if (me.controlStackPos != controlStack.size()-1 || me.nextExpressionStackPos != nextForExpressionStackPos) |
| throwInvalidMarkNesting(); // The stacks should be back to the same size at this point for a valid end mark. |
| return; |
| } |
| } |
| |
| // It was invalid, or became invalid. |
| if (markEntries == null) |
| throwInvalidMarkNesting(); // We have no marks, so this is an invalid end mark. |
| |
| // We are invalid, need to pop to the given markNumber. |
| // Starting from the end we search back to find the entry for the given mark number. We do it |
| // from the end because it is more likely to be closer to the end than to the beginning. |
| for (int i = markEntries.size()-1; i >=0; i--) { |
| MarkEntry me = (MarkEntry) markEntries.get(i); |
| if (me.markID == markNumber) { |
| // Found it. |
| // Trim the control stack down to the size at time of mark. (No easy way to do this other than repeated remove's. |
| // We do it backwards to eliminate repeated shuffling of entries. |
| for (int j = controlStack.size()-1; j > me.controlStackPos; j--) { |
| controlStack.remove(j); |
| } |
| |
| // Trim the expression stack. This is simple, just reset the next entry pointer. |
| nextForExpressionStackPos = me.nextExpressionStackPos; |
| |
| if (expressionProxies != null) { |
| // Now we need to mark all of the expression proxies that occured after the mark as |
| // not resolved (since someone may be listening), and remove them, and reuse the proxies. |
| for (int j = expressionProxies.size()-1; j > me.expressionProxiesPos; j--) { |
| ExpressionProxy proxy = (ExpressionProxy) expressionProxies.remove(j); |
| if (proxy != null && proxy.hasListeners()) |
| fireProxyNotResolved(proxy); |
| } |
| } |
| |
| // Now that we know it is valid, we want to remove all of the mark entries above it in the stack |
| // since those are now invalid. We couldn't remove them as we were searching for the entry because |
| // if the entry wasn't found we didn't want to wipe out the probably valid ones. |
| for (int j = markEntries.size()-1; j >= i; j--) { |
| markEntries.remove(j); |
| } |
| |
| if (!markEntries.isEmpty()) |
| currentMarkEntry = (MarkEntry) markEntries.get(markEntries.size()-1); |
| else |
| currentMarkEntry = null; |
| pushEndmarkToProxy(markNumber, true); |
| expressionValid = true; |
| return; |
| } |
| } |
| throwInvalidMarkNesting(); // The mark number wasn't found, so this is an invalid end mark. |
| } |
| |
| /** |
| * Begin the transfer of the expression to another thread. |
| * <p> |
| * This is used when the expression needs to continue to be built up, but it needs |
| * to be done on a different thread. The reason for doing something special other |
| * than just using it on the other thread is that some proxy registries connections are |
| * tied through the thread. If you switched to another thread the connections would not |
| * be properly set up. |
| * This is not on the IExpression interface because even though it is API, it is tricky |
| * to use and so not exposed to everyone. Users can legitimately cast to Expression and |
| * use this as API for advanced use. |
| * <p> |
| * This is used to begin the transfer. It puts it into a state ready for the transfer. Calling this |
| * method will cause a synchronization of the expression up to the current level. This means |
| * that it will not return until the expression has been completely processed in the proxy registry |
| * up to this point. Typically the connection is a pipe where the instructions are just pushed onto |
| * it and the caller is not held up waiting for the registry to process it. |
| * <p> |
| * Then when the other thread is done, it will call beginTransferThread itself to signal that it is done |
| * and that the old thread can pick it up. Then the old thread will call transferThread to pick up processing. |
| * <p> |
| * It will be: |
| * <pre><code> |
| * ... expression stuff ... |
| * expression.beginTransferThread() |
| * ... do what is necessary to get to the other thread ... |
| * ... on other thread: |
| * expression.transferThread(); |
| * try { |
| * ... do your expression stuff on this thread ... |
| * } finally { |
| * expression.beginTransferThread(); // This is to return it to old thread. |
| * } |
| * ... tell old thread to pick up ... |
| * ... back on old thread: |
| * expression.transferThread(); |
| * ... do more expression stuff ... |
| * expression.invokeExpression(); |
| * </code></pre> |
| * |
| * @throws IllegalStateException |
| * @throws ThrowableProxy Thrown if there was an exception with the remote vm during this request. |
| * @since 1.1.0 |
| */ |
| public final void beginTransferThread() throws IllegalStateException, ThrowableProxy { |
| try { |
| pushForExpression(THREADTRANSFER_EXPRESSION); |
| pushBeginTransferThreadToProxy(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| /** |
| * Transfer the expression to the current thread. |
| * <p> |
| * This is called to actually transfer to the current thread. It must be the next call against |
| * the expression after the beginTransferThread, but on the new thread. |
| * <p> |
| * This is not on the IExpression interface because even though it is API, it is tricky |
| * to use and so not exposed to everyone. Users can legitimately cast to Expression and |
| * use this as API for advanced use. |
| * @see Expression#beginTransferThread() for a full explanation. |
| * @throws IllegalStateException |
| * |
| * @since 1.1.0 |
| */ |
| public final void transferThread() throws IllegalStateException { |
| try { |
| checkForExpression(THREADTRANSFER_EXPRESSION); |
| pushTransferThreadToProxy(); |
| } catch (RuntimeException e) { |
| markInvalid(); |
| throw e; |
| } |
| } |
| |
| |
| /** |
| * Get the IProxyBeanType for the type string sent in. |
| * @param type |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| protected IProxyBeanType getProxyBeanType(String type) { |
| return getRegistry().getBeanTypeProxyFactory().getBeanTypeProxy(this, type); |
| } |
| |
| /** |
| * Create the expression proxy subclass that is applicable for this kind of processor. |
| * @param proxyType type of proxy. {@link Expression#NORMAL_EXPRESSION_PROXY |
| * @param proxyID the id of the new expression proxy. |
| * |
| * @return |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract ExpressionProxy createExpressionProxy(int proxyType, int proxyID); |
| |
| /** |
| * Push this proxy to the other side. It will simply take the proxy and push it onto |
| * its evaluation stack. It will be treated as the result of an expression. It's just |
| * that the expression was evaluatable on this side (since it is already a proxy). |
| * |
| * @param proxy |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushToProxy(IProxy proxy); |
| |
| /** |
| * Tell the other side we are complete. This will always be called after expression evaluation, or |
| * if expression was prematurely closed. |
| * <p> |
| * <b>Note:</b> The implementation must be able to handle multiple invocations, where the first call is a valid close and any |
| * subsequent call should be ignored. |
| * |
| * @throws ThrowableProxy |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void closeProxy(); |
| |
| /** |
| * Do invoke. This should simply make sure everything is done and throw any pending errors. |
| * <p> |
| * <b>Note:</b> The expression proxies MUST be resolved (callbacks called) in the order they are found in the expressionProxies list. This |
| * is so that the contract is followed that resolution notifications will occur in the order of creation. |
| * |
| * @param proxycount Number of Expression Proxies that need a callback. |
| * @param list of expression proxies. If proxycount > 0, then process the non-null entries in the list. They will be of type ExpressionProxy. |
| * @throws ThrowableProxy |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushInvoke(int proxycount, List expressionProxies) throws ThrowableProxy, NoExpressionValueException; |
| |
| /** |
| * Pull the top expression value from the evaluation stack. It will also under |
| * the covers call closeProxy. It also must process the expression proxy callbacks. It must do the expression proxy callbacks first, and then |
| * process the result value. If an error had occured sometime during processing, it should still process the proxy callbacks before throwing |
| * an exception. |
| * <p> |
| * <b>Note:</b> The expression proxies MUST be resolved (callbacks called) in the order they are found in the expressionProxies list. This |
| * is so that the contract is followed that resolution notifications will occur in the order of creation. Also <b>REQUIRED</b> is that |
| * the entire list must be processed of proxies must be processed by this call. It cannot do some or none. |
| * |
| * @param proxycount Number of Expression Proxies that need a callback. |
| * @param list of expression proxies. If proxycount > 0, then process the non-null entries in the list. They will be of type ExpressionProxy. |
| * @return The top level evaluation stack value. |
| * @throws ThrowableProxy |
| * @throws NoExpressionValueException |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract IBeanProxy pullProxyValue(int proxycount, List expressionProxies) throws ThrowableProxy, NoExpressionValueException; |
| |
| /** |
| * Push to proxy the cast expression. The expression to use will be on the top of its evaluation stack. |
| * The result of the cast expression will be placed onto the evaluation stack. |
| * |
| * @param type Cast type. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushCastToProxy(IProxyBeanType type); |
| |
| /** |
| * Push to proxy the instanceof expression. The expression to use will be on the top of its evaluation stack. |
| * The result of the instanceof expression will be placed onto the evaluation stack. |
| * |
| * @param type Instanceof type. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushInstanceofToProxy(IProxyBeanType type); |
| |
| /** |
| * Push to proxy the infix operation. This is called on the completion of each operand of the expression. |
| * So it will be called a minimum of two times. |
| * |
| * @param operator The operator. |
| * @param operandType The operand type. left, other, or last. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushInfixToProxy(InfixOperator operator, InternalInfixOperandType operandType); |
| |
| /** |
| * Push to proxy the prefix expression. The expression to use will be on top of its evaluation stack. |
| * The result of the prefix operation will be placed onto the evaluation stack. |
| * |
| * @param operator |
| * |
| * @see IExpressionConstants#PRE_MINUS |
| * @since 1.0.0 |
| */ |
| protected abstract void pushPrefixToProxy(PrefixOperator operator); |
| |
| |
| /** |
| * Push to proxy the array access. The result will be placed onto the evaluation stack. |
| * |
| * @param indexCount |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushArrayAccessToProxy(int indexCount); |
| |
| /** |
| * Push to proxy the array creation. The result will be placed onto the evaluation stack. |
| * @param type The array type. |
| * @param dimensionCount |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushArrayCreationToProxy(IProxyBeanType type, int dimensionCount); |
| |
| /** |
| * Push to proxy the array initializer. The resulting array will be placed onto the evaluation stack. |
| * @param type The array type. (must be an array type). |
| * @param stripDimCount the number of dimensions that must be stripped from the array type. This is needed |
| * because the first array initializer needs to be for the component type of the array (array minus one dimension), and |
| * each initializer after that needs one more dimension stripped off. But since we are working with possible expression |
| * proxies for "type", we can't create the appropriate component types of the array. So we need to tell the |
| * processor how many dims to strip from the original type (which is what is sent in on every initializer push, the original type). |
| * @param expressionCount |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushArrayInitializerToProxy(IProxyBeanType type, int stripDimCount, int expressionCount); |
| |
| /** |
| * Push to proxy the class instance creation. The resulting class instance will be placed onto the evaluation stack. |
| * |
| * @param type Class type. |
| * @param argumentCount The number of arguments. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushClassInstanceCreationToProxy(IProxyBeanType type, int argumentCount); |
| |
| /** |
| * Push to proxy the type receiver. The resulting class will be placed onto the evaluation stack, along with it also |
| * being the expression type. |
| * @param type Class type. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushTypeReceiverToProxy(IProxyBeanType type); |
| |
| /** |
| * Push to proxy the field access. The result value will be placed onto the evaluation stack. |
| * @param field The name of the field if string, or an IFieldProxy. |
| * @param hasReceiver Has receiver flag. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushFieldAccessToProxy(Object field, boolean hasReceiver); |
| |
| /** |
| * Push to proxy the method invocation. The result value will be placed onto the evaluation stack. |
| * |
| * @param method String for method name or IProxyMethod |
| * @param hasReceiver |
| * @param argCount |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushMethodInvocationToProxy(Object method, boolean hasReceiver, int argCount); |
| |
| /** |
| * Push to proxy the conditional expression. This will be called on each part of expression. The expression type |
| * will be the current part (e.g. test, true, false). |
| * |
| * @param expressionType The expression type. |
| * |
| * @since 1.0.0 |
| */ |
| protected abstract void pushConditionalToProxy(InternalConditionalOperandType expressionType); |
| |
| /** |
| * Push to the proxy the expression proxy. Whatever the last expression value is will be assigned to the ExpressionProxy. |
| * |
| * @param proxy |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushAssignmentToProxy(ExpressionProxy proxy); |
| |
| /** |
| * Push the assignment expression. The operands are already on the stack. |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushAssignmentToProxy(); |
| |
| |
| /** |
| * Push the begin block expression. |
| * @param blockNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushBlockBeginToProxy(int blockNumber); |
| |
| /** |
| * Push the end block expression. |
| * @param blockNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushBlockEndToProxy(int blockNumber); |
| |
| /** |
| * Push the break block expression. |
| * @param blockNumber |
| * |
| * @since 1.1.0 |
| * |
| */ |
| protected abstract void pushBlockBreakToProxy(int blockNumber); |
| |
| /** |
| * Push the begin try expression. |
| * @param tryNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushTryBeginToProxy(int tryNumber); |
| |
| /** |
| * Push the catch clause to proxy. |
| * @param tryNumber |
| * @param exceptionType |
| * @param ep ExpressionProxy to be assigned with the exception or <code>null</code> if exception is not to be assigned. |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushTryCatchClauseToProxy(int tryNumber, IProxyBeanType exceptionType, ExpressionProxy ep); |
| |
| /** |
| * Push the finally clause to proxy. |
| * @param tryNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushTryFinallyClauseToProxy(int tryNumber); |
| |
| /** |
| * Push try end to proxy. |
| * @param tryNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushTryEndToProxy(int tryNumber); |
| |
| /** |
| * Push the throw of the exception to proxy. |
| * @param exception |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushThrowToProxy(); |
| |
| /** |
| * Push a rethrow to proxy. |
| * @param tryNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushRethrowToProxy(int tryNumber); |
| |
| /** |
| * Push the BeanType Expression proxy to be resolved on the execution side. |
| * @param proxy |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushBeanTypeToProxy(IBeanTypeExpressionProxy proxy); |
| |
| /** |
| * Push the Method Expression proxy to be resolved on the execution side. |
| * @param proxy |
| * @param declaringType |
| * @param methodName |
| * @param parameterTypes parameter types or <code>null</code> if no parameters. |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushMethodToProxy(ExpressionProxy proxy, IProxyBeanType declaringType, String methodName, IProxyBeanType[] parameterTypes); |
| |
| /** |
| * Push the Field Expression Proxy to be resolved on the execution side. |
| * @param proxy |
| * @param declaringType |
| * @param fieldName |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushFieldToProxy(ExpressionProxy proxy, IProxyBeanType declaringType, String fieldName); |
| |
| /** |
| * Push the If test condition to proxy. |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushIfTestToProxy(); |
| |
| /** |
| * Push a true or else clause to proxy. |
| * @param clauseType |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushIfElseToProxy(InternalIfElseOperandType clauseType); |
| |
| /** |
| * Push to proxy a new instance using an initialization string. |
| * @param initializationString |
| * @param resultType |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushNewInstanceToProxy(String initializationString, IProxyBeanType resultType); |
| |
| /** |
| * Push the mark id to proxy. |
| * |
| * @param markID |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushMarkToProxy(int markID); |
| |
| /** |
| * Push the end mark id to proxy. |
| * |
| * @param markID |
| * @param restore <code>true</code> if this is a restore due to error, <code>false</code> if this is just a normal end mark. |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushEndmarkToProxy(int markID, boolean restore); |
| |
| /** |
| * Push the begin transfer thread to proxy. |
| * |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushBeginTransferThreadToProxy() throws ThrowableProxy; |
| |
| /** |
| * Push the actual transfer to the current thread to proxy. |
| * |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushTransferThreadToProxy(); |
| |
| /** |
| * Push the subexpression begin to proxy. |
| * @param subexpressionNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushSubexpressionBeginToProxy(int subexpressionNumber); |
| |
| /** |
| * Push the subexpression end to proxy. |
| * @param subexpressionNumber |
| * |
| * @since 1.1.0 |
| */ |
| protected abstract void pushSubexpressionEndToProxy(int subexpressionNumber); |
| } |