選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

TypeChecker.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.compiler;
  16. import javassist.CtClass;
  17. import javassist.CtField;
  18. import javassist.Modifier;
  19. import javassist.ClassPool;
  20. import javassist.NotFoundException;
  21. import javassist.compiler.ast.*;
  22. import javassist.bytecode.*;
  23. /**
  24. * This class does type checking and, if needed, transformes the original
  25. * abstract syntax tree. The resulting tree is available from
  26. * this.modifiedExpr.
  27. */
  28. public class TypeChecker extends Visitor implements Opcode, TokenId {
  29. static final String javaLangObject = "java.lang.Object";
  30. static final String jvmJavaLangObject = "java/lang/Object";
  31. static final String jvmJavaLangString = "java/lang/String";
  32. static final String jvmJavaLangClass = "java/lang/Class";
  33. /* The following fields are used by atXXX() methods
  34. * for returning the type of the compiled expression.
  35. */
  36. protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
  37. protected int arrayDim;
  38. protected String className; // JVM-internal representation
  39. protected ASTree modifiedExpr; // null if the given expr was not changed
  40. protected MemberResolver resolver;
  41. protected CtClass thisClass;
  42. protected MethodInfo thisMethod;
  43. public TypeChecker(CtClass cc, ClassPool cp) {
  44. resolver = new MemberResolver(cp);
  45. thisClass = cc;
  46. thisMethod = null;
  47. }
  48. /**
  49. * Records the currently compiled method.
  50. */
  51. public void setThisMethod(MethodInfo m) {
  52. thisMethod = m;
  53. }
  54. protected static void fatal() throws CompileError {
  55. throw new CompileError("fatal");
  56. }
  57. /**
  58. * Returns the JVM-internal representation of this class name.
  59. */
  60. protected String getThisName() {
  61. return MemberResolver.javaToJvmName(thisClass.getName());
  62. }
  63. /**
  64. * Returns the JVM-internal representation of this super class name.
  65. */
  66. protected String getSuperName() throws CompileError {
  67. return MemberResolver.javaToJvmName(
  68. MemberResolver.getSuperclass(thisClass).getName());
  69. }
  70. /* Converts a class name into a JVM-internal representation.
  71. *
  72. * It may also expand a simple class name to java.lang.*.
  73. * For example, this converts Object into java/lang/Object.
  74. */
  75. protected String resolveClassName(ASTList name) throws CompileError {
  76. return resolver.resolveClassName(name);
  77. }
  78. /* Expands a simple class name to java.lang.*.
  79. * For example, this converts Object into java/lang/Object.
  80. */
  81. protected String resolveClassName(String jvmName) throws CompileError {
  82. return resolver.resolveJvmClassName(jvmName);
  83. }
  84. public void atNewExpr(NewExpr expr) throws CompileError {
  85. if (expr.isArray())
  86. atNewArrayExpr(expr);
  87. else {
  88. CtClass clazz = resolver.lookupClassByName(expr.getClassName());
  89. String cname = clazz.getName();
  90. ASTList args = expr.getArguments();
  91. atMethodCallCore(clazz, MethodInfo.nameInit, args);
  92. exprType = CLASS;
  93. arrayDim = 0;
  94. className = MemberResolver.javaToJvmName(cname);
  95. modifiedExpr = null;
  96. }
  97. }
  98. public void atNewArrayExpr(NewExpr expr) throws CompileError {
  99. int type = expr.getArrayType();
  100. ASTList size = expr.getArraySize();
  101. ASTList classname = expr.getClassName();
  102. if (size.length() > 1)
  103. atMultiNewArray(type, classname, size);
  104. else {
  105. size.head().accept(this);
  106. if (modifiedExpr != null)
  107. size.setHead(modifiedExpr);
  108. exprType = type;
  109. arrayDim = 1;
  110. modifiedExpr = null;
  111. if (type == CLASS)
  112. className = resolveClassName(classname);
  113. else
  114. className = null;
  115. }
  116. }
  117. protected void atMultiNewArray(int type, ASTList classname, ASTList size)
  118. throws CompileError
  119. {
  120. int count, dim;
  121. dim = size.length();
  122. for (count = 0; size != null; size = size.tail()) {
  123. ASTree s = size.head();
  124. if (s == null)
  125. break; // int[][][] a = new int[3][4][];
  126. ++count;
  127. s.accept(this);
  128. if (modifiedExpr != null)
  129. size.setHead(modifiedExpr);
  130. }
  131. modifiedExpr = null;
  132. exprType = type;
  133. arrayDim = dim;
  134. if (type == CLASS)
  135. className = resolveClassName(classname);
  136. else
  137. className = null;
  138. }
  139. public void atAssignExpr(AssignExpr expr) throws CompileError {
  140. // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
  141. int op = expr.getOperator();
  142. ASTree left = expr.oprand1();
  143. ASTree right = expr.oprand2();
  144. if (left instanceof Variable)
  145. atVariableAssign(expr, op, (Variable)left,
  146. ((Variable)left).getDeclarator(),
  147. right);
  148. else {
  149. if (left instanceof Expr) {
  150. Expr e = (Expr)left;
  151. if (e.getOperator() == ARRAY) {
  152. atArrayAssign(expr, op, (Expr)left, right);
  153. return;
  154. }
  155. }
  156. atFieldAssign(expr, op, left, right);
  157. }
  158. }
  159. /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
  160. *
  161. * expr and var can be null.
  162. */
  163. private void atVariableAssign(Expr expr, int op, Variable var,
  164. Declarator d, ASTree right)
  165. throws CompileError
  166. {
  167. int varType = d.getType();
  168. int varArray = d.getArrayDim();
  169. String varClass = d.getClassName();
  170. if (op != '=') {
  171. atVariable(var);
  172. if (modifiedExpr != null)
  173. expr.setOprand1(modifiedExpr);
  174. }
  175. right.accept(this);
  176. if (modifiedExpr != null)
  177. expr.setOprand2(modifiedExpr);
  178. exprType = varType;
  179. arrayDim = varArray;
  180. className = varClass;
  181. modifiedExpr = null;
  182. }
  183. private void atArrayAssign(Expr expr, int op, Expr array,
  184. ASTree right) throws CompileError
  185. {
  186. atArrayRead(array);
  187. if (modifiedExpr != null)
  188. expr.setOprand1(modifiedExpr);
  189. int aType = exprType;
  190. int aDim = arrayDim;
  191. String cname = className;
  192. right.accept(this);
  193. if (modifiedExpr != null)
  194. expr.setOprand2(modifiedExpr);
  195. exprType = aType;
  196. arrayDim = aDim;
  197. className = cname;
  198. modifiedExpr = null;
  199. }
  200. protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
  201. throws CompileError
  202. {
  203. CtField f = atFieldRead(left);
  204. int fType = exprType;
  205. int fDim = arrayDim;
  206. String cname = className;
  207. if (modifiedExpr != null)
  208. expr.setOprand1(modifiedExpr);
  209. if (Modifier.isFinal(f.getModifiers()))
  210. throw new CompileError("assignment to a final field");
  211. right.accept(this);
  212. if (modifiedExpr != null)
  213. expr.setOprand2(modifiedExpr);
  214. exprType = fType;
  215. arrayDim = fDim;
  216. className = cname;
  217. modifiedExpr = null;
  218. }
  219. public void atCondExpr(CondExpr expr) throws CompileError {
  220. booleanExpr(expr.condExpr());
  221. if (modifiedExpr != null)
  222. expr.setCond(modifiedExpr);
  223. expr.thenExpr().accept(this);
  224. if (modifiedExpr != null)
  225. expr.setThen(modifiedExpr);
  226. int type1 = exprType;
  227. int dim1 = arrayDim;
  228. String cname1 = className;
  229. expr.elseExpr().accept(this);
  230. if (modifiedExpr != null)
  231. expr.setElse(modifiedExpr);
  232. if (dim1 == 0 && dim1 == arrayDim)
  233. if (CodeGen.rightIsStrong(type1, exprType))
  234. expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
  235. else if (CodeGen.rightIsStrong(exprType, type1)) {
  236. expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
  237. exprType = type1;
  238. }
  239. modifiedExpr = null;
  240. }
  241. public void atBinExpr(BinExpr expr) throws CompileError {
  242. int token = expr.getOperator();
  243. int k = CodeGen.lookupBinOp(token);
  244. if (k < 0) {
  245. /* equation: &&, ||, ==, !=, <=, >=, <, >
  246. */
  247. booleanExpr(expr);
  248. }
  249. else {
  250. /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
  251. */
  252. if (token != '+')
  253. atNonPlusExpr(expr, token);
  254. else {
  255. Expr e = atPlusExpr(expr);
  256. if (e != null) {
  257. /* String concatenation has been translated into
  258. * an expression using StringBuffer.
  259. */
  260. e = CallExpr.makeCall(Expr.make('.', e,
  261. new Member("toString")), null);
  262. className = jvmJavaLangString;
  263. modifiedExpr = e; // expr will be replaced with e.
  264. }
  265. }
  266. }
  267. }
  268. private void atNonPlusExpr(BinExpr expr, int token) throws CompileError {
  269. ASTree left = expr.oprand1();
  270. ASTree right = expr.oprand2();
  271. left.accept(this);
  272. if (modifiedExpr != null) {
  273. left = modifiedExpr;
  274. expr.setOprand1(left);
  275. }
  276. int type1 = exprType;
  277. right.accept(this);
  278. if (modifiedExpr != null) {
  279. right = modifiedExpr;
  280. expr.setOprand2(right);
  281. }
  282. modifiedExpr = computeConstExpr(token, left, right);
  283. computeBinExprType(expr, token, type1);
  284. }
  285. /* This method deals with string concatenation. It converts a +
  286. * expression on String such as:
  287. * "value:" + i + "."
  288. * into:
  289. * new StringBuffer().append("value:").append(i).append(".")
  290. * .toString()
  291. *
  292. * This method also inserts a cast operator for the right operand
  293. * if needed.
  294. *
  295. * EXPR must be a + expression.
  296. *
  297. * atPlusExpr() returns null if the expression is not a string
  298. * concatenation.
  299. */
  300. private Expr atPlusExpr(BinExpr expr) throws CompileError {
  301. ASTree left = expr.oprand1();
  302. ASTree right = expr.oprand2();
  303. if (isPlusExpr(left)) {
  304. Expr newExpr = atPlusExpr((BinExpr)left);
  305. if (newExpr != null) {
  306. right.accept(this);
  307. if (modifiedExpr != null)
  308. right = modifiedExpr;
  309. exprType = CLASS;
  310. arrayDim = 0;
  311. className = "java/lang/StringBuffer";
  312. modifiedExpr = null;
  313. return makeAppendCall(newExpr, right);
  314. }
  315. }
  316. else
  317. left.accept(this);
  318. int type1 = exprType;
  319. int dim1 = arrayDim;
  320. String cname = className;
  321. if (modifiedExpr != null) {
  322. left = modifiedExpr;
  323. expr.setOprand1(left);
  324. }
  325. right.accept(this);
  326. if (modifiedExpr != null) {
  327. right = modifiedExpr;
  328. expr.setOprand2(right);
  329. }
  330. modifiedExpr = computeConstExpr('+', left, right);
  331. if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
  332. || (exprType == CLASS && arrayDim == 0
  333. && jvmJavaLangString.equals(className)))
  334. {
  335. exprType = CLASS;
  336. arrayDim = 0;
  337. if (modifiedExpr != null) {
  338. // this expression is constant.
  339. className = jvmJavaLangString;
  340. return null;
  341. }
  342. else {
  343. className = "java/lang/StringBuffer";
  344. ASTList sbufClass = ASTList.make(new Symbol("java"),
  345. new Symbol("lang"),
  346. new Symbol("StringBuffer"));
  347. ASTree e = new NewExpr(sbufClass, null);
  348. return makeAppendCall(makeAppendCall(e, left), right);
  349. }
  350. }
  351. else {
  352. computeBinExprType(expr, '+', type1);
  353. return null;
  354. }
  355. }
  356. private static boolean isPlusExpr(ASTree expr) {
  357. if (expr instanceof BinExpr) {
  358. BinExpr bexpr = (BinExpr)expr;
  359. int token = bexpr.getOperator();
  360. return token == '+';
  361. }
  362. return false;
  363. }
  364. private static Expr makeAppendCall(ASTree target, ASTree arg) {
  365. return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
  366. new ASTList(arg));
  367. }
  368. private void computeBinExprType(BinExpr expr, int token, int type1)
  369. throws CompileError
  370. {
  371. // arrayDim should be 0.
  372. int type2 = exprType;
  373. if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
  374. exprType = type1;
  375. else
  376. insertCast(expr, type1, type2);
  377. if (CodeGen.isP_INT(exprType))
  378. exprType = INT; // type1 may be BYTE, ...
  379. arrayDim = 0;
  380. // don't change the value of modifiedExpr.
  381. }
  382. private void booleanExpr(ASTree expr)
  383. throws CompileError
  384. {
  385. ASTree modExpr = null;
  386. int op = CodeGen.getCompOperator(expr);
  387. if (op == EQ) { // ==, !=, ...
  388. BinExpr bexpr = (BinExpr)expr;
  389. bexpr.oprand1().accept(this);
  390. if (modifiedExpr != null)
  391. bexpr.setOprand1(modifiedExpr);
  392. int type1 = exprType;
  393. int dim1 = arrayDim;
  394. bexpr.oprand2().accept(this);
  395. if (modifiedExpr != null)
  396. bexpr.setOprand2(modifiedExpr);
  397. if (dim1 == 0 && arrayDim == 0)
  398. insertCast(bexpr, type1, exprType);
  399. }
  400. else if (op == '!') {
  401. ((Expr)expr).oprand1().accept(this);
  402. if (modifiedExpr != null)
  403. ((Expr)expr).setOprand1(modifiedExpr);
  404. }
  405. else if (op == ANDAND || op == OROR) {
  406. BinExpr bexpr = (BinExpr)expr;
  407. bexpr.oprand1().accept(this);
  408. if (modifiedExpr != null)
  409. bexpr.setOprand1(modifiedExpr);
  410. bexpr.oprand2().accept(this);
  411. if (modifiedExpr != null)
  412. bexpr.setOprand2(modifiedExpr);
  413. }
  414. else { // others
  415. expr.accept(this);
  416. modExpr = modifiedExpr;
  417. }
  418. exprType = BOOLEAN;
  419. arrayDim = 0;
  420. modifiedExpr = modExpr;
  421. }
  422. private void insertCast(BinExpr expr, int type1, int type2)
  423. throws CompileError
  424. {
  425. if (CodeGen.rightIsStrong(type1, type2))
  426. expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
  427. else
  428. exprType = type1;
  429. }
  430. private ASTree computeConstExpr(int op, ASTree left, ASTree right) {
  431. if (left instanceof StringL && right instanceof StringL && op == '+')
  432. return new StringL(((StringL)left).get() + ((StringL)right).get());
  433. else if (left instanceof IntConst)
  434. return ((IntConst)left).compute(op, right);
  435. else if (left instanceof DoubleConst)
  436. return ((DoubleConst)left).compute(op, right);
  437. else
  438. return null; // not constant expression
  439. }
  440. public void atCastExpr(CastExpr expr) throws CompileError {
  441. String cname = resolveClassName(expr.getClassName());
  442. expr.getOprand().accept(this);
  443. if (modifiedExpr != null)
  444. expr.setOprand(modifiedExpr);
  445. exprType = expr.getType();
  446. arrayDim = expr.getArrayDim();
  447. className = cname;
  448. modifiedExpr = null;
  449. }
  450. public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
  451. expr.getOprand().accept(this);
  452. if (modifiedExpr != null)
  453. expr.setOprand(modifiedExpr);
  454. exprType = BOOLEAN;
  455. arrayDim = 0;
  456. modifiedExpr = null;
  457. }
  458. public void atExpr(Expr expr) throws CompileError {
  459. // array access, member access,
  460. // (unary) +, (unary) -, ++, --, !, ~
  461. int token = expr.getOperator();
  462. ASTree oprand = expr.oprand1();
  463. if (token == '.') {
  464. String member = ((Symbol)expr.oprand2()).get();
  465. if (member.equals("length"))
  466. atArrayLength(expr);
  467. else if (member.equals("class"))
  468. atClassObject(expr); // .class
  469. else
  470. atFieldRead(expr);
  471. }
  472. else if (token == MEMBER) { // field read
  473. String member = ((Symbol)expr.oprand2()).get();
  474. if (member.equals("class"))
  475. atClassObject(expr); // .class
  476. else
  477. atFieldRead(expr);
  478. }
  479. else if (token == ARRAY)
  480. atArrayRead(expr);
  481. else if (token == PLUSPLUS || token == MINUSMINUS)
  482. atPlusPlus(token, oprand, expr);
  483. else if (token == '!')
  484. booleanExpr(expr);
  485. else if (token == CALL) // method call
  486. fatal();
  487. else {
  488. oprand.accept(this);
  489. if (modifiedExpr != null) {
  490. oprand = modifiedExpr;
  491. expr.setOprand1(oprand);
  492. }
  493. modifiedExpr = computeConstExpr(token, oprand);
  494. if (token == '-' || token == '~') {
  495. if (CodeGen.isP_INT(exprType))
  496. exprType = INT; // type may be BYTE, ...
  497. }
  498. }
  499. }
  500. private ASTree computeConstExpr(int op, ASTree oprand) {
  501. if (oprand instanceof IntConst) {
  502. IntConst c = (IntConst)oprand;
  503. long v = c.get();
  504. if (op == '-')
  505. v = -v;
  506. else if (op == '~')
  507. v = ~v;
  508. c.set(v);
  509. }
  510. else if (oprand instanceof DoubleConst) {
  511. DoubleConst c = (DoubleConst)oprand;
  512. if (op == '-')
  513. c.set(-c.get());
  514. }
  515. return null;
  516. }
  517. public void atCallExpr(CallExpr expr) throws CompileError {
  518. String mname = null;
  519. CtClass targetClass = null;
  520. ASTree method = expr.oprand1();
  521. ASTList args = (ASTList)expr.oprand2();
  522. if (method instanceof Member) {
  523. mname = ((Member)method).get();
  524. targetClass = thisClass;
  525. }
  526. else if (method instanceof Keyword) { // constructor
  527. mname = MethodInfo.nameInit; // <init>
  528. if (((Keyword)method).get() == SUPER)
  529. targetClass = MemberResolver.getSuperclass(thisClass);
  530. else
  531. targetClass = thisClass;
  532. }
  533. else if (method instanceof Expr) {
  534. Expr e = (Expr)method;
  535. mname = ((Symbol)e.oprand2()).get();
  536. int op = e.getOperator();
  537. if (op == MEMBER) // static method
  538. targetClass
  539. = resolver.lookupClass(((Symbol)e.oprand1()).get(),
  540. false);
  541. else if (op == '.') {
  542. ASTree target = e.oprand1();
  543. try {
  544. target.accept(this);
  545. if (modifiedExpr != null)
  546. e.setOprand1(modifiedExpr);
  547. }
  548. catch (NoFieldException nfe) {
  549. if (nfe.getExpr() != target)
  550. throw nfe;
  551. // it should be a static method.
  552. exprType = CLASS;
  553. arrayDim = 0;
  554. className = nfe.getField(); // JVM-internal
  555. }
  556. if (arrayDim > 0)
  557. targetClass = resolver.lookupClass(javaLangObject, true);
  558. else if (exprType == CLASS /* && arrayDim == 0 */)
  559. targetClass = resolver.lookupClassByJvmName(className);
  560. else
  561. badMethod();
  562. }
  563. else
  564. badMethod();
  565. }
  566. else
  567. fatal();
  568. MemberResolver.Method minfo
  569. = atMethodCallCore(targetClass, mname, args);
  570. expr.setMethod(minfo);
  571. modifiedExpr = null;
  572. }
  573. private static void badMethod() throws CompileError {
  574. throw new CompileError("bad method");
  575. }
  576. /**
  577. * modifiedExpr is not set.
  578. *
  579. * @return a pair of the class declaring the invoked method
  580. * and the MethodInfo of that method. Never null.
  581. */
  582. public MemberResolver.Method atMethodCallCore(CtClass targetClass,
  583. String mname, ASTList args)
  584. throws CompileError
  585. {
  586. int nargs = getMethodArgsLength(args);
  587. int[] types = new int[nargs];
  588. int[] dims = new int[nargs];
  589. String[] cnames = new String[nargs];
  590. atMethodArgs(args, types, dims, cnames);
  591. MemberResolver.Method found
  592. = resolver.lookupMethod(targetClass, thisMethod, mname,
  593. types, dims, cnames, false);
  594. if (found == null) {
  595. String msg;
  596. if (mname.equals(MethodInfo.nameInit))
  597. msg = "constructor not found";
  598. else
  599. msg = "Method " + mname + " not found in "
  600. + targetClass.getName();
  601. throw new CompileError(msg);
  602. }
  603. String desc = found.info.getDescriptor();
  604. setReturnType(desc);
  605. return found;
  606. }
  607. public int getMethodArgsLength(ASTList args) {
  608. return ASTList.length(args);
  609. }
  610. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  611. String[] cnames) throws CompileError {
  612. int i = 0;
  613. while (args != null) {
  614. ASTree a = args.head();
  615. a.accept(this);
  616. if (modifiedExpr != null)
  617. args.setHead(modifiedExpr);
  618. types[i] = exprType;
  619. dims[i] = arrayDim;
  620. cnames[i] = className;
  621. ++i;
  622. args = args.tail();
  623. }
  624. }
  625. /* modifiedExpr is not set.
  626. */
  627. void setReturnType(String desc) throws CompileError {
  628. int i = desc.indexOf(')');
  629. if (i < 0)
  630. badMethod();
  631. char c = desc.charAt(++i);
  632. int dim = 0;
  633. while (c == '[') {
  634. ++dim;
  635. c = desc.charAt(++i);
  636. }
  637. arrayDim = dim;
  638. if (c == 'L') {
  639. int j = desc.indexOf(';', i + 1);
  640. if (j < 0)
  641. badMethod();
  642. exprType = CLASS;
  643. className = desc.substring(i + 1, j);
  644. }
  645. else {
  646. exprType = MemberResolver.descToType(c);
  647. className = null;
  648. }
  649. }
  650. private CtField atFieldRead(ASTree expr) throws CompileError {
  651. CtField f = fieldAccess(expr);
  652. FieldInfo finfo = f.getFieldInfo2();
  653. String type = finfo.getDescriptor();
  654. int i = 0;
  655. int dim = 0;
  656. char c = type.charAt(i);
  657. while (c == '[') {
  658. ++dim;
  659. c = type.charAt(++i);
  660. }
  661. arrayDim = dim;
  662. exprType = MemberResolver.descToType(c);
  663. if (c == 'L')
  664. className = type.substring(i + 1, type.indexOf(';', i + 1));
  665. else
  666. className = null;
  667. modifiedExpr = null; ??
  668. return f;
  669. }
  670. protected CtField fieldAccess(ASTree expr) throws CompileError {
  671. if (expr instanceof Member) {
  672. String name = ((Member)expr).get();
  673. try {
  674. return thisClass.getField(name);
  675. }
  676. catch (NotFoundException e) {
  677. // EXPR might be part of a static member access?
  678. throw new NoFieldException(name, expr);
  679. }
  680. }
  681. else if (expr instanceof Expr) {
  682. Expr e = (Expr)expr;
  683. int op = e.getOperator();
  684. if (op == MEMBER)
  685. return resolver.lookupField(((Symbol)e.oprand1()).get(),
  686. (Symbol)e.oprand2());
  687. else if (op == '.')
  688. try {
  689. e.oprand1().accept(this);
  690. if (modifiedExpr != null)
  691. e.setOprand1(modifiedExpr);
  692. if (exprType == CLASS && arrayDim == 0)
  693. return resolver.lookupFieldByJvmName(className,
  694. (Symbol)e.oprand2());
  695. }
  696. catch (NoFieldException nfe) {
  697. if (nfe.getExpr() != e.oprand1())
  698. throw nfe;
  699. /* EXPR should be a static field.
  700. * If EXPR might be part of a qualified class name,
  701. * lookupFieldByJvmName2() throws NoFieldException.
  702. */
  703. Symbol fname = (Symbol)e.oprand2();
  704. return resolver.lookupFieldByJvmName2(nfe.getField(),
  705. fname, expr);
  706. }
  707. }
  708. throw new CompileError("bad filed access");
  709. }
  710. public void atClassObject(Expr expr) throws CompileError {
  711. exprType = CLASS;
  712. arrayDim = 0;
  713. className =jvmJavaLangClass;
  714. modifiedExpr = null;
  715. }
  716. public void atArrayLength(Expr expr) throws CompileError {
  717. expr.oprand1().accept(this);
  718. if (modifiedExpr != null)
  719. expr.setOprand1(modifiedExpr);
  720. exprType = INT;
  721. arrayDim = 0;
  722. modifiedExpr = null;
  723. }
  724. public void atArrayRead(Expr expr) throws CompileError {
  725. ASTree array = expr.oprand1();
  726. array.accept(this);
  727. if (modifiedExpr != null)
  728. expr.setOprand1(modifiedExpr);
  729. int type = exprType;
  730. int dim = arrayDim;
  731. String cname = className;
  732. ASTree index = expr.oprand2();
  733. index.accept(this);
  734. if (modifiedExpr != null)
  735. expr.setOprand2(modifiedExpr);
  736. exprType = type;
  737. arrayDim = dim - 1;
  738. className = cname;
  739. modifiedExpr = null;
  740. }
  741. private void atPlusPlus(int token, ASTree oprand, Expr expr)
  742. throws CompileError
  743. {
  744. boolean isPost = oprand == null; // ++i or i++?
  745. if (isPost)
  746. oprand = expr.oprand2();
  747. if (oprand instanceof Variable) {
  748. Declarator d = ((Variable)oprand).getDeclarator();
  749. exprType = d.getType();
  750. arrayDim = d.getArrayDim();
  751. modifiedExpr = null;
  752. }
  753. else {
  754. if (oprand instanceof Expr) {
  755. Expr e = (Expr)oprand;
  756. if (e.getOperator() == ARRAY) {
  757. atArrayRead(e);
  758. // arrayDim should be 0.
  759. int t = exprType;
  760. if (t == INT || t == BYTE || t == CHAR || t == SHORT)
  761. exprType = INT;
  762. return;
  763. }
  764. }
  765. atFieldPlusPlus(oprand);
  766. }
  767. }
  768. protected void atFieldPlusPlus(ASTree oprand) throws CompileError
  769. {
  770. atFieldRead(oprand);
  771. int t = exprType;
  772. if (t == INT || t == BYTE || t == CHAR || t == SHORT)
  773. exprType = INT;
  774. }
  775. public void atMember(Member mem) throws CompileError {
  776. atFieldRead(mem);
  777. }
  778. public void atVariable(Variable v) throws CompileError {
  779. Declarator d = v.getDeclarator();
  780. exprType = d.getType();
  781. arrayDim = d.getArrayDim();
  782. className = d.getClassName();
  783. }
  784. public void atKeyword(Keyword k) throws CompileError {
  785. arrayDim = 0;
  786. int token = k.get();
  787. switch (token) {
  788. case TRUE :
  789. case FALSE :
  790. exprType = BOOLEAN;
  791. break;
  792. case NULL :
  793. exprType = NULL;
  794. break;
  795. case THIS :
  796. case SUPER :
  797. exprType = CLASS;
  798. if (token == THIS)
  799. className = getThisName();
  800. else
  801. className = getSuperName();
  802. break;
  803. default :
  804. fatal();
  805. }
  806. }
  807. public void atStringL(StringL s) throws CompileError {
  808. exprType = CLASS;
  809. arrayDim = 0;
  810. className = jvmJavaLangString;
  811. }
  812. public void atIntConst(IntConst i) throws CompileError {
  813. arrayDim = 0;
  814. int type = i.getType();
  815. if (type == IntConstant || type == CharConstant)
  816. exprType = (type == IntConstant ? INT : CHAR);
  817. else
  818. exprType = LONG;
  819. }
  820. public void atDoubleConst(DoubleConst d) throws CompileError {
  821. arrayDim = 0;
  822. if (d.getType() == DoubleConstant)
  823. exprType = DOUBLE;
  824. else
  825. exprType = FLOAT;
  826. }
  827. }