001    package org.extendj.ast;
002    
003    import java.util.HashSet;
004    import java.io.File;
005    import java.util.Set;
006    import java.util.Collections;
007    import java.util.Collection;
008    import java.util.ArrayList;
009    import beaver.*;
010    import java.util.*;
011    import java.io.ByteArrayOutputStream;
012    import java.io.PrintStream;
013    import java.lang.reflect.InvocationTargetException;
014    import java.lang.reflect.Method;
015    import org.jastadd.util.*;
016    import java.util.zip.*;
017    import java.io.*;
018    import org.jastadd.util.PrettyPrintable;
019    import org.jastadd.util.PrettyPrinter;
020    import java.io.FileNotFoundException;
021    import java.io.BufferedInputStream;
022    import java.io.DataInputStream;
023    /**
024     * @ast class
025     * @aspect BytecodeReader
026     * @declaredat /home/jesper/git/extendj/java8/frontend/BytecodeReader.jrag:35
027     */
028    public class BytecodeParser extends AbstractClassfileParser implements Flags {
029      
030    
031        public String outerClassName;
032    
033      
034    
035        public BytecodeParser(InputStream in, String name) {
036          super(in, name);
037        }
038    
039      
040    
041        @Override
042        public boolean outerClassNameEquals(String name) {
043          return outerClassName != null && outerClassName.equals(name);
044        }
045    
046      
047    
048        public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName,
049            Program classPath, boolean isInner)
050            throws FileNotFoundException, IOException {
051          isInnerClass = isInner;
052          return parse(outerTypeDecl, outerClassName, classPath);
053        }
054    
055      
056    
057        public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName, Program program)
058            throws FileNotFoundException, IOException {
059    
060          if (VERBOSE) {
061            println("Parsing byte codes in " + name);
062          }
063    
064          this.outerClassName = outerClassName;
065          parseMagic();
066          int minor = parseMinor();
067          int major = parseMajor();
068          if (AbstractClassfileParser.VERBOSE) {
069            println(String.format("Classfile version: %d.%d", major, minor));
070          }
071          if (major > 52) {
072            error(String.format("Can not parse classfile version %d.%d."
073                  + " Classfile versions up to 52.x (Java 8) are supported by"
074                  + " this version of the compiler.",
075                  major, minor));
076          }
077          parseConstantPool();
078          CompilationUnit cu = new CompilationUnit();
079          TypeDecl typeDecl = parseTypeDecl();
080          cu.setPackageDecl(classInfo.packageDecl());
081          cu.addTypeDecl(typeDecl);
082          parseFields(typeDecl);
083          parseMethods(typeDecl);
084          //parse attributes, and if we have an inner class, then execute the branch...
085          if (new Attributes.TypeAttributes(this, typeDecl, outerTypeDecl, program).isInnerClass()) {
086            //this is a workaround for the fact that JastAdd stores inner classes as members of
087            //their outer classes, even for inner classes that come from bytecode;
088            //to avoid having inner classes show up as top-level classes, we remove them here
089            //from the compilation unit again...
090    
091            //first add the cu to the program, so that getTypeDecls() won't fail
092            program.addCompilationUnit(cu);
093            //then clear the cu
094            for (int i=0;i<cu.getTypeDecls().getNumChild();i++) {
095              cu.getTypeDecls().removeChild(i);
096            }
097            //and remove the cu from the program again
098            program.getCompilationUnits().removeChild(program.getCompilationUnits().getIndexOfChild(cu));
099          }
100    
101          return cu;
102        }
103    
104      
105    
106        public TypeDecl parseTypeDecl() throws IOException {
107          int flags = u2();
108          Modifiers modifiers = modifiers(flags & 0xfddf);
109          if ((flags & (ACC_INTERFACE | ACC_ENUM)) == ACC_ENUM) {
110            // Modifiers <ID:String> /[SuperClass:Access]/ Implements:Access* BodyDecl*;
111            EnumDecl decl = new EnumDecl();
112            decl.setModifiers(modifiers);
113            decl.setID(parseThisClass());
114            Access superClass = parseSuperClass();
115            // TODO trying to overwrite NTA?
116            decl.setImplementsList(parseInterfaces(new List()));
117            return decl;
118          } else if ((flags & ACC_INTERFACE) == 0) {
119            ClassDecl decl = new ClassDecl();
120            decl.setModifiers(modifiers);
121            decl.setID(parseThisClass());
122            Access superClass = parseSuperClass();
123            decl.setSuperClassOpt(
124                superClass == null
125                ? new Opt()
126                : new Opt(superClass));
127            decl.setImplementsList(parseInterfaces(new List()));
128            return decl;
129          } else if ((flags & ACC_ANNOTATION) == 0) {
130            InterfaceDecl decl = new InterfaceDecl();
131            decl.setModifiers(modifiers);
132            decl.setID(parseThisClass());
133            Access superClass = parseSuperClass();
134            decl.setSuperInterfaceList(parseInterfaces(
135                superClass == null
136                ? new List()
137                : new List().add(superClass)));
138            return decl;
139          } else {
140            AnnotationDecl decl = new AnnotationDecl();
141            decl.setModifiers(modifiers);
142            decl.setID(parseThisClass());
143            Access superClass = parseSuperClass();
144            parseInterfaces(
145                superClass == null
146                ? new List()
147                : new List().add(superClass));
148            return decl;
149          }
150        }
151    
152      
153    
154        public static Access fromClassName(String s) {
155          // Sample ClassName: a/b/c$d$e
156          // the package name ends at the last '/'
157          // after that follows a list of type names separated by '$'
158          // all except the first are nested types
159    
160          String packageName = "";
161          int index = s.lastIndexOf('/');
162          if (index != -1) {
163            packageName = s.substring(0, index).replace('/', '.');
164          }
165          String typeName = s.substring(index + 1, s.length());
166          if (typeName.indexOf('$') != -1) {
167            return new BytecodeTypeAccess(packageName, typeName);
168          } else {
169            return new TypeAccess(packageName, typeName);
170          }
171        }
172    
173      
174    
175        public void parseMethods(TypeDecl typeDecl) throws IOException {
176          int count = u2();
177          if (VERBOSE) {
178            println("Methods (" + count + "):");
179          }
180          for (int i = 0; i < count; i++) {
181            if (VERBOSE) {
182              print("  Method nbr " + i + " ");
183            }
184            MethodInfo info = new MethodInfo(this);
185            if (!info.isSynthetic() && !info.name.equals("<clinit>")) {
186              BodyDecl bodyDecl = info.bodyDecl();
187              if (bodyDecl instanceof MethodDecl && typeDecl instanceof InterfaceDecl) {
188                MethodDecl methodDecl = (MethodDecl) bodyDecl;
189                boolean foundAbstract = false;
190                boolean foundStatic = false;
191                for (int j = 0; j < methodDecl.getModifiers().getNumModifier(); j++) {
192                  Modifier modifier = methodDecl.getModifiers().getModifier(j);
193                  if (modifier.getID().equals("abstract")) {
194                    foundAbstract = true;
195                  } else if (modifier.getID().equals("static")) {
196                    foundStatic = true;
197                  }
198                }
199                if (!foundAbstract && !foundStatic) {
200                  methodDecl.getModifiers().addModifier(new Modifier("default"));
201                }
202              }
203              typeDecl.addBodyDecl(bodyDecl);
204            }
205          }
206        }
207    
208      
209    
210        @Override
211        public void parseConstantPoolEntry(int i) throws IOException {
212          int tag = u1();
213          switch (tag) {
214            case CONSTANT_Class:
215              constantPool[i] = new CONSTANT_Class_Info(this);
216              break;
217            case CONSTANT_FieldRef:
218              constantPool[i] = new CONSTANT_Fieldref_Info(this);
219              break;
220            case CONSTANT_MethodRef:
221              constantPool[i] = new CONSTANT_Methodref_Info(this);
222              break;
223            case CONSTANT_InterfaceMethodRef:
224              constantPool[i] = new CONSTANT_InterfaceMethodref_Info(this);
225              break;
226            case CONSTANT_String:
227              constantPool[i] = new CONSTANT_String_Info(this);
228              break;
229            case CONSTANT_Integer:
230              constantPool[i] = new CONSTANT_Integer_Info(this);
231              break;
232            case CONSTANT_Float:
233              constantPool[i] = new CONSTANT_Float_Info(this);
234              break;
235            case CONSTANT_Long:
236              constantPool[i] = new CONSTANT_Long_Info(this);
237              break;
238            case CONSTANT_Double:
239              constantPool[i] = new CONSTANT_Double_Info(this);
240              break;
241            case CONSTANT_NameAndType:
242              constantPool[i] = new CONSTANT_NameAndType_Info(this);
243              break;
244            case CONSTANT_Utf8:
245              constantPool[i] = new CONSTANT_Utf8_Info(this);
246              break;
247            case 15:
248              u1();
249              u2();
250              break;
251            case 16:
252              u2();
253              break;
254            case 18:
255              u2();
256              u2();
257            default:
258              println("Unknown entry: " + tag);
259          }
260        }
261    
262    
263    }