javassist.compiler.TypeChecker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.compiler;
import javassist.CtClass;
import javassist.CtField;
import javassist.ClassPool;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.compiler.ast.*;
import javassist.bytecode.*;
public class TypeChecker extends Visitor implements Opcode, TokenId {
static final String javaLangObject = "java.lang.Object";
static final String jvmJavaLangObject = "java/lang/Object";
static final String jvmJavaLangString = "java/lang/String";
static final String jvmJavaLangClass = "java/lang/Class";
/* The following fields are used by atXXX() methods
* for returning the type of the compiled expression.
*/
protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
protected int arrayDim;
protected String className; // JVM-internal representation
protected MemberResolver resolver;
protected CtClass thisClass;
protected MethodInfo thisMethod;
public TypeChecker(CtClass cc, ClassPool cp) {
resolver = new MemberResolver(cp);
thisClass = cc;
thisMethod = null;
}
/*
* Converts an array of tuples of exprType, arrayDim, and className
* into a String object.
*/
protected static String argTypesToString(int[] types, int[] dims,
String[] cnames) {
StringBuffer sbuf = new StringBuffer();
sbuf.append('(');
int n = types.length;
if (n > 0) {
int i = 0;
while (true) {
typeToString(sbuf, types[i], dims[i], cnames[i]);
if (++i < n)
sbuf.append(',');
else
break;
}
}
sbuf.append(')');
return sbuf.toString();
}
/*
* Converts a tuple of exprType, arrayDim, and className
* into a String object.
*/
protected static StringBuffer typeToString(StringBuffer sbuf,
int type, int dim, String cname) {
String s;
if (type == CLASS)
s = MemberResolver.jvmToJavaName(cname);
else if (type == NULL)
s = "Object";
else
try {
s = MemberResolver.getTypeName(type);
}
catch (CompileError e) {
s = "?";
}
sbuf.append(s);
while (dim-- > 0)
sbuf.append("[]");
return sbuf;
}
/**
* Records the currently compiled method.
*/
public void setThisMethod(MethodInfo m) {
thisMethod = m;
}
protected static void fatal() throws CompileError {
throw new CompileError("fatal");
}
/**
* Returns the JVM-internal representation of this class name.
*/
protected String getThisName() {
return MemberResolver.javaToJvmName(thisClass.getName());
}
/**
* Returns the JVM-internal representation of this super class name.
*/
protected String getSuperName() throws CompileError {
return MemberResolver.javaToJvmName(
MemberResolver.getSuperclass(thisClass).getName());
}
/* Converts a class name into a JVM-internal representation.
*
* It may also expand a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object.
*/
protected String resolveClassName(ASTList name) throws CompileError {
return resolver.resolveClassName(name);
}
/* Expands a simple class name to java.lang.*.
* For example, this converts Object into java/lang/Object.
*/
protected String resolveClassName(String jvmName) throws CompileError {
return resolver.resolveJvmClassName(jvmName);
}
public void atNewExpr(NewExpr expr) throws CompileError {
if (expr.isArray())
atNewArrayExpr(expr);
else {
CtClass clazz = resolver.lookupClassByName(expr.getClassName());
String cname = clazz.getName();
ASTList args = expr.getArguments();
atMethodCallCore(clazz, MethodInfo.nameInit, args);
exprType = CLASS;
arrayDim = 0;
className = MemberResolver.javaToJvmName(cname);
}
}
public void atNewArrayExpr(NewExpr expr) throws CompileError {
int type = expr.getArrayType();
ASTList size = expr.getArraySize();
ASTList classname = expr.getClassName();
ASTree init = expr.getInitializer();
if (init != null)
init.accept(this);
if (size.length() > 1)
atMultiNewArray(type, classname, size);
else {
ASTree sizeExpr = size.head();
if (sizeExpr != null)
sizeExpr.accept(this);
exprType = type;
arrayDim = 1;
if (type == CLASS)
className = resolveClassName(classname);
else
className = null;
}
}
public void atArrayInit(ArrayInit init) throws CompileError {
ASTList list = init;
while (list != null) {
ASTree h = list.head();
list = list.tail();
if (h != null)
h.accept(this);
}
}
protected void atMultiNewArray(int type, ASTList classname, ASTList size)
throws CompileError
{
int count, dim;
dim = size.length();
for (count = 0; size != null; size = size.tail()) {
ASTree s = size.head();
if (s == null)
break; // int[][][] a = new int[3][4][];
++count;
s.accept(this);
}
exprType = type;
arrayDim = dim;
if (type == CLASS)
className = resolveClassName(classname);
else
className = null;
}
public void atAssignExpr(AssignExpr expr) throws CompileError {
// =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
int op = expr.getOperator();
ASTree left = expr.oprand1();
ASTree right = expr.oprand2();
if (left instanceof Variable)
atVariableAssign(expr, op, (Variable)left,
((Variable)left).getDeclarator(),
right);
else {
if (left instanceof Expr) {
Expr e = (Expr)left;
if (e.getOperator() == ARRAY) {
atArrayAssign(expr, op, (Expr)left, right);
return;
}
}
atFieldAssign(expr, op, left, right);
}
}
/* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
*
* expr and var can be null.
*/
private void atVariableAssign(Expr expr, int op, Variable var,
Declarator d, ASTree right)
throws CompileError
{
int varType = d.getType();
int varArray = d.getArrayDim();
String varClass = d.getClassName();
if (op != '=')
atVariable(var);
right.accept(this);
exprType = varType;
arrayDim = varArray;
className = varClass;
}
private void atArrayAssign(Expr expr, int op, Expr array,
ASTree right) throws CompileError
{
atArrayRead(array.oprand1(), array.oprand2());
int aType = exprType;
int aDim = arrayDim;
String cname = className;
right.accept(this);
exprType = aType;
arrayDim = aDim;
className = cname;
}
protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
throws CompileError
{
CtField f = fieldAccess(left);
atFieldRead(f);
int fType = exprType;
int fDim = arrayDim;
String cname = className;
right.accept(this);
exprType = fType;
arrayDim = fDim;
className = cname;
}
public void atCondExpr(CondExpr expr) throws CompileError {
booleanExpr(expr.condExpr());
expr.thenExpr().accept(this);
int type1 = exprType;
int dim1 = arrayDim;
String cname1 = className;
expr.elseExpr().accept(this);
if (dim1 == 0 && dim1 == arrayDim)
if (CodeGen.rightIsStrong(type1, exprType))
expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
else if (CodeGen.rightIsStrong(exprType, type1)) {
expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
exprType = type1;
}
}
/*
* If atBinExpr() substitutes a new expression for the original
* binary-operator expression, it changes the operator name to '+'
* (if the original is not '+') and sets the new expression to the
* left-hand-side expression and null to the right-hand-side expression.
*/
public void atBinExpr(BinExpr expr) throws CompileError {
int token = expr.getOperator();
int k = CodeGen.lookupBinOp(token);
if (k >= 0) {
/* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
*/
if (token == '+') {
Expr e = atPlusExpr(expr);
if (e != null) {
/* String concatenation has been translated into
* an expression using StringBuffer.
*/
e = CallExpr.makeCall(Expr.make('.', e,
new Member("toString")), null);
expr.setOprand1(e);
expr.setOprand2(null); // <---- look at this!
className = jvmJavaLangString;
}
}
else {
ASTree left = expr.oprand1();
ASTree right = expr.oprand2();
left.accept(this);
int type1 = exprType;
right.accept(this);
if (!isConstant(expr, token, left, right))
computeBinExprType(expr, token, type1);
}
}
else {
/* equation: &&, ||, ==, !=, <=, >=, <, >
*/
booleanExpr(expr);
}
}
/* EXPR must be a + expression.
* atPlusExpr() returns non-null if the given expression is string
* concatenation. The returned value is "new StringBuffer().append..".
*/
private Expr atPlusExpr(BinExpr expr) throws CompileError {
ASTree left = expr.oprand1();
ASTree right = expr.oprand2();
if (right == null) {
// this expression has been already type-checked.
// see atBinExpr() above.
left.accept(this);
return null;
}
if (isPlusExpr(left)) {
Expr newExpr = atPlusExpr((BinExpr)left);
if (newExpr != null) {
right.accept(this);
exprType = CLASS;
arrayDim = 0;
className = "java/lang/StringBuffer";
return makeAppendCall(newExpr, right);
}
}
else
left.accept(this);
int type1 = exprType;
int dim1 = arrayDim;
String cname = className;
right.accept(this);
if (isConstant(expr, '+', left, right))
return null;
if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
|| (exprType == CLASS && arrayDim == 0
&& jvmJavaLangString.equals(className))) {
ASTList sbufClass = ASTList.make(new Symbol("java"),
new Symbol("lang"), new Symbol("StringBuffer"));
ASTree e = new NewExpr(sbufClass, null);
exprType = CLASS;
arrayDim = 0;
className = "java/lang/StringBuffer";
return makeAppendCall(makeAppendCall(e, left), right);
}
else {
computeBinExprType(expr, '+', type1);
return null;
}
}
private boolean isConstant(BinExpr expr, int op, ASTree left,
ASTree right) throws CompileError
{
left = stripPlusExpr(left);
right = stripPlusExpr(right);
ASTree newExpr = null;
if (left instanceof StringL && right instanceof StringL && op == '+')
newExpr = new StringL(((StringL)left).get()
+ ((StringL)right).get());
else if (left instanceof IntConst)
newExpr = ((IntConst)left).compute(op, right);
else if (left instanceof DoubleConst)
newExpr = ((DoubleConst)left).compute(op, right);
if (newExpr == null)
return false; // not a constant expression
else {
expr.setOperator('+');
expr.setOprand1(newExpr);
expr.setOprand2(null);
newExpr.accept(this); // for setting exprType, arrayDim, ...
return true;
}
}
/* CodeGen.atSwitchStmnt() also calls stripPlusExpr().
*/
static ASTree stripPlusExpr(ASTree expr) {
if (expr instanceof BinExpr) {
BinExpr e = (BinExpr)expr;
if (e.getOperator() == '+' && e.oprand2() == null)
return e.getLeft();
}
else if (expr instanceof Expr) { // note: BinExpr extends Expr.
Expr e = (Expr)expr;
int op = e.getOperator();
if (op == MEMBER) {
ASTree cexpr = getConstantFieldValue((Member)e.oprand2());
if (cexpr != null)
return cexpr;
}
else if (op == '+' && e.getRight() == null)
return e.getLeft();
}
else if (expr instanceof Member) {
ASTree cexpr = getConstantFieldValue((Member)expr);
if (cexpr != null)
return cexpr;
}
return expr;
}
/**
* If MEM is a static final field, this method returns a constant
* expression representing the value of that field.
*/
private static ASTree getConstantFieldValue(Member mem) {
return getConstantFieldValue(mem.getField());
}
public static ASTree getConstantFieldValue(CtField f) {
if (f == null)
return null;
Object value = f.getConstantValue();
if (value == null)
return null;
if (value instanceof String)
return new StringL((String)value);
else if (value instanceof Double || value instanceof Float) {
int token = (value instanceof Double)
? DoubleConstant : FloatConstant;
return new DoubleConst(((Number)value).doubleValue(), token);
}
else if (value instanceof Number) {
int token = (value instanceof Long) ? LongConstant : IntConstant;
return new IntConst(((Number)value).longValue(), token);
}
else if (value instanceof Boolean)
return new Keyword(((Boolean)value).booleanValue()
? TokenId.TRUE : TokenId.FALSE);
else
return null;
}
private static boolean isPlusExpr(ASTree expr) {
if (expr instanceof BinExpr) {
BinExpr bexpr = (BinExpr)expr;
int token = bexpr.getOperator();
return token == '+';
}
return false;
}
private static Expr makeAppendCall(ASTree target, ASTree arg) {
return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
new ASTList(arg));
}
private void computeBinExprType(BinExpr expr, int token, int type1)
throws CompileError
{
// arrayDim should be 0.
int type2 = exprType;
if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
exprType = type1;
else
insertCast(expr, type1, type2);
if (CodeGen.isP_INT(exprType))
exprType = INT; // type1 may be BYTE, ...
}
private void booleanExpr(ASTree expr)
throws CompileError
{
int op = CodeGen.getCompOperator(expr);
if (op == EQ) { // ==, !=, ...
BinExpr bexpr = (BinExpr)expr;
bexpr.oprand1().accept(this);
int type1 = exprType;
int dim1 = arrayDim;
bexpr.oprand2().accept(this);
if (dim1 == 0 && arrayDim == 0)
insertCast(bexpr, type1, exprType);
}
else if (op == '!')
((Expr)expr).oprand1().accept(this);
else if (op == ANDAND || op == OROR) {
BinExpr bexpr = (BinExpr)expr;
bexpr.oprand1().accept(this);
bexpr.oprand2().accept(this);
}
else // others
expr.accept(this);
exprType = BOOLEAN;
arrayDim = 0;
}
private void insertCast(BinExpr expr, int type1, int type2)
throws CompileError
{
if (CodeGen.rightIsStrong(type1, type2))
expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
else
exprType = type1;
}
public void atCastExpr(CastExpr expr) throws CompileError {
String cname = resolveClassName(expr.getClassName());
expr.getOprand().accept(this);
exprType = expr.getType();
arrayDim = expr.getArrayDim();
className = cname;
}
public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
expr.getOprand().accept(this);
exprType = BOOLEAN;
arrayDim = 0;
}
public void atExpr(Expr expr) throws CompileError {
// array access, member access,
// (unary) +, (unary) -, ++, --, !, ~
int token = expr.getOperator();
ASTree oprand = expr.oprand1();
if (token == '.') {
String member = ((Symbol)expr.oprand2()).get();
if (member.equals("length"))
try {
atArrayLength(expr);
}
catch (NoFieldException nfe) {
// length might be a class or package name.
atFieldRead(expr);
}
else if (member.equals("class"))
atClassObject(expr); // .class
else
atFieldRead(expr);
}
else if (token == MEMBER) { // field read
String member = ((Symbol)expr.oprand2()).get();
if (member.equals("class"))
atClassObject(expr); // .class
else
atFieldRead(expr);
}
else if (token == ARRAY)
atArrayRead(oprand, expr.oprand2());
else if (token == PLUSPLUS || token == MINUSMINUS)
atPlusPlus(token, oprand, expr);
else if (token == '!')
booleanExpr(expr);
else if (token == CALL) // method call
fatal();
else {
oprand.accept(this);
if (!isConstant(expr, token, oprand))
if (token == '-' || token == '~')
if (CodeGen.isP_INT(exprType))
exprType = INT; // type may be BYTE, ...
}
}
private boolean isConstant(Expr expr, int op, ASTree oprand) {
oprand = stripPlusExpr(oprand);
if (oprand instanceof IntConst) {
IntConst c = (IntConst)oprand;
long v = c.get();
if (op == '-')
v = -v;
else if (op == '~')
v = ~v;
else
return false;
c.set(v);
}
else if (oprand instanceof DoubleConst) {
DoubleConst c = (DoubleConst)oprand;
if (op == '-')
c.set(-c.get());
else
return false;
}
else
return false;
expr.setOperator('+');
return true;
}
public void atCallExpr(CallExpr expr) throws CompileError {
String mname = null;
CtClass targetClass = null;
ASTree method = expr.oprand1();
ASTList args = (ASTList)expr.oprand2();
if (method instanceof Member) {
mname = ((Member)method).get();
targetClass = thisClass;
}
else if (method instanceof Keyword) { // constructor
mname = MethodInfo.nameInit; //
if (((Keyword)method).get() == SUPER)
targetClass = MemberResolver.getSuperclass(thisClass);
else
targetClass = thisClass;
}
else if (method instanceof Expr) {
Expr e = (Expr)method;
mname = ((Symbol)e.oprand2()).get();
int op = e.getOperator();
if (op == MEMBER) // static method
targetClass
= resolver.lookupClass(((Symbol)e.oprand1()).get(),
false);
else if (op == '.') {
ASTree target = e.oprand1();
try {
target.accept(this);
}
catch (NoFieldException nfe) {
if (nfe.getExpr() != target)
throw nfe;
// it should be a static method.
exprType = CLASS;
arrayDim = 0;
className = nfe.getField(); // JVM-internal
e.setOperator(MEMBER);
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
className)));
}
if (arrayDim > 0)
targetClass = resolver.lookupClass(javaLangObject, true);
else if (exprType == CLASS /* && arrayDim == 0 */)
targetClass = resolver.lookupClassByJvmName(className);
else
badMethod();
}
else
badMethod();
}
else
fatal();
MemberResolver.Method minfo
= atMethodCallCore(targetClass, mname, args);
expr.setMethod(minfo);
}
private static void badMethod() throws CompileError {
throw new CompileError("bad method");
}
/**
* @return a pair of the class declaring the invoked method
* and the MethodInfo of that method. Never null.
*/
public MemberResolver.Method atMethodCallCore(CtClass targetClass,
String mname, ASTList args)
throws CompileError
{
int nargs = getMethodArgsLength(args);
int[] types = new int[nargs];
int[] dims = new int[nargs];
String[] cnames = new String[nargs];
atMethodArgs(args, types, dims, cnames);
MemberResolver.Method found
= resolver.lookupMethod(targetClass, thisClass, thisMethod,
mname, types, dims, cnames);
if (found == null) {
String clazz = targetClass.getName();
String signature = argTypesToString(types, dims, cnames);
String msg;
if (mname.equals(MethodInfo.nameInit))
msg = "cannot find constructor " + clazz + signature;
else
msg = mname + signature + " not found in " + clazz;
throw new CompileError(msg);
}
String desc = found.info.getDescriptor();
setReturnType(desc);
return found;
}
public int getMethodArgsLength(ASTList args) {
return ASTList.length(args);
}
public void atMethodArgs(ASTList args, int[] types, int[] dims,
String[] cnames) throws CompileError {
int i = 0;
while (args != null) {
ASTree a = args.head();
a.accept(this);
types[i] = exprType;
dims[i] = arrayDim;
cnames[i] = className;
++i;
args = args.tail();
}
}
void setReturnType(String desc) throws CompileError {
int i = desc.indexOf(')');
if (i < 0)
badMethod();
char c = desc.charAt(++i);
int dim = 0;
while (c == '[') {
++dim;
c = desc.charAt(++i);
}
arrayDim = dim;
if (c == 'L') {
int j = desc.indexOf(';', i + 1);
if (j < 0)
badMethod();
exprType = CLASS;
className = desc.substring(i + 1, j);
}
else {
exprType = MemberResolver.descToType(c);
className = null;
}
}
private void atFieldRead(ASTree expr) throws CompileError {
atFieldRead(fieldAccess(expr));
}
private void atFieldRead(CtField f) throws CompileError {
FieldInfo finfo = f.getFieldInfo2();
String type = finfo.getDescriptor();
int i = 0;
int dim = 0;
char c = type.charAt(i);
while (c == '[') {
++dim;
c = type.charAt(++i);
}
arrayDim = dim;
exprType = MemberResolver.descToType(c);
if (c == 'L')
className = type.substring(i + 1, type.indexOf(';', i + 1));
else
className = null;
}
/* if EXPR is to access a static field, fieldAccess() translates EXPR
* into an expression using '#' (MEMBER). For example, it translates
* java.lang.Integer.TYPE into java.lang.Integer#TYPE. This translation
* speeds up type resolution by MemberCodeGen.
*/
protected CtField fieldAccess(ASTree expr) throws CompileError {
if (expr instanceof Member) {
Member mem = (Member)expr;
String name = mem.get();
try {
CtField f = thisClass.getField(name);
if (Modifier.isStatic(f.getModifiers()))
mem.setField(f);
return f;
}
catch (NotFoundException e) {
// EXPR might be part of a static member access?
throw new NoFieldException(name, expr);
}
}
else if (expr instanceof Expr) {
Expr e = (Expr)expr;
int op = e.getOperator();
if (op == MEMBER) {
Member mem = (Member)e.oprand2();
CtField f
= resolver.lookupField(((Symbol)e.oprand1()).get(), mem);
mem.setField(f);
return f;
}
else if (op == '.') {
try {
e.oprand1().accept(this);
}
catch (NoFieldException nfe) {
if (nfe.getExpr() != e.oprand1())
throw nfe;
/* EXPR should be a static field.
* If EXPR might be part of a qualified class name,
* lookupFieldByJvmName2() throws NoFieldException.
*/
return fieldAccess2(e, nfe.getField());
}
CompileError err = null;
try {
if (exprType == CLASS && arrayDim == 0)
return resolver.lookupFieldByJvmName(className,
(Symbol)e.oprand2());
}
catch (CompileError ce) {
err = ce;
}
/* If a filed name is the same name as a package's,
* a static member of a class in that package is not
* visible. For example,
*
* class Foo {
* int javassist;
* }
*
* It is impossible to add the following method:
*
* String m() { return javassist.CtClass.intType.toString(); }
*
* because javassist is a field name. However, this is
* often inconvenient, this compiler allows it. The following
* code is for that.
*/
ASTree oprnd1 = e.oprand1();
if (oprnd1 instanceof Symbol)
return fieldAccess2(e, ((Symbol)oprnd1).get());
if (err != null)
throw err;
}
}
throw new CompileError("bad filed access");
}
private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError {
Member fname = (Member)e.oprand2();
CtField f = resolver.lookupFieldByJvmName2(jvmClassName, fname, e);
e.setOperator(MEMBER);
e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName)));
fname.setField(f);
return f;
}
public void atClassObject(Expr expr) throws CompileError {
exprType = CLASS;
arrayDim = 0;
className =jvmJavaLangClass;
}
public void atArrayLength(Expr expr) throws CompileError {
expr.oprand1().accept(this);
if (arrayDim == 0)
throw new NoFieldException("length", expr);
exprType = INT;
arrayDim = 0;
}
public void atArrayRead(ASTree array, ASTree index)
throws CompileError
{
array.accept(this);
int type = exprType;
int dim = arrayDim;
String cname = className;
index.accept(this);
exprType = type;
arrayDim = dim - 1;
className = cname;
}
private void atPlusPlus(int token, ASTree oprand, Expr expr)
throws CompileError
{
boolean isPost = oprand == null; // ++i or i++?
if (isPost)
oprand = expr.oprand2();
if (oprand instanceof Variable) {
Declarator d = ((Variable)oprand).getDeclarator();
exprType = d.getType();
arrayDim = d.getArrayDim();
}
else {
if (oprand instanceof Expr) {
Expr e = (Expr)oprand;
if (e.getOperator() == ARRAY) {
atArrayRead(e.oprand1(), e.oprand2());
// arrayDim should be 0.
int t = exprType;
if (t == INT || t == BYTE || t == CHAR || t == SHORT)
exprType = INT;
return;
}
}
atFieldPlusPlus(oprand);
}
}
protected void atFieldPlusPlus(ASTree oprand) throws CompileError
{
CtField f = fieldAccess(oprand);
atFieldRead(f);
int t = exprType;
if (t == INT || t == BYTE || t == CHAR || t == SHORT)
exprType = INT;
}
public void atMember(Member mem) throws CompileError {
atFieldRead(mem);
}
public void atVariable(Variable v) throws CompileError {
Declarator d = v.getDeclarator();
exprType = d.getType();
arrayDim = d.getArrayDim();
className = d.getClassName();
}
public void atKeyword(Keyword k) throws CompileError {
arrayDim = 0;
int token = k.get();
switch (token) {
case TRUE :
case FALSE :
exprType = BOOLEAN;
break;
case NULL :
exprType = NULL;
break;
case THIS :
case SUPER :
exprType = CLASS;
if (token == THIS)
className = getThisName();
else
className = getSuperName();
break;
default :
fatal();
}
}
public void atStringL(StringL s) throws CompileError {
exprType = CLASS;
arrayDim = 0;
className = jvmJavaLangString;
}
public void atIntConst(IntConst i) throws CompileError {
arrayDim = 0;
int type = i.getType();
if (type == IntConstant || type == CharConstant)
exprType = (type == IntConstant ? INT : CHAR);
else
exprType = LONG;
}
public void atDoubleConst(DoubleConst d) throws CompileError {
arrayDim = 0;
if (d.getType() == DoubleConstant)
exprType = DOUBLE;
else
exprType = FLOAT;
}
}