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 | } |