package bluej.parser;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Stack;
import bluej.debugger.gentype.GenTypeClass;
import bluej.debugger.gentype.GenTypeDeclTpar;
import bluej.debugger.gentype.GenTypeParameter;
import bluej.debugger.gentype.GenTypeSolid;
import bluej.debugger.gentype.JavaPrimitiveType;
import bluej.debugger.gentype.JavaType;
import bluej.debugger.gentype.Reflective;
import bluej.parser.TextAnalyzer.MethodCallDesc;
import bluej.parser.entity.ConstantBoolValue;
import bluej.parser.entity.ConstantFloatValue;
import bluej.parser.entity.ConstantIntValue;
import bluej.parser.entity.ConstantStringEntity;
import bluej.parser.entity.EntityResolver;
import bluej.parser.entity.ErrorEntity;
import bluej.parser.entity.JavaEntity;
import bluej.parser.entity.NullEntity;
import bluej.parser.entity.PackageOrClass;
import bluej.parser.entity.SolidTargEntity;
import bluej.parser.entity.TypeArgumentEntity;
import bluej.parser.entity.TypeEntity;
import bluej.parser.entity.UnboundedWildcardEntity;
import bluej.parser.entity.UnresolvedEntity;
import bluej.parser.entity.ValueEntity;
import bluej.parser.entity.WildcardExtendsEntity;
import bluej.parser.entity.WildcardSuperEntity;
import bluej.parser.lexer.JavaTokenTypes;
import bluej.parser.lexer.LocatableToken;
import bluej.utility.JavaReflective;
import threadchecker.OnThread;
import threadchecker.Tag;
| A parser for the codepad.
|
| @author Davin McCall
|
public class TextParser
extends JavaParser{
private EntityResolver resolver;
private JavaEntity accessType;
private boolean staticAccess;
protected Stack<JavaEntity> valueStack = new Stack<JavaEntity>();
private int arrayCount = 0;
| A class to represent operators, possibly associated with a token
|
protected class Operator
{
int type;
LocatableToken token;
Operator(int type, LocatableToken token) { this.type = type; this.token = token;
}
int getType() { return type;
}
LocatableToken getToken() { return token;
}
}
protected Stack<Operator> operatorStack = new Stack<Operator>();
| A stack of type argument lists - one list for each method call on the operator stack
|
protected Stack<List<LocatableToken>> typeArgStack = new Stack<List<LocatableToken>>();
|
| Make up some operators - only for cases where there is not a token
| type we could use, or for where the token is ambiguos:
|
private static final int CAST_OPERATOR = JavaTokenTypes.INVALID + 1;
private static final int BAD_CAST_OPERATOR = CAST_OPERATOR + 1;
private static final int PAREN_OPERATOR = BAD_CAST_OPERATOR + 1;
private static final int MEMBER_CALL_OP = PAREN_OPERATOR + 1;
private static final int METHOD_CALL_OP = MEMBER_CALL_OP + 1;
private static final int CONSTRUCTOR_CALL_OP = METHOD_CALL_OP + 1;
private static final int UNARY_PLUS_OP = CONSTRUCTOR_CALL_OP + 1;
private static final int UNARY_MINUS_OP = UNARY_PLUS_OP + 1;
|
| Parse states - mainly so we know what to do with a type specification
| when we seen one:
|
private static final int STATE_NONE = 0;
private static final int STATE_NEW = 1;
private static final int STATE_NEW_ARGS = 2;
private static final int STATE_INSTANCEOF = 3;
private int state = STATE_NONE;
| Arguments for a method or constructor call are added to the list at the top of this stack
|
private Stack<List<JavaEntity>> argumentStack = new Stack<List<JavaEntity>>();
| Construct a text parser for parsing an expression.
|
| @param resolver Resolver to resolve symbols
| @param r Reader to read the expression source
| @param accessType The containing type
| @param staticAccess Whether the expression occurs in a static context
|
public TextParser(EntityResolver resolver, Reader r, JavaEntity accessType, boolean staticAccess)
{
super(r);
this.resolver = resolver;
this.accessType = accessType;
this.staticAccess = staticAccess;
}
| Construct a text parser for parsing an expression, where the expression is located
| at a particular line and column in the source.
|
| @param resolver Resolver to resolve symbols
| @param r Reader to read the expression source
| @param accessType The containing type
| @param staticAccess Whether the expression occurs in a static context
| @param line The line in the source where the expression occurs
| @param col The column in the source where the expression occurs
|
public TextParser(EntityResolver resolver, Reader r, JavaEntity accessType, boolean staticAccess,
int line, int col, int pos)
{
super(r, line, col, pos);
this.resolver = resolver;
this.accessType = accessType;
this.staticAccess = staticAccess;
}
| Construct a text parser for parsing an expression which is represented in a String.
|
| @param resolver Resolver to resolve symbols
| @param s A string containing the expression
| @param accessType The containing type
| @param staticAccess Whether the expression occurs in a static context
|
public TextParser(EntityResolver resolver, String s, JavaEntity accessType, boolean staticAccess)
{
this(resolver, new StringReader(s), accessType, staticAccess);
}
| Check whether the parsed expression ended at the end of the input.
|
| @return true iff the parsed expression ended at the end of the input (reader or string);
| false otherwise.
|
public boolean atEnd()
{
return tokenStream.LA(1).getType() == JavaTokenTypes.EOF;
}
| Get the type of the parsed expression. If the type is unknown or an error occurred,
| returns {}code null}.
|
public JavaEntity getExpressionType()
{
processHigherPrecedence(getPrecedence(JavaTokenTypes.EOF) - 1);
if (valueStack.isEmpty()) {
return null;
}
return valueStack.pop();
}
| Pop an item from the value stack. If there are no values to pop, supply an error entity.
|
protected JavaEntity popValueStack()
{
if (! valueStack.isEmpty()) {
return valueStack.pop();
}
return new ErrorEntity();
}
| Get the precedence level for a given operator type.
|
private int getPrecedence(int tokenType)
{
switch (tokenType) {
case JavaTokenTypes.LCURLY:
return -10;
case PAREN_OPERATOR:
return -2;
case JavaTokenTypes.LITERAL_new:
return -1;
case JavaTokenTypes.ASSIGN:
case JavaTokenTypes.BAND_ASSIGN:
case JavaTokenTypes.BOR_ASSIGN:
case JavaTokenTypes.PLUS_ASSIGN:
case JavaTokenTypes.MINUS_ASSIGN:
case JavaTokenTypes.STAR_ASSIGN:
case JavaTokenTypes.DIV_ASSIGN:
case JavaTokenTypes.SL_ASSIGN:
case JavaTokenTypes.SR_ASSIGN:
case JavaTokenTypes.BSR_ASSIGN:
case JavaTokenTypes.MOD_ASSIGN:
case JavaTokenTypes.BXOR_ASSIGN:
return 0;
case JavaTokenTypes.QUESTION:
return 1;
case JavaTokenTypes.LT:
case JavaTokenTypes.LE:
case JavaTokenTypes.GT:
case JavaTokenTypes.GE:
case JavaTokenTypes.LITERAL_instanceof:
return 8;
case JavaTokenTypes.EQUAL:
case JavaTokenTypes.NOT_EQUAL:
return 9;
case JavaTokenTypes.SL:
case JavaTokenTypes.SR:
case JavaTokenTypes.BSR:
return 10;
case JavaTokenTypes.PLUS:
case JavaTokenTypes.MINUS:
return 11;
case JavaTokenTypes.STAR:
case JavaTokenTypes.DIV:
return 12;
case JavaTokenTypes.LNOT:
case JavaTokenTypes.BNOT:
case JavaTokenTypes.INC:
case JavaTokenTypes.DEC:
case UNARY_PLUS_OP:
case UNARY_MINUS_OP:
case CAST_OPERATOR:
case BAD_CAST_OPERATOR:
return 13;
case JavaTokenTypes.DOT:
case MEMBER_CALL_OP:
case METHOD_CALL_OP:
case CONSTRUCTOR_CALL_OP:
return 20;
default:
}
return -1;
}
| Process all on-stack operators with a higher precedence than that given
|
private void processHigherPrecedence(int precedence)
{
while (! operatorStack.isEmpty()){
Operator top = operatorStack.peek();
if (getPrecedence(top.getType()) <= precedence) {
break;
}
operatorStack.pop();
processOperator(top);
}
}
| Process an operator, take the operands from the value stack and leave the result on the
| stack.
|
private void processOperator(Operator operator)
{
int tokenType = operator.getType();
JavaEntity arg1;
JavaEntity arg2;
switch (tokenType) {
case JavaTokenTypes.PLUS:
case JavaTokenTypes.MINUS:
case JavaTokenTypes.STAR:
case JavaTokenTypes.DIV:
case JavaTokenTypes.MOD:
case JavaTokenTypes.SL:
case JavaTokenTypes.SR:
case JavaTokenTypes.BSR:
case JavaTokenTypes.LT:
case JavaTokenTypes.LE:
case JavaTokenTypes.GT:
case JavaTokenTypes.GE:
case JavaTokenTypes.EQUAL:
case JavaTokenTypes.NOT_EQUAL:
case JavaTokenTypes.ASSIGN:
case JavaTokenTypes.BAND_ASSIGN:
case JavaTokenTypes.BOR_ASSIGN:
case JavaTokenTypes.PLUS_ASSIGN:
case JavaTokenTypes.MINUS_ASSIGN:
case JavaTokenTypes.STAR_ASSIGN:
case JavaTokenTypes.DIV_ASSIGN:
case JavaTokenTypes.SL_ASSIGN:
case JavaTokenTypes.SR_ASSIGN:
case JavaTokenTypes.BSR_ASSIGN:
case JavaTokenTypes.MOD_ASSIGN:
case JavaTokenTypes.BXOR_ASSIGN:
case JavaTokenTypes.BAND:
case JavaTokenTypes.BOR:
case JavaTokenTypes.BXOR:
case JavaTokenTypes.LOR:
case JavaTokenTypes.LAND:
arg2 = popValueStack();
arg1 = popValueStack();
doBinaryOp(arg1, arg2, operator);
break;
case JavaTokenTypes.LNOT:
case JavaTokenTypes.BNOT:
case JavaTokenTypes.INC:
case JavaTokenTypes.DEC:
case UNARY_MINUS_OP:
case UNARY_PLUS_OP:
arg1 = popValueStack();
checkArg(arg1, operator);
break;
case CAST_OPERATOR:
doCast();
break;
case BAD_CAST_OPERATOR:
popValueStack();
valueStack.push(new ErrorEntity());
break;
case JavaTokenTypes.QUESTION:
processQuestionOperator();
break;
}
}
@OnThread(Tag.FXPlatform)
private strictfp void doCast()
{
ValueEntity varg1 = popValueStack().resolveAsValue();
TypeEntity castType = popValueStack().resolveAsType();
if (varg1 == null || castType == null) {
valueStack.push(new ErrorEntity());
return;
}
if (ValueEntity.isConstant(varg1)) {
JavaType jctype = castType.getType();
if (jctype.isIntegralType()) {
long ival;
if (varg1.hasConstantIntValue()) {
ival = varg1.getConstantIntValue();
if (jctype.typeIs(JavaType.JT_BYTE)) {
ival = (byte) ival;
}
else if (jctype.typeIs(JavaType.JT_CHAR)) {
ival = (char) ival;
}
else if (jctype.typeIs(JavaType.JT_INT)) {
ival = (int) ival;
}
else if (jctype.typeIs(JavaType.JT_SHORT)) {
ival = (short) ival;
}
}
else if (varg1.hasConstantFloatValue()) {
if (jctype.typeIs(JavaType.JT_BYTE)) {
ival = (byte) varg1.getConstantFloatValue();
}
else if (jctype.typeIs(JavaType.JT_CHAR)) {
ival = (char) varg1.getConstantFloatValue();
}
else if (jctype.typeIs(JavaType.JT_INT)) {
ival = (int) varg1.getConstantFloatValue();
}
else if (jctype.typeIs(JavaType.JT_SHORT)) {
ival = (short) varg1.getConstantFloatValue();
}
else {
ival = (long) varg1.getConstantFloatValue();
}
}
else {
valueStack.push(new ErrorEntity());
return;
}
valueStack.push(new ConstantIntValue(null, jctype, ival));
return;
}
else if (jctype.typeIs(JavaType.JT_FLOAT) || jctype.typeIs(JavaType.JT_DOUBLE)) {
double dval;
if (varg1.hasConstantIntValue()) {
dval = varg1.getConstantIntValue();
}
else if (varg1.hasConstantFloatValue()) {
dval = varg1.getConstantFloatValue();
}
else {
valueStack.push(new ErrorEntity());
return;
}
if (jctype.typeIs(JavaType.JT_FLOAT)) {
dval = (float) dval;
}
valueStack.push(new ConstantFloatValue(jctype, dval));
return;
}
else if (jctype.toString().equals("java.lang.String")) {
if (varg1.isConstantString()) {
valueStack.push(varg1);
}
else {
valueStack.push(new ErrorEntity());
}
return;
}
}
JavaType argType = varg1.getType();
JavaType jctype = castType.getType();
if (argType.isPrimitive() && ! jctype.isPrimitive()) {
if (argType.typeIs(JavaType.JT_NULL)) {
valueStack.push(new ValueEntity(jctype));
return;
}
String jctypeStr = jctype.toString();
if (argType.typeIs(JavaType.JT_BOOLEAN) && jctypeStr.equals("java.lang.Boolean")
|| argType.typeIs(JavaType.JT_CHAR) && jctypeStr.equals("java.lang.Character")
|| argType.typeIs(JavaType.JT_BYTE) && jctypeStr.equals("java.lang.Byte")
|| argType.typeIs(JavaType.JT_SHORT) && jctypeStr.equals("java.lang.Short")
|| argType.typeIs(JavaType.JT_INT) && jctypeStr.equals("java.lang.Integer")
|| argType.typeIs(JavaType.JT_LONG) && jctypeStr.equals("java.lang.Long")
|| argType.typeIs(JavaType.JT_FLOAT) && jctypeStr.equals("java.lang.Float")
|| argType.typeIs(JavaType.JT_DOUBLE) && jctypeStr.equals("java.lang.Double")) {
valueStack.push(new ValueEntity(jctype));
}
else {
valueStack.push(new ErrorEntity());
}
return;
}
JavaType argUnboxed = TextAnalyzer.unBox(argType);
if (argUnboxed.isNumeric() && jctype.isNumeric()) {
valueStack.push(new ValueEntity(jctype));
return;
}
if (jctype.isPrimitive()) {
if (jctype.typeIs(JavaType.JT_BOOLEAN) && argUnboxed.typeIs(JavaType.JT_BOOLEAN)) {
valueStack.push(new ValueEntity(jctype));
}
else {
valueStack.push(new ErrorEntity());
}
return;
}
valueStack.push(new ValueEntity(jctype));
}
@Override
protected void gotArrayElementAccess()
{
JavaEntity index = popValueStack();
processHigherPrecedence(getPrecedence(JavaTokenTypes.DOT) - 1);
JavaEntity array = popValueStack();
index = index.resolveAsValue();
array = array.resolveAsValue();
if (index == null || array == null) {
valueStack.push(new ErrorEntity());
return;
}
JavaType componentType = array.getType().getArrayComponent();
if (componentType == null) {
valueStack.push(new ErrorEntity());
}
else {
valueStack.push(new ValueEntity(componentType));
}
}
private void processNewOperator(Operator token)
{
if (! argumentStack.isEmpty()) {
argumentStack.pop();
}
else {
popValueStack();
valueStack.push(new ErrorEntity());
}
}
| Process the "member call operator".
|*/
private void processMemberCall(Operator op)
{
// See JLS 15.12
// step 1 - determine type to search
// Seeing as this is a member call, that's already mostly done.
JavaEntity target = popValueStack();
|
|JavaEntity vtarget = target.resolveAsValue();
|
|GenTypeSolid targetType;
|
|if (vtarget != null) {
|
|GenTypeSolid stype = vtarget.getType().asSolid();
|
|if (stype == null) {
|
|// call on a primitive
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|targetType = stype;
|
|}
|
|else {
|
|// entity may be a type rather than a value
|
|target = target.resolveAsType();
|
|if (target == null) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|GenTypeSolid stype = target.getType().getCapture().asSolid();
|
|if (stype == null) {
|
|// call on a primitive
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|targetType = stype;
|
|}
|
|if (op.getToken().getType() == JavaTokenTypes.IDENT) {
|
|processMethodCall(targetType, op.getToken().getText(), typeArgStack.pop());
|
|}
|
|else {
|
|valueStack.push(new ErrorEntity());
|
|}
|
|}
|
|private void processMethodCall(Operator op)
|
|{
|
|if (op.getToken().getType() == JavaTokenTypes.IDENT) {
|
|processMethodCall(accessType.getType().asClass(), op.getToken().getText(),
|
|Collections.<LocatableToken>emptyList());
|
|}
|
|else {
|
|valueStack.push(new ErrorEntity());
|
|}
|
|}
|
|private void processMethodCall(GenTypeSolid targetType, String methodName, List<LocatableToken> typeArgTokens)
|
|{
|
|GenTypeClass accessClass = accessType.getType().asClass();
|
|if (accessClass == null) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|// Gather the argument types.
|
|List<JavaEntity> argList = argumentStack.pop();
|
|JavaType [] argTypes = new JavaType[argList.size()];
|
|for (int i = 0; i < argTypes.length; i++) {
|
|JavaEntity cent = argList.get(i).resolveAsValue();
|
|if (cent == null) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|argTypes[i] = cent.getType();
|
|}
|
|// Determine type arguments to method invocation
|
|List<GenTypeParameter> typeArgs;
|
|if (! typeArgTokens.isEmpty()) {
|
|DepthRef depthRef = new DepthRef();
|
|ListIterator<LocatableToken> i = typeArgTokens.listIterator(1); // skip '<'
|
|List<TypeArgumentEntity> typeArgEnts = readTypeArguments(i, depthRef);
|
|if (typeArgEnts == null) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|typeArgs = new ArrayList<GenTypeParameter>(typeArgEnts.size());
|
|for (TypeArgumentEntity typeArgEnt : typeArgEnts) {
|
|GenTypeParameter targType = typeArgEnt.getType();
|
|if (targType == null || targType.isPrimitive() || targType.isWildcard()) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|typeArgs.add(targType);
|
|}
|
|}
|
|else {
|
|typeArgs = Collections.emptyList();
|
|}
|
|ArrayList<MethodCallDesc> suitable = TextAnalyzer.getSuitableMethods(methodName,
|
|targetType, argTypes, typeArgs, accessClass.getReflective());
|
|if (suitable.size() == 0) {
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|// JLS 3rd ed. 15.12.2.5. We already have a list of the maximally specific methods:
|
|// - if one or more methods have non override-equivalent signatures, the call is ambiguous
|
|// - otherwise, if there is exactly one non-abstract method, choose that one;
|
|// - otherwise, arbitrarily choose one from the set with the most specific return type.
|
|int nonAbstractCount = 0;
|
|MethodCallDesc nonAbstractMethod = null;
|
|MethodCallDesc mostSpecificMethod = null;
|
|Iterator<MethodCallDesc> i = suitable.iterator();
|
|MethodCallDesc first = i.next();
|
|if (! first.method.isAbstract()) {
|
|nonAbstractCount++;
|
|nonAbstractMethod = first;
|
|}
|
|mostSpecificMethod = first;
|
|if (suitable.size() > 1) {
|
|List<GenTypeDeclTpar> tpars = first.method.getTparTypes();
|
|List<JavaType> paramTypes = first.method.getParamTypes();
|
|while (i.hasNext()){
|
|MethodCallDesc next = i.next();
|
|if (!checkOverrideEquivalence(tpars, paramTypes, next.method.getTparTypes(), next.method.getParamTypes())) {
|
|// Non override equivalent signatures: ambiguous call
|
|valueStack.push(new ErrorEntity());
|
|return;
|
|}
|
|if (! next.method.isAbstract()) {
|
|nonAbstractCount++;
|
|nonAbstractMethod = next;
|
|}
|
|if (mostSpecificMethod.retType.isAssignableFrom(next.retType)) {
|
|mostSpecificMethod = next;
|
|}
|
|}
|
|}
|
|MethodCallDesc chosenMethod = nonAbstractMethod;
|
|if (nonAbstractCount != 1) {
|
|chosenMethod = mostSpecificMethod;
|
|}
|
|// TODO check applicability of chosen method as per JLS 3rd ed. 15.12.3
|
|valueStack.push(new ValueEntity(chosenMethod.retType));
|
|}
|
|private static boolean checkOverrideEquivalence(List<GenTypeDeclTpar> firstTpars, List<JavaType> firstParamTypes,
|
|List<GenTypeDeclTpar> secondTpars, List<JavaType> secondParamTypes)
|
|{
|
|if (firstTpars.size() != 0 && secondTpars.size() != 0) {
|
|// Type parameters must be matchable
|
|if (firstTpars.size() != secondTpars.size()) {
|
|return false;
|
|}
|
|// Create a map from second method tpar name to first method tpar
|
|Map<String,GenTypeParameter> tparMap = new HashMap<String,GenTypeParameter>();
|
|Iterator<GenTypeDeclTpar> i = firstTpars.iterator();
|
|Iterator<GenTypeDeclTpar> j = secondTpars.iterator();
|
|while (i.hasNext()){
|
|GenTypeDeclTpar firstTpar = i.next();
|
|GenTypeDeclTpar secondTpar = j.next();
|
|tparMap.put(secondTpar.getTparName(), firstTpar);
|
|if (!secondTpar.getUpperBound().mapTparsToTypes(tparMap).equals(firstTpar.getUpperBound())) {
|
|return false;
|
|}
|
|}
|
|// Check argument types
|
|Iterator<JavaType> k = firstParamTypes.iterator();
|
|Iterator<JavaType> l = secondParamTypes.iterator();
|
|while (k.hasNext()){
|
|if (!l.next().mapTparsToTypes(tparMap).equals(k.next())) {
|
|return false;
|
|}
|
|}
|
|return true;
|
|}
|
|if (firstTpars.isEmpty() && secondTpars.isEmpty()) {
|
|// The parameter types might match exactly
|
|boolean doMatch = true;
|
|Iterator<JavaType> k = firstParamTypes.iterator();
|
|Iterator<JavaType> l = secondParamTypes.iterator();
|
|while (k.hasNext()){
|
|if (!l.next().equals(k.next())) {
|
|doMatch = false;
|
|break;
|
|}
|
|}
|
|if (doMatch) {
|
|return true;
|
|}
|
|}
|
|if (firstTpars.isEmpty()) {
|
|// The first signature might be the erasure of the second
|
|boolean doMatch = true;
|
|Iterator<JavaType> k = firstParamTypes.iterator();
|
|Iterator<JavaType> l = secondParamTypes.iterator();
|
|while (k.hasNext()){
|
|if (!l.next().getErasedType().equals(k.next())) {
|
|doMatch = false;
|
|break;
|
|}
|
|}
|
|if (doMatch) {
|
|return true;
|
|}
|
|}
|
|if (secondTpars.isEmpty()) {
|
|// The second signature might be the erasure of the first
|
|boolean doMatch = true;
|
|Iterator<JavaType> k = firstParamTypes.iterator();
|
|Iterator<JavaType> l = secondParamTypes.iterator();
|
|while (k.hasNext()){
|
|if (!l.next().equals(k.next().getErasedType())) {
|
|doMatch = false;
|
|break;
|
|}
|
|}
|
|return doMatch;
|
|}
|
|return false;
|
|}
|
|/**
| For a unary operator, check that the argument is valid,
| then process the operator.
|
private void checkArg(JavaEntity arg1, Operator op)
{
JavaEntity rarg1 = arg1.resolveAsValue();
if (rarg1 == null) {
valueStack.push(new ErrorEntity());
return;
}
doUnaryOp(rarg1, op);
}
| Do a unary plus operation (JLS 3rd ed. 15.15.3)
|
private void doUnaryPlus(ValueEntity arg)
{
JavaType argType = arg.getType();
if (arg.hasConstantIntValue()) {
long value = arg.getConstantIntValue();
JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
valueStack.push(new ConstantIntValue(null, rtype, value));
}
else if (arg.hasConstantFloatValue()) {
double value = arg.getConstantFloatValue();
valueStack.push(new ConstantFloatValue(argType, value));
}
else {
JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
if (rtype != null) {
valueStack.push(new ValueEntity(rtype));
}
else {
valueStack.push(new ErrorEntity());
}
}
}
| Do a unary minus operation (JLS 3rd ed. 15.15.4)
|
private void doUnaryMinus(ValueEntity arg)
{
JavaType argType = arg.getType();
if (arg.hasConstantIntValue()) {
long value = -arg.getConstantIntValue();
JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
valueStack.push(new ConstantIntValue(null, rtype, value));
}
else if (arg.hasConstantFloatValue()) {
double value = -arg.getConstantFloatValue();
valueStack.push(new ConstantFloatValue(argType, value));
}
else {
JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
if (rtype != null) {
valueStack.push(new ValueEntity(rtype));
}
else {
valueStack.push(new ErrorEntity());
}
}
}
| Process a unary operator.
|
private void doUnaryOp(JavaEntity arg, Operator op)
{
ValueEntity varg = arg.resolveAsValue();
if (varg == null) {
valueStack.push(new ErrorEntity());
return;
}
JavaType argType = varg.getType();
int ttype = op.getType();
switch (ttype) {
case JavaTokenTypes.LNOT:
if (varg.hasConstantBooleanValue()) {
boolean rval = ! varg.getConstantBooleanValue();
valueStack.push(new ConstantBoolValue(rval));
}
else if (argType.typeIs(JavaType.JT_BOOLEAN) || argType.toString().equals("java.lang.Boolean")) {
valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
}
else {
valueStack.push(new ErrorEntity());
}
break;
case JavaTokenTypes.BNOT:
if (varg.hasConstantIntValue()) {
long rval = ~ varg.getConstantIntValue();
JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
valueStack.push(new ConstantIntValue(null, rtype, rval));
}
else {
JavaType argTypeUnboxed = TextAnalyzer.unBox(argType);
if (argTypeUnboxed.isIntegralType()) {
valueStack.push(new ValueEntity(TextAnalyzer.unaryNumericPromotion(argTypeUnboxed)));
}
else {
valueStack.push(new ErrorEntity());
}
}
break;
case JavaTokenTypes.INC:
case JavaTokenTypes.DEC:
JavaType argTypeUnboxed = TextAnalyzer.unBox(argType);
if (argTypeUnboxed.isIntegralType()) {
valueStack.push(new ValueEntity(argType));
}
else {
valueStack.push(new ErrorEntity());
}
break;
case UNARY_PLUS_OP:
doUnaryPlus(varg);
break;
case UNARY_MINUS_OP:
doUnaryMinus(varg);
break;
}
}
| Cast an integer value to the given integer type, and return the resulting value.
| The returned value will be within the range of values representable by the type.
|
private long limitResult(JavaType type, long value)
{
if (type.typeIs(JavaType.JT_BYTE)) {
return (byte) value;
}
else if (type.typeIs(JavaType.JT_CHAR)) {
return (char) value;
}
else if (type.typeIs(JavaType.JT_SHORT)) {
return (short) value;
}
else if (type.typeIs(JavaType.JT_INT)) {
return (int) value;
}
return value;
}
| Promote an integer or float to a float, return the result
|
private float promoteToFloat(ValueEntity arg1)
{
if (arg1.hasConstantFloatValue()) {
return (float) arg1.getConstantFloatValue();
}
else {
return arg1.getConstantIntValue();
}
}
| Promote an integer, float or double to a double, return the result.
|
private double promoteToDouble(ValueEntity arg1)
{
if (arg1.hasConstantFloatValue()) {
return (float) arg1.getConstantFloatValue();
}
else {
return arg1.getConstantIntValue();
}
}
| Process the '+' operator
|
private void doOpPlus(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
JavaType a2type = arg2.getType();
GenTypeSolid a1solid = a1type.asSolid();
GenTypeSolid a2solid = a2type.asSolid();
GenTypeClass a1class = null;
GenTypeClass a2class = null;
if (a1solid != null) {
GenTypeClass [] stypes = a1solid.getReferenceSupertypes();
if (stypes.length > 0) {
a1class = a1solid.getReferenceSupertypes()[0];
}
}
if (a2solid != null) {
GenTypeClass [] stypes = a2solid.getReferenceSupertypes();
if (stypes.length > 0) {
a2class = a2solid.getReferenceSupertypes()[0];
}
}
if (a1class != null && a1class.toString().equals("java.lang.String")) {
valueStack.push(new ValueEntity(a1class));
return;
}
if (a2class != null && a2class.toString().equals("java.lang.String")) {
valueStack.push(new ValueEntity(a2class));
return;
}
doBnpOp(op, arg1, arg2);
}
| Process an operator which performs binary numeric promotion and which allows
| the result to be a constant expression.
|
private strictfp void doBnpOp(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
JavaType a2type = arg2.getType();
JavaType resultType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
if (resultType == null) {
valueStack.push(new ErrorEntity());
return;
}
if ((arg1.hasConstantIntValue() || arg1.hasConstantFloatValue())
&& (arg2.hasConstantIntValue() || arg2.hasConstantFloatValue())) {
if (resultType.isIntegralType()) {
long a1 = arg1.getConstantIntValue();
long a2 = arg2.getConstantIntValue();
long rval;
switch (op.type) {
case JavaTokenTypes.PLUS:
rval = a1 + a2; break;
case JavaTokenTypes.MINUS:
rval = a1 - a2; break;
case JavaTokenTypes.STAR:
rval = a1 * a2; break;
case JavaTokenTypes.DIV:
if (a2 == 0) {
valueStack.push(new ValueEntity(resultType));
return;
}
rval = a1 / a2; break;
case JavaTokenTypes.MOD:
if (a2 == 0) {
valueStack.push(new ValueEntity(resultType));
return;
}
rval = a1 % a2; break;
case JavaTokenTypes.BAND:
rval = a1 & a2; break;
case JavaTokenTypes.BOR:
rval = a1 | a2; break;
case JavaTokenTypes.BXOR:
rval = a1 ^ a2; break;
default:
rval = 0; break;
}
rval = limitResult(resultType, rval);
valueStack.push(new ConstantIntValue(null, resultType, rval));
}
else if (resultType.typeIs(JavaType.JT_FLOAT)) {
float a1, a2;
a1 = promoteToFloat(arg1);
a2 = promoteToFloat(arg2);
float rval;
switch (op.type) {
case JavaTokenTypes.PLUS:
rval = a1 + a2; break;
case JavaTokenTypes.MINUS:
rval = a1 - a2; break;
case JavaTokenTypes.STAR:
rval = a1 * a2; break;
case JavaTokenTypes.DIV:
rval = a1 / a2; break;
case JavaTokenTypes.MOD:
rval = a1 % a2; break;
case JavaTokenTypes.BAND:
case JavaTokenTypes.BOR:
case JavaTokenTypes.BXOR:
default:
valueStack.push(new ErrorEntity());
return;
}
valueStack.push(new ConstantFloatValue(resultType, rval));
}
else {
double a1 = promoteToDouble(arg1);
double a2 = promoteToDouble(arg2);
double rval;
switch (op.type) {
case JavaTokenTypes.PLUS:
rval = a1 + a2; break;
case JavaTokenTypes.MINUS:
rval = a1 - a2; break;
case JavaTokenTypes.STAR:
rval = a1 * a2; break;
case JavaTokenTypes.DIV:
rval = a1 / a2; break;
case JavaTokenTypes.MOD:
rval = a1 % a2; break;
case JavaTokenTypes.BAND:
case JavaTokenTypes.BOR:
case JavaTokenTypes.BXOR:
default:
valueStack.push(new ErrorEntity());
return;
}
valueStack.push(new ConstantFloatValue(resultType, rval));
}
return;
}
valueStack.push(new ValueEntity(null, resultType));
}
| Process equality operators '==' and '!='
|
private void doEqualityOp(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
JavaType a2type = arg2.getType();
if (ValueEntity.isConstant(arg1) && ValueEntity.isConstant(arg2)) {
if (a1type.isNumeric()) {
if (! a2type.isNumeric()) {
valueStack.push(new ErrorEntity());
return;
}
JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
if (promotedType.isIntegralType()) {
long a1 = arg1.getConstantIntValue();
long a2 = arg2.getConstantIntValue();
boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
valueStack.push(new ConstantBoolValue(rval));
}
else if (promotedType.typeIs(JavaType.JT_FLOAT)) {
float a1 = promoteToFloat(arg1);
float a2 = promoteToFloat(arg2);
boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
valueStack.push(new ConstantBoolValue(rval));
}
else {
double a1 = promoteToDouble(arg1);
double a2 = promoteToDouble(arg2);
boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
valueStack.push(new ConstantBoolValue(rval));
}
return;
}
if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
boolean a1 = arg1.getConstantBooleanValue();
boolean a2 = arg2.getConstantBooleanValue();
boolean rval = op.type == JavaTokenTypes.EQUAL ? a1 == a2 : a1 != a2;
valueStack.push(new ConstantBoolValue(rval));
return;
}
if (arg1.isConstantString() && arg2.isConstantString()) {
String a1 = arg1.getConstantString();
String a2 = arg2.getConstantString();
boolean rval = (op.type != JavaTokenTypes.EQUAL) ^ a1.equals(a2);
valueStack.push(new ConstantBoolValue(rval));
return;
}
valueStack.push(new ErrorEntity());
}
if (a1type.isNumeric() || a2type.isNumeric()) {
JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
if (promotedType == null) {
valueStack.push(new ErrorEntity());
}
else {
valueStack.push(new ValueEntity("", JavaPrimitiveType.getBoolean()));
}
}
else if (a1type.isNull() && a2type.isNull()
|| a1type.isNull() && a2type.asSolid() != null
|| a1type.asSolid() != null && a2type.isNull()) {
|
valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
}
else if (a1type.asSolid() != null && a2type.asSolid() != null) {
valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
}
else {
valueStack.push(new ErrorEntity());
}
}
| Process a relationship operator - '<', '>', '<=', '>='
|
private void doRelationshipOp(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
JavaType a2type = arg2.getType();
JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
if (promotedType == null) {
valueStack.push(new ErrorEntity());
}
else {
if (ValueEntity.isConstant(arg1) && ValueEntity.isConstant(arg2)) {
if (promotedType.isIntegralType()) {
long a1 = arg1.getConstantIntValue();
long a2 = arg2.getConstantIntValue();
boolean rval;
switch (op.type) {
case JavaTokenTypes.LT:
rval = a1 < a2; break;
case JavaTokenTypes.LE:
rval = a1 <= a2; break;
case JavaTokenTypes.GT:
rval = a1 > a2; break;
default:
rval = a1 >= a2;
}
valueStack.push(new ConstantBoolValue(rval));
}
else if (promotedType.typeIs(JavaType.JT_FLOAT)) {
float a1 = promoteToFloat(arg1);
float a2 = promoteToFloat(arg2);
boolean rval;
switch (op.type) {
case JavaTokenTypes.LT:
rval = a1 < a2; break;
case JavaTokenTypes.LE:
rval = a1 <= a2; break;
case JavaTokenTypes.GT:
rval = a1 > a2; break;
default:
rval = a1 >= a2;
}
valueStack.push(new ConstantBoolValue(rval));
}
else {
double a1 = promoteToDouble(arg1);
double a2 = promoteToDouble(arg2);
boolean rval;
switch (op.type) {
case JavaTokenTypes.LT:
rval = a1 < a2; break;
case JavaTokenTypes.LE:
rval = a1 <= a2; break;
case JavaTokenTypes.GT:
rval = a1 > a2; break;
default:
rval = a1 >= a2;
}
valueStack.push(new ConstantBoolValue(rval));
}
return;
}
valueStack.push(new ValueEntity("", JavaPrimitiveType.getBoolean()));
}
}
| Do a bitwise operation - '&', '|' or '^'
|
private void doBitwiseOp(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
if (a1type.typeIs(JavaType.JT_BOOLEAN)
|| a1type.toString().equals("java.lang.Boolean")) {
JavaType a2type = arg2.getType();
if (a2type.typeIs(JavaType.JT_BOOLEAN)
|| a2type.toString().equals("java.lang.Boolean")) {
if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
boolean a1 = arg1.getConstantBooleanValue();
boolean a2 = arg2.getConstantBooleanValue();
boolean rval;
switch (op.type) {
case JavaTokenTypes.BAND:
rval = a1 & a2;
break;
case JavaTokenTypes.BOR:
rval = a1 | a2;
break;
default:
rval = a1 ^ a2;
}
valueStack.push(new ConstantBoolValue(rval));
}
else {
valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
}
return;
}
}
doBnpOp(op, arg1, arg2);
}
| Do a logical operation - '&&' or '||'
| @param op
| @param arg1
| @param arg2
|
private void doLogicalOp(Operator op, ValueEntity arg1, ValueEntity arg2)
{
JavaType a1type = arg1.getType();
if (a1type.typeIs(JavaType.JT_BOOLEAN)
|| a1type.toString().equals("java.lang.Boolean")) {
JavaType a2type = arg2.getType();
if (a2type.typeIs(JavaType.JT_BOOLEAN)
|| a2type.toString().equals("java.lang.Boolean")) {
if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
boolean a1 = arg1.getConstantBooleanValue();
boolean a2 = arg2.getConstantBooleanValue();
boolean rval;
switch (op.type) {
case JavaTokenTypes.LAND:
rval = a1 && a2;
default:
rval = a1 || a2;
}
valueStack.push(new ConstantBoolValue(rval));
}
else {
valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
}
return;
}
}
valueStack.push(new ErrorEntity());
}
| Process a binary operator. Arguments have been resolved as values.
| The result is pushed back onto the value stack.
|
private void doBinaryOp(JavaEntity uarg1, JavaEntity uarg2, Operator op)
{
ValueEntity arg1 = uarg1.resolveAsValue();
ValueEntity arg2 = uarg2.resolveAsValue();
if (arg1 == null || arg2 == null) {
valueStack.push(new ErrorEntity());
return;
}
JavaType a1type = arg1.getType().getCapture();
int ttype = op.getType();
switch (ttype) {
case JavaTokenTypes.PLUS:
doOpPlus(op, arg1, arg2);
return;
case JavaTokenTypes.MINUS:
case JavaTokenTypes.STAR:
case JavaTokenTypes.DIV:
case JavaTokenTypes.MOD:
doBnpOp(op, arg1, arg2);
break;
case JavaTokenTypes.BAND:
case JavaTokenTypes.BOR:
case JavaTokenTypes.BXOR:
doBitwiseOp(op, arg1, arg2);
break;
case JavaTokenTypes.LOR:
case JavaTokenTypes.LAND:
doLogicalOp(op, arg1, arg2);
break;
case JavaTokenTypes.SL:
case JavaTokenTypes.SR:
case JavaTokenTypes.BSR:
JavaType a1typeP = TextAnalyzer.unaryNumericPromotion(a1type);
JavaType a2typeP = TextAnalyzer.unaryNumericPromotion(a1type);
if (a1typeP == null || a2typeP == null || !a1typeP.isIntegralType()
|| ! a2typeP.isIntegralType()) {
valueStack.push(new ErrorEntity());
}
else {
if (arg1.hasConstantIntValue() && arg2.hasConstantIntValue()) {
long a1 = arg1.getConstantIntValue();
long a2 = arg2.getConstantIntValue();
long rval;
if (ttype == JavaTokenTypes.SL) {
rval = a1 << a2;
}
else if (ttype == JavaTokenTypes.SR) {
rval = a1 >> a2;
}
else {
rval = a1 >>> a2;
}
rval = limitResult(a1typeP, rval);
valueStack.push(new ConstantIntValue(null, a1typeP, rval));
}
else {
valueStack.push(new ValueEntity("", a1typeP));
}
}
break;
case JavaTokenTypes.LT:
case JavaTokenTypes.LE:
case JavaTokenTypes.GT:
case JavaTokenTypes.GE:
doRelationshipOp(op, arg1, arg2);
break;
case JavaTokenTypes.EQUAL:
case JavaTokenTypes.NOT_EQUAL:
doEqualityOp(op, arg1, arg2);
break;
case JavaTokenTypes.ASSIGN:
case JavaTokenTypes.BAND_ASSIGN:
case JavaTokenTypes.BOR_ASSIGN:
case JavaTokenTypes.PLUS_ASSIGN:
case JavaTokenTypes.MINUS_ASSIGN:
case JavaTokenTypes.STAR_ASSIGN:
case JavaTokenTypes.DIV_ASSIGN:
case JavaTokenTypes.SL_ASSIGN:
case JavaTokenTypes.SR_ASSIGN:
case JavaTokenTypes.BSR_ASSIGN:
case JavaTokenTypes.MOD_ASSIGN:
case JavaTokenTypes.BXOR_ASSIGN:
valueStack.push(arg1);
break;
case JavaTokenTypes.DOT:
valueStack.push(new ErrorEntity());
default:
}
}
private void processQuestionOperator()
{
JavaEntity rhs = popValueStack();
JavaEntity lhs = popValueStack();
JavaEntity condition = popValueStack();
ValueEntity conditionv = condition.resolveAsValue();
if (conditionv == null) {
valueStack.push(new ErrorEntity());
return;
}
JavaType ctype = conditionv.getType();
if (!ctype.typeIs(JavaType.JT_BOOLEAN) && !ctype.toString().equals("java.lang.Boolean")) {
valueStack.push(new ErrorEntity());
return;
}
ValueEntity rhsv = rhs.resolveAsValue();
ValueEntity lhsv = lhs.resolveAsValue();
if (rhsv == null || lhsv == null) {
valueStack.push(new ErrorEntity());
return;
}
ValueEntity rent = TextAnalyzer.questionOperator15(conditionv, lhsv, rhsv);
valueStack.push(rent);
}
@Override
protected void beginExpression(LocatableToken token)
{
operatorStack.push(new Operator(PAREN_OPERATOR, token));
}
@Override
protected void endExpression(LocatableToken token, boolean isEmpty)
{
if (isEmpty) {
valueStack.push(new ErrorEntity());
}
processHigherPrecedence(getPrecedence(PAREN_OPERATOR));
operatorStack.pop();
if (!operatorStack.isEmpty()) {
if (operatorStack.peek().type == JavaTokenTypes.LCURLY) {
popValueStack();
}
}
}
private void gotStringLiteral(LocatableToken token)
{
String ctext = token.getText();
StringBuffer sb = new StringBuffer(ctext.length());
for (int pos = 1; pos < ctext.length(); pos++) {
char c = ctext.charAt(pos);
if (c == '\"') {
break; }
if (c == '\\') {
c = ctext.charAt(2);
if (c == 'b') {
c = '\b';
}
else if (c == 't') {
c = '\t';
}
else if (c == 'n') {
c = '\n';
}
else if (c == 'f') {
c = '\f';
}
else if (c == 'r') {
c = '\r';
}
else if (c == '\'') {
c = '\'';
}
else if (c == '\"') {
c = '\"';
}
else if (c == '\\') {
c = '\\';
}
else if (c >= '0' && c <= '7') {
int val = c - '0';
while (++pos < ctext.length()){
char d = ctext.charAt(pos);
if (d == '\'') break;
if (d < '0' || d > '7') {
valueStack.push(new ErrorEntity());
return;
}
val = val * 8 + (d - '0');
if (val > 0377) {
valueStack.push(new ErrorEntity());
return;
}
}
c = (char) val;
}
else {
valueStack.push(new ErrorEntity());
return;
}
}
sb.append(c);
}
JavaType stringType = new GenTypeClass(new JavaReflective(String.class));
ValueEntity ent = new ConstantStringEntity(stringType, sb.toString());
valueStack.push(ent);
}
@Override
protected void gotLiteral(LocatableToken token)
{
if (token.getType() == JavaTokenTypes.CHAR_LITERAL) {
String ctext = token.getText();
char c = ctext.charAt(1);
if (c == '\\') {
c = ctext.charAt(2);
if (c == 'b') {
c = '\b';
}
else if (c == 't') {
c = '\t';
}
else if (c == 'n') {
c = '\n';
}
else if (c == 'f') {
c = '\f';
}
else if (c == 'r') {
c = '\r';
}
else if (c == '\'') {
c = '\'';
}
else if (c == '\"') {
c = '\"';
}
else if (c == '\\') {
c = '\\';
}
else if (c >= '0' && c <= '7') {
int val = c - '0';
int pos = 3;
while (pos < ctext.length()){
char d = ctext.charAt(pos++);
if (d == '\'') break;
if (d < '0' || d > '7') {
valueStack.push(new ErrorEntity());
return;
}
val = val * 8 + (d - '0');
if (val > 0377) {
valueStack.push(new ErrorEntity());
return;
}
}
c = (char) val;
}
else {
valueStack.push(new ErrorEntity());
return;
}
}
valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getChar(), c));
}
else if (token.getType() == JavaTokenTypes.NUM_INT) {
try {
valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getInt(), Integer.decode(token.getText())));
}
catch (NumberFormatException nfe) {
valueStack.push(new ErrorEntity());
}
}
else if (token.getType() == JavaTokenTypes.NUM_LONG) {
try {
String text = token.getText();
text = text.substring(0, text.length() - 1);
valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getLong(), Long.decode(text)));
}
catch (NumberFormatException nfe) {
valueStack.push(new ErrorEntity());
}
}
else if (token.getType() == JavaTokenTypes.NUM_FLOAT) {
try {
valueStack.push(new ConstantFloatValue(JavaPrimitiveType.getFloat(), Float.parseFloat(token.getText())));
}
catch (NumberFormatException nfe) {
valueStack.push(new ErrorEntity());
}
}
else if (token.getType() == JavaTokenTypes.NUM_DOUBLE) {
try {
valueStack.push(new ConstantFloatValue(JavaPrimitiveType.getDouble(), Double.parseDouble(token.getText())));
}
catch (NumberFormatException nfe) {
valueStack.push(new ErrorEntity());
}
}
else if (token.getType() == JavaTokenTypes.LITERAL_null) {
valueStack.push(new NullEntity());
}
else if (token.getType() == JavaTokenTypes.STRING_LITERAL) {
gotStringLiteral(token);
}
else if (token.getType() == JavaTokenTypes.LITERAL_true
|| token.getType() == JavaTokenTypes.LITERAL_false) {
|
valueStack.push(new ConstantBoolValue(token.getType() == JavaTokenTypes.LITERAL_true));
}
else if (token.getType() == JavaTokenTypes.LITERAL_this) {
if (staticAccess) {
valueStack.push(new ErrorEntity());
}
else {
JavaType type = accessType.getType();
if (type != null) {
valueStack.push(new ValueEntity(type));
}
else {
valueStack.push(new ErrorEntity());
}
}
}
else if (token.getType() == JavaTokenTypes.LITERAL_super)
{
for (JavaType type : accessType.getType().asClass().getReflective().getSuperTypes())
{
if (type != null)
{
valueStack.push(new ValueEntity(type));
}
else
{
valueStack.push(new ErrorEntity());
}
}
}
else
{
valueStack.push(new ErrorEntity());
}
}
@Override