001 /*
002 @license.text@
003 */
004 package biz.hammurapi.codegen;
005
006 import java.util.ArrayList;
007 import java.util.Collection;
008 import java.util.HashSet;
009 import java.util.Iterator;
010 import java.util.Properties;
011 import java.util.Set;
012
013 import org.apache.bcel.Constants;
014 import org.apache.bcel.classfile.Utility;
015 import org.apache.bcel.generic.ClassGen;
016 import org.apache.bcel.generic.InstructionList;
017 import org.apache.bcel.generic.MethodGen;
018 import org.apache.bcel.generic.Type;
019
020 import biz.hammurapi.codegen.JavaTokenTypes;
021
022 import antlr.collections.AST;
023 import biz.hammurapi.util.Parameter;
024
025
026 /**
027 * @author Pavel Vlasov
028 * @version $Revision: 1.7 $
029 */
030 public class Interface extends ClassGeneratorBase {
031
032 /**
033 * Constructor
034 * @param definition E.g. <CODE>public interface C extends a.b.A, a.b.c.d.B</CODE> Superinterfaces names shall be fully qualified.
035 * @param description
036 * @param listener
037 * @throws GenerationException
038 */
039 public Interface(String definition, String description, GenerationListener listener) throws GenerationException {
040 this.listener=listener;
041 AST ast=typeDefinition(definition);
042 if (ast==null) {
043 throw new GenerationException("Cannot parse definition: "+definition);
044 }
045
046 if (ast.getType()==JavaTokenTypes.INTERFACE_DEF) {
047 Set modifiers=new HashSet();
048 String name=null;
049 Collection superInterfaces=new ArrayList();
050 for (AST node=ast.getFirstChild(); node!=null; node=node.getNextSibling()) {
051 switch (node.getType()) {
052 case JavaTokenTypes.MODIFIERS:
053 for (AST child=node.getFirstChild(); child!=null; child=child.getNextSibling()) {
054 modifiers.add(child.getText());
055 }
056 break;
057 case JavaTokenTypes.IDENT:
058 name=node.getText();
059 break;
060 case JavaTokenTypes.DOT:
061 name=toString(node);
062 break;
063 case JavaTokenTypes.EXTENDS_CLAUSE:
064 for (AST interfaceNode=node.getFirstChild(); interfaceNode!=null; interfaceNode=interfaceNode.getNextSibling()) {
065 superInterfaces.add(toString(interfaceNode));
066 }
067 break;
068 default:
069 throw new GenerationException("Unexpected node: "+node);
070 }
071 }
072
073 cg = new ClassGen(
074 name,
075 "java.lang.Object",
076 description==null ? "<generated>" : description,
077 modifiers(modifiers) | Constants.ACC_INTERFACE,
078 (String[]) superInterfaces.toArray(new String[superInterfaces.size()]));
079
080 if (listener!=null) {
081 listener.onClass(cg, description);
082 }
083 } else {
084 throw new GenerationException("Invalid node type "+ast.getType()+" in definition '"+definition+"'");
085 }
086 }
087
088 /**
089 *
090 * @param definition E.g. <CODE>public void setX(int x)</CODE> All types shall be fully qualified.
091 * @param parameters Collection of {@link biz.hammurapi.util.Parameter} Parameters to be appended to parameters in definition. Can be null.
092 * @param description
093 * @return
094 * @throws GenerationException
095 */
096 public MethodGen addMethod(String definition, Collection parameters, String description, Properties attributes) throws GenerationException {
097 AST ast=field(definition);
098 if (ast.getType()==JavaTokenTypes.METHOD_DEF) {
099 Set modifiers=new HashSet();
100 String name=null;
101 String returnType=null;
102 Collection throwsList=new ArrayList();
103 Collection allParameters=new ArrayList();
104 class ParameterImpl implements Parameter {
105
106 private String type;
107 private String name;
108
109 ParameterImpl(String name, String type) {
110 this.name=name;
111 this.type=type;
112 }
113
114 public String getName() {
115 return name;
116 }
117
118 public String getType() {
119 return type;
120 }
121
122 }
123
124 for (AST node=ast.getFirstChild(); node!=null; node=node.getNextSibling()) {
125 switch (node.getType()) {
126 case JavaTokenTypes.MODIFIERS:
127 for (AST child=node.getFirstChild(); child!=null; child=child.getNextSibling()) {
128 modifiers.add(child.getText());
129 }
130 break;
131 case JavaTokenTypes.IDENT:
132 case JavaTokenTypes.INIT:
133 name=node.getText();
134 break;
135 case JavaTokenTypes.TYPE:
136 returnType = toString(node.getFirstChild());
137 break;
138 case JavaTokenTypes.PARAMETERS:
139 for (AST pnode = node.getFirstChild(); pnode!=null; pnode=pnode.getNextSibling()) {
140 for (AST ppnode=pnode.getFirstChild(); ppnode!=null; ppnode=pnode.getNextSibling()) {
141 String pname=null;
142 String ptype=null;
143 switch (ppnode.getType()) {
144 case JavaTokenTypes.IDENT:
145 pname=node.getText();
146 break;
147 case JavaTokenTypes.TYPE:
148 ptype=toString(ppnode.getFirstChild());
149 break;
150 default:
151 throw new GenerationException("Unexpected node: "+ppnode.getText());
152 }
153 allParameters.add(new ParameterImpl(pname, ptype));
154 }
155 }
156 break;
157 case JavaTokenTypes.LITERAL_throws:
158 for (AST tnode=node.getFirstChild(); tnode!=null; tnode=tnode.getNextSibling()) {
159 throwsList.add(toString(tnode));
160 }
161 break;
162
163 default:
164 throw new GenerationException("Unexpected node: "+node);
165 }
166 }
167
168 if (parameters!=null) {
169 allParameters.addAll(parameters);
170 }
171
172 Collection signature=new ArrayList();
173 signature.add(name);
174 Iterator pit=allParameters.iterator();
175 while (pit.hasNext()) {
176 signature.add(((Parameter) pit.next()).getType());
177 }
178
179 if (checkMethod(signature, returnType, throwsList)) {
180 Type[] args = new Type[allParameters.size()];
181 String[] argNames = new String[args.length];
182 pit=allParameters.iterator();
183 for (int i=0; pit.hasNext(); i++) {
184 Parameter p=(Parameter) pit.next();
185 args[i]=Type.getType(Utility.getSignature(p.getType()));
186 argNames[i]=p.getName();
187 }
188
189 InstructionList emptyInstructionList = new InstructionList();
190 MethodGen mg =
191 new MethodGen(
192 Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | modifiers(modifiers),
193 java2BcelType(returnType),
194 args,
195 argNames,
196 name,
197 cg.getClassName(),
198 emptyInstructionList,
199 cg.getConstantPool());
200
201 Iterator thit=throwsList.iterator();
202 while (thit.hasNext()) {
203 mg.addException((String) thit.next());
204 }
205
206 cg.addMethod(mg.getMethod());
207
208 emptyInstructionList.dispose();
209
210 if (listener!=null && (cg.isPublic() || cg.isProtected())) {
211 listener.onMethod(cg.getClassName(), mg.toString(), description, attributes);
212 }
213
214 return mg;
215 }
216 return null;
217 }
218 throw new GenerationException("Invalid node type "+ast.getType()+" in definition '"+definition+"'");
219 }
220
221 /**
222 * Creates a public static final field of specified name and type.
223 * @param name
224 * @param type
225 * @param description
226 * @param attributes
227 * @throws GenerationException
228 */
229 public void addField(String name, String type, String description, Properties attributes) throws GenerationException {
230 addField("public static final "+type+" "+name, description, attributes);
231 }
232 }