001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.compiler;
017:
018: import javassist.*;
019: import javassist.compiler.ast.*;
020:
021: /* Type checker accepting extended Java syntax for Javassist.
022: */
023:
024: public class JvstTypeChecker extends TypeChecker {
025: private JvstCodeGen codeGen;
026:
027: public JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen) {
028: super (cc, cp);
029: codeGen = gen;
030: }
031:
032: /* If the type of the expression compiled last is void,
033: * add ACONST_NULL and change exprType, arrayDim, className.
034: */
035: public void addNullIfVoid() {
036: if (exprType == VOID) {
037: exprType = CLASS;
038: arrayDim = 0;
039: className = jvmJavaLangObject;
040: }
041: }
042:
043: /* To support $args, $sig, and $type.
044: * $args is an array of parameter list.
045: */
046: public void atMember(Member mem) throws CompileError {
047: String name = mem.get();
048: if (name.equals(codeGen.paramArrayName)) {
049: exprType = CLASS;
050: arrayDim = 1;
051: className = jvmJavaLangObject;
052: } else if (name.equals(JvstCodeGen.sigName)) {
053: exprType = CLASS;
054: arrayDim = 1;
055: className = "java/lang/Class";
056: } else if (name.equals(JvstCodeGen.dollarTypeName)
057: || name.equals(JvstCodeGen.clazzName)) {
058: exprType = CLASS;
059: arrayDim = 0;
060: className = "java/lang/Class";
061: } else
062: super .atMember(mem);
063: }
064:
065: protected void atFieldAssign(Expr expr, int op, ASTree left,
066: ASTree right) throws CompileError {
067: if (left instanceof Member
068: && ((Member) left).get().equals(codeGen.paramArrayName)) {
069: right.accept(this );
070: CtClass[] params = codeGen.paramTypeList;
071: if (params == null)
072: return;
073:
074: int n = params.length;
075: for (int i = 0; i < n; ++i)
076: compileUnwrapValue(params[i]);
077: } else
078: super .atFieldAssign(expr, op, left, right);
079: }
080:
081: public void atCastExpr(CastExpr expr) throws CompileError {
082: ASTList classname = expr.getClassName();
083: if (classname != null && expr.getArrayDim() == 0) {
084: ASTree p = classname.head();
085: if (p instanceof Symbol && classname.tail() == null) {
086: String typename = ((Symbol) p).get();
087: if (typename.equals(codeGen.returnCastName)) {
088: atCastToRtype(expr);
089: return;
090: } else if (typename.equals(JvstCodeGen.wrapperCastName)) {
091: atCastToWrapper(expr);
092: return;
093: }
094: }
095: }
096:
097: super .atCastExpr(expr);
098: }
099:
100: /**
101: * Inserts a cast operator to the return type.
102: * If the return type is void, this does nothing.
103: */
104: protected void atCastToRtype(CastExpr expr) throws CompileError {
105: CtClass returnType = codeGen.returnType;
106: expr.getOprand().accept(this );
107: if (exprType == VOID || CodeGen.isRefType(exprType)
108: || arrayDim > 0)
109: compileUnwrapValue(returnType);
110: else if (returnType instanceof CtPrimitiveType) {
111: CtPrimitiveType pt = (CtPrimitiveType) returnType;
112: int destType = MemberResolver
113: .descToType(pt.getDescriptor());
114: exprType = destType;
115: arrayDim = 0;
116: className = null;
117: }
118: }
119:
120: protected void atCastToWrapper(CastExpr expr) throws CompileError {
121: expr.getOprand().accept(this );
122: if (CodeGen.isRefType(exprType) || arrayDim > 0)
123: return; // Object type. do nothing.
124:
125: CtClass clazz = resolver.lookupClass(exprType, arrayDim,
126: className);
127: if (clazz instanceof CtPrimitiveType) {
128: exprType = CLASS;
129: arrayDim = 0;
130: className = jvmJavaLangObject;
131: }
132: }
133:
134: /* Delegates to a ProcHandler object if the method call is
135: * $proceed(). It may process $cflow().
136: */
137: public void atCallExpr(CallExpr expr) throws CompileError {
138: ASTree method = expr.oprand1();
139: if (method instanceof Member) {
140: String name = ((Member) method).get();
141: if (codeGen.procHandler != null
142: && name.equals(codeGen.proceedName)) {
143: codeGen.procHandler.setReturnType(this , (ASTList) expr
144: .oprand2());
145: return;
146: } else if (name.equals(JvstCodeGen.cflowName)) {
147: atCflow((ASTList) expr.oprand2());
148: return;
149: }
150: }
151:
152: super .atCallExpr(expr);
153: }
154:
155: /* To support $cflow().
156: */
157: protected void atCflow(ASTList cname) throws CompileError {
158: exprType = INT;
159: arrayDim = 0;
160: className = null;
161: }
162:
163: /* To support $$. ($$) is equivalent to ($1, ..., $n).
164: * It can be used only as a parameter list of method call.
165: */
166: public boolean isParamListName(ASTList args) {
167: if (codeGen.paramTypeList != null && args != null
168: && args.tail() == null) {
169: ASTree left = args.head();
170: return (left instanceof Member && ((Member) left).get()
171: .equals(codeGen.paramListName));
172: } else
173: return false;
174: }
175:
176: public int getMethodArgsLength(ASTList args) {
177: String pname = codeGen.paramListName;
178: int n = 0;
179: while (args != null) {
180: ASTree a = args.head();
181: if (a instanceof Member && ((Member) a).get().equals(pname)) {
182: if (codeGen.paramTypeList != null)
183: n += codeGen.paramTypeList.length;
184: } else
185: ++n;
186:
187: args = args.tail();
188: }
189:
190: return n;
191: }
192:
193: public void atMethodArgs(ASTList args, int[] types, int[] dims,
194: String[] cnames) throws CompileError {
195: CtClass[] params = codeGen.paramTypeList;
196: String pname = codeGen.paramListName;
197: int i = 0;
198: while (args != null) {
199: ASTree a = args.head();
200: if (a instanceof Member && ((Member) a).get().equals(pname)) {
201: if (params != null) {
202: int n = params.length;
203: for (int k = 0; k < n; ++k) {
204: CtClass p = params[k];
205: setType(p);
206: types[i] = exprType;
207: dims[i] = arrayDim;
208: cnames[i] = className;
209: ++i;
210: }
211: }
212: } else {
213: a.accept(this );
214: types[i] = exprType;
215: dims[i] = arrayDim;
216: cnames[i] = className;
217: ++i;
218: }
219:
220: args = args.tail();
221: }
222: }
223:
224: /* called by Javac#recordSpecialProceed().
225: */
226: void compileInvokeSpecial(ASTree target, String classname,
227: String methodname, String descriptor, ASTList args)
228: throws CompileError {
229: target.accept(this );
230: int nargs = getMethodArgsLength(args);
231: atMethodArgs(args, new int[nargs], new int[nargs],
232: new String[nargs]);
233: setReturnType(descriptor);
234: addNullIfVoid();
235: }
236:
237: protected void compileUnwrapValue(CtClass type) throws CompileError {
238: if (type == CtClass.voidType)
239: addNullIfVoid();
240: else
241: setType(type);
242: }
243:
244: /* Sets exprType, arrayDim, and className;
245: * If type is void, then this method does nothing.
246: */
247: public void setType(CtClass type) throws CompileError {
248: setType(type, 0);
249: }
250:
251: private void setType(CtClass type, int dim) throws CompileError {
252: if (type.isPrimitive()) {
253: CtPrimitiveType pt = (CtPrimitiveType) type;
254: exprType = MemberResolver.descToType(pt.getDescriptor());
255: arrayDim = dim;
256: className = null;
257: } else if (type.isArray())
258: try {
259: setType(type.getComponentType(), dim + 1);
260: } catch (NotFoundException e) {
261: throw new CompileError("undefined type: "
262: + type.getName());
263: }
264: else {
265: exprType = CLASS;
266: arrayDim = dim;
267: className = MemberResolver.javaToJvmName(type.getName());
268: }
269: }
270: }
|