You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Javac.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 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.CtMember;
  18. import javassist.CtField;
  19. import javassist.CtBehavior;
  20. import javassist.CtMethod;
  21. import javassist.CtConstructor;
  22. import javassist.CannotCompileException;
  23. import javassist.ClassPool;
  24. import javassist.Modifier;
  25. import javassist.bytecode.Bytecode;
  26. import javassist.NotFoundException;
  27. import javassist.compiler.ast.*;
  28. public class Javac {
  29. JvstCodeGen gen;
  30. SymbolTable stable;
  31. private Bytecode bytecode;
  32. public static final String param0Name = "$0";
  33. public static final String resultVarName = "$_";
  34. public static final String proceedName = "$proceed";
  35. /**
  36. * Constructs a compiler.
  37. *
  38. * @param thisClass the class that a compiled method/field
  39. * belongs to.
  40. */
  41. public Javac(CtClass thisClass) {
  42. this(new Bytecode(thisClass.getClassFile2().getConstPool(), 0, 0),
  43. thisClass);
  44. }
  45. /**
  46. * Constructs a compiler.
  47. * The produced bytecode is stored in the <code>Bytecode</code> object
  48. * specified by <code>b</code>.
  49. *
  50. * @param thisClass the class that a compiled method/field
  51. * belongs to.
  52. */
  53. public Javac(Bytecode b, CtClass thisClass) {
  54. gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool());
  55. stable = new SymbolTable();
  56. bytecode = b;
  57. }
  58. /**
  59. * Returns the produced bytecode.
  60. */
  61. public Bytecode getBytecode() { return bytecode; }
  62. /**
  63. * Compiles a method, constructor, or field declaration
  64. * to a class.
  65. * A field declaration can declare only one field.
  66. *
  67. * <p>In a method or constructor body, $0, $1, ... and $_
  68. * are not available.
  69. *
  70. * @return a <code>CtMethod</code>, <code>CtConstructor</code>,
  71. * or <code>CtField</code> object.
  72. * @see #recordProceed(String,String)
  73. */
  74. public CtMember compile(String src) throws CompileError {
  75. Parser p = new Parser(new Lex(src));
  76. ASTList mem = p.parseMember1(stable);
  77. try {
  78. if (mem instanceof FieldDecl)
  79. return compileField((FieldDecl)mem);
  80. else
  81. return compileMethod(p, (MethodDecl)mem);
  82. }
  83. catch (CannotCompileException e) {
  84. throw new CompileError(e.getMessage());
  85. }
  86. }
  87. public static class CtFieldWithInit extends CtField {
  88. private ASTree init;
  89. CtFieldWithInit(CtClass type, String name, CtClass declaring)
  90. throws CannotCompileException
  91. {
  92. super(type, name, declaring);
  93. init = null;
  94. }
  95. protected void setInit(ASTree i) { init = i; }
  96. protected ASTree getInitAST() {
  97. return init;
  98. }
  99. }
  100. private CtField compileField(FieldDecl fd)
  101. throws CompileError, CannotCompileException
  102. {
  103. CtFieldWithInit f;
  104. Declarator d = fd.getDeclarator();
  105. f = new CtFieldWithInit(gen.lookupClass(d), d.getVariable().get(),
  106. gen.getThisClass());
  107. f.setModifiers(gen.getModifiers(fd.getModifiers()));
  108. if (fd.getInit() != null)
  109. f.setInit(fd.getInit());
  110. return f;
  111. }
  112. private CtMember compileMethod(Parser p, MethodDecl md)
  113. throws CompileError
  114. {
  115. int mod = gen.getModifiers(md.getModifiers());
  116. CtClass[] plist = gen.makeParamList(md);
  117. CtClass[] tlist = gen.makeThrowsList(md);
  118. recordParams(plist, Modifier.isStatic(mod));
  119. md = p.parseMethod2(stable, md);
  120. try {
  121. if (md.isConstructor()) {
  122. CtConstructor cons = new CtConstructor(plist,
  123. gen.getThisClass());
  124. cons.setModifiers(mod);
  125. md.accept(gen);
  126. cons.getMethodInfo().setCodeAttribute(
  127. bytecode.toCodeAttribute());
  128. cons.setExceptionTypes(tlist);
  129. return cons;
  130. }
  131. else {
  132. Declarator r = md.getReturn();
  133. CtClass rtype = gen.lookupClass(r);
  134. recordReturnType(rtype, false);
  135. CtMethod method = new CtMethod(rtype, r.getVariable().get(),
  136. plist, gen.getThisClass());
  137. method.setModifiers(mod);
  138. gen.setThisMethod(method);
  139. md.accept(gen);
  140. if (md.getBody() != null)
  141. method.getMethodInfo().setCodeAttribute(
  142. bytecode.toCodeAttribute());
  143. else
  144. method.setModifiers(mod | Modifier.ABSTRACT);
  145. method.setExceptionTypes(tlist);
  146. return method;
  147. }
  148. }
  149. catch (NotFoundException e) {
  150. throw new CompileError(e.toString());
  151. }
  152. }
  153. /**
  154. * Compiles a method (or constructor) body.
  155. */
  156. public Bytecode compileBody(CtBehavior method, String src)
  157. throws CompileError
  158. {
  159. try {
  160. int mod = method.getModifiers();
  161. recordParams(method.getParameterTypes(), Modifier.isStatic(mod));
  162. CtClass rtype;
  163. if (method instanceof CtMethod) {
  164. gen.setThisMethod((CtMethod)method);
  165. rtype = ((CtMethod)method).getReturnType();
  166. }
  167. else
  168. rtype = CtClass.voidType;
  169. recordReturnType(rtype, false);
  170. boolean isVoid = rtype == CtClass.voidType;
  171. Parser p = new Parser(new Lex(src));
  172. SymbolTable stb = new SymbolTable(stable);
  173. Stmnt s = p.parseStatement(stb);
  174. gen.atMethodBody(s, method instanceof CtConstructor, isVoid);
  175. return bytecode;
  176. }
  177. catch (NotFoundException e) {
  178. throw new CompileError(e.toString());
  179. }
  180. }
  181. /**
  182. * Makes variables $0 (this), $1, $2, ..., and $args represent method
  183. * parameters. $args represents an array of all the parameters.
  184. * It also makes $$ available as a parameter list of method call.
  185. *
  186. * <p>This must be called before calling <code>compileStmnt()</code> and
  187. * <code>compileExpr()</code>. The correct value of
  188. * <code>isStatic</code> must be recorded before compilation.
  189. */
  190. public void recordParams(CtClass[] params, boolean isStatic)
  191. throws CompileError
  192. {
  193. gen.recordParams(params, isStatic, "$", "$args", "$$", stable);
  194. }
  195. /**
  196. * Makes variables $0, $1, $2, ..., and $args represent method
  197. * parameters. $args represents an array of all the parameters.
  198. * It also makes $$ available as a parameter list of method call.
  199. * $0 can represent a local variable other than THIS (variable 0).
  200. *
  201. * <p>This must be called before calling <code>compileStmnt()</code> and
  202. * <code>compileExpr()</code>. The correct value of
  203. * <code>isStatic</code> must be recorded before compilation.
  204. *
  205. * @paaram use0 true if $0 is used.
  206. * @param varNo the register number of $0 (use0 is true)
  207. * or $1 (otherwise).
  208. * @param target the type of $0 (it can be null if use0 is false).
  209. * @param isStatic true if the method in which the compiled bytecode
  210. * is embedded is static.
  211. */
  212. public void recordParams(String target, CtClass[] params,
  213. boolean use0, int varNo, boolean isStatic)
  214. throws CompileError
  215. {
  216. gen.recordParams(params, isStatic, "$", "$args", "$$",
  217. use0, varNo, target, stable);
  218. }
  219. /**
  220. * Prepares to use cast $r, $w, $_, and $type.
  221. * It also enables to write a return statement with a return value
  222. * for void method.
  223. *
  224. * <p>If the return type is void, ($r) does nothing.
  225. * The type of $_ is java.lang.Object.
  226. *
  227. * @param useResultVar true if $_ is used.
  228. * @return -1 or the variable index assigned to $_.
  229. */
  230. public int recordReturnType(CtClass type, boolean useResultVar)
  231. throws CompileError
  232. {
  233. gen.recordType(type);
  234. return gen.recordReturnType(type, "$r",
  235. (useResultVar ? resultVarName : null), stable);
  236. }
  237. /**
  238. * Prepares to use $type. Note that recordReturnType() overwrites
  239. * the value of $type.
  240. */
  241. public void recordType(CtClass t) {
  242. gen.recordType(t);
  243. }
  244. /**
  245. * Makes the given variable available.
  246. *
  247. * @param type variable type
  248. * @param name variable name
  249. */
  250. public int recordVariable(CtClass type, String name)
  251. throws CompileError
  252. {
  253. return gen.recordVariable(type, name, stable);
  254. }
  255. /**
  256. * Prepares to use $proceed().
  257. * If the return type of $proceed() is void, null is pushed on the
  258. * stack.
  259. *
  260. * @param target an expression specifying the target object.
  261. * if null, "this" is the target.
  262. * @param method the method name.
  263. */
  264. public void recordProceed(String target, String method)
  265. throws CompileError
  266. {
  267. Parser p = new Parser(new Lex(target));
  268. final ASTree texpr = p.parseExpression(stable);
  269. final String m = method;
  270. ProceedHandler h = new ProceedHandler() {
  271. public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
  272. throws CompileError
  273. {
  274. ASTree expr = new Member(m);
  275. if (texpr != null)
  276. expr = Expr.make('.', texpr, expr);
  277. expr = Expr.make(TokenId.CALL, expr, args);
  278. expr.accept(gen);
  279. gen.addNullIfVoid();
  280. }
  281. };
  282. gen.setProceedHandler(h, proceedName);
  283. }
  284. /**
  285. * Prepares to use $proceed().
  286. */
  287. public void recordProceed(ProceedHandler h) {
  288. gen.setProceedHandler(h, proceedName);
  289. }
  290. /**
  291. * Compiles a statement (or a block).
  292. * <code>recordParams()</code> must be called before invoking
  293. * this method.
  294. *
  295. * <p>Local variables that are not declared
  296. * in the compiled source text are not accessible within that
  297. * source text. Fields and method parameters
  298. * ($0, $1, ..) are available.
  299. */
  300. public void compileStmnt(String src) throws CompileError {
  301. Parser p = new Parser(new Lex(src));
  302. SymbolTable stb = new SymbolTable(stable);
  303. // while (p.hasMore()) {
  304. Stmnt s = p.parseStatement(stb);
  305. if (s != null)
  306. s.accept(gen);
  307. // }
  308. }
  309. /**
  310. * Compiles an exression. <code>recordParams()</code> must be
  311. * called before invoking this method.
  312. *
  313. * <p>Local variables are not accessible
  314. * within the compiled source text. Fields and method parameters
  315. * ($0, $1, ..) are available if <code>recordParams()</code>
  316. * have been invoked.
  317. */
  318. public void compileExpr(String src) throws CompileError {
  319. Parser p = new Parser(new Lex(src));
  320. ASTree e = p.parseExpression(stable);
  321. compileExpr(e);
  322. }
  323. /**
  324. * Compiles an exression. <code>recordParams()</code> must be
  325. * called before invoking this method.
  326. *
  327. * <p>Local variables are not accessible
  328. * within the compiled source text. Fields and method parameters
  329. * ($0, $1, ..) are available if <code>recordParams()</code>
  330. * have been invoked.
  331. */
  332. public void compileExpr(ASTree e) throws CompileError {
  333. if (e != null)
  334. e.accept(gen);
  335. }
  336. }