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 }