| 1 | package org.apache.velocity.runtime.compiler; |
| 2 | |
| 3 | /* |
| 4 | * Copyright 2000-2001,2004 The Apache Software Foundation. |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | |
| 19 | import org.apache.bcel.generic.*; |
| 20 | import org.apache.bcel.Constants; |
| 21 | |
| 22 | /** |
| 23 | * The start of a velocity template compiler. Incomplete. |
| 24 | * |
| 25 | * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> |
| 26 | * @version $Id: Compiler.java,v 1.6.8.1 2004/03/03 23:22:55 geirm Exp $ |
| 27 | */ |
| 28 | public class Compiler implements InstructionConstants |
| 29 | { |
| 30 | public static void main(String[] args) |
| 31 | { |
| 32 | String template = args[0].substring(0, args[0].indexOf(".")); |
| 33 | ClassGen cg = |
| 34 | new ClassGen(template, "java.lang.Object", "<generated>", |
| 35 | Constants.ACC_PUBLIC | Constants.ACC_SUPER, null); |
| 36 | |
| 37 | ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant pool |
| 38 | InstructionList il = new InstructionList(); |
| 39 | MethodGen mg = new MethodGen(Constants.ACC_STATIC | |
| 40 | Constants.ACC_PUBLIC, // access flags |
| 41 | Type.VOID, // return type |
| 42 | new Type[]{ // argument types |
| 43 | new ArrayType(Type.STRING, 1)}, |
| 44 | new String[]{ "argv" }, // arg names |
| 45 | "main", template, // method, class |
| 46 | il, cp); |
| 47 | |
| 48 | //Add often needed constants to constant pool. |
| 49 | |
| 50 | int br_index = cp.addClass("java.io.BufferedReader"); |
| 51 | int ir_index = cp.addClass("java.io.InputStreamReader"); |
| 52 | int system_out = cp.addFieldref("java.lang.System", "out", // System.out |
| 53 | "Ljava/io/PrintStream;"); |
| 54 | int system_in = cp.addFieldref("java.lang.System", "in", // System.in |
| 55 | "Ljava/io/InputStream;"); |
| 56 | |
| 57 | // Create BufferedReader object and store it in local variable `in'. |
| 58 | |
| 59 | il.append(new NEW(br_index)); |
| 60 | il.append(DUP); |
| 61 | il.append(new NEW(ir_index)); |
| 62 | il.append(DUP); |
| 63 | il.append(new GETSTATIC(system_in)); |
| 64 | |
| 65 | // Call constructors, i.e. BufferedReader(InputStreamReader()) |
| 66 | |
| 67 | il.append( new INVOKESPECIAL( |
| 68 | cp.addMethodref("java.io.InputStreamReader", "<init>", |
| 69 | "(Ljava/io/InputStream;)V"))); |
| 70 | il.append( new INVOKESPECIAL( |
| 71 | cp.addMethodref("java.io.BufferedReader", "<init>", "(Ljava/io/Reader;)V"))); |
| 72 | |
| 73 | // Create local variable `in' |
| 74 | |
| 75 | LocalVariableGen lg = mg.addLocalVariable("in", |
| 76 | new ObjectType("java.io.BufferedReader"), null, null); |
| 77 | int in = lg.getIndex(); |
| 78 | lg.setStart(il.append(new ASTORE(in))); // `i' valid from here |
| 79 | |
| 80 | // Create local variable `name' |
| 81 | |
| 82 | lg = mg.addLocalVariable("name", Type.STRING, null, null); |
| 83 | int name = lg.getIndex(); |
| 84 | il.append(ACONST_NULL); |
| 85 | lg.setStart(il.append(new ASTORE(name))); // `name' valid from here |
| 86 | |
| 87 | InstructionHandle try_start = il.append(new GETSTATIC(system_out)); |
| 88 | il.append(new PUSH(cp, "I will be a template compiler!")); |
| 89 | il.append( new INVOKEVIRTUAL( |
| 90 | cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V"))); |
| 91 | |
| 92 | // Upon normal execution we jump behind exception handler, |
| 93 | // the target address is not known yet. |
| 94 | |
| 95 | GOTO g = new GOTO(null); |
| 96 | InstructionHandle try_end = il.append(g); |
| 97 | |
| 98 | InstructionHandle handler = il.append(RETURN); |
| 99 | mg.addExceptionHandler(try_start, try_end, handler, |
| 100 | new ObjectType("java.io.IOException")); |
| 101 | |
| 102 | // Normal code continues, now we can set the branch target of the GOTO. |
| 103 | |
| 104 | InstructionHandle ih = il.append(new GETSTATIC(system_out)); |
| 105 | g.setTarget(ih); |
| 106 | |
| 107 | // String concatenation compiles to StringBuffer operations. |
| 108 | |
| 109 | il.append(new NEW(cp.addClass("java.lang.StringBuffer"))); |
| 110 | il.append(DUP); |
| 111 | il.append(new PUSH(cp, " ")); |
| 112 | il.append( new INVOKESPECIAL( |
| 113 | cp.addMethodref("java.lang.StringBuffer", "<init>", "(Ljava/lang/String;)V"))); |
| 114 | |
| 115 | il.append(new ALOAD(name)); |
| 116 | |
| 117 | // One can also abstract from using the ugly signature syntax by using |
| 118 | // the getMethodSignature() method. For example: |
| 119 | |
| 120 | String sig = Type.getMethodSignature(Type.STRINGBUFFER, |
| 121 | new Type[]{ Type.STRING }); |
| 122 | il.append( new INVOKEVIRTUAL( |
| 123 | cp.addMethodref("java.lang.StringBuffer", "append", sig))); |
| 124 | |
| 125 | il.append( new INVOKEVIRTUAL( |
| 126 | cp.addMethodref("java.lang.StringBuffer", "toString", "()Ljava/lang/String;"))); |
| 127 | |
| 128 | il.append(RETURN); |
| 129 | |
| 130 | mg.setMaxStack(5); // Needed stack size |
| 131 | cg.addMethod(mg.getMethod()); |
| 132 | |
| 133 | // Add public <init> method, i.e. empty constructor |
| 134 | cg.addEmptyConstructor(Constants.ACC_PUBLIC); |
| 135 | |
| 136 | // Get JavaClass object and dump it to file. |
| 137 | try |
| 138 | { |
| 139 | cg.getJavaClass().dump(template + ".class"); |
| 140 | } |
| 141 | catch (java.io.IOException e) |
| 142 | { |
| 143 | System.err.println(e); |
| 144 | } |
| 145 | } |
| 146 | } |