tools/java/src/stx/libjava/tools/environment/Environment.java
author Jan Vrany <jan.vrany@fit.cvut.cz>
Thu, 12 Sep 2013 00:24:05 +0100
branchdevelopment
changeset 2728 658220e93dc9
parent 2488 experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerEnvironment.java@5395660e3366
child 2729 ac412f6ea6d4
permissions -rw-r--r--
Java package reorganization. Compiler-related support classes moved to package tools, java package structure reorganized, classes renamed. The goal is to use same INameEnvironment and ICompulationUnit implementation for both compiling and parsing, highlighting and resolving.

package stx.libjava.tools.environment;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;

public class Environment implements INameEnvironment {
	protected ClassLoader classloader;
	public TypeRegistry types;
	
	public Environment() {
		 this(new TypeRegistry(), ClassLoader.getSystemClassLoader() );
	}
	
	public Environment(TypeRegistry types) {
		this(types, ClassLoader.getSystemClassLoader());
	}

	public Environment(ClassLoader cl) {
		 this(new TypeRegistry(), cl);
	}

	
	public Environment(TypeRegistry types, ClassLoader cl) {
		this.types = types;
		this.classloader = cl;
	}
	
	public ClassLoader getClassLoader() {
		return classloader;
	}

	/**
	 * Find a type with the given compound name.
	 * Answer the binary form of the type if it is known to be consistent.
	 * Otherwise, answer the compilation unit which defines the type
	 * or null if the type does not exist.
	 * Types in the default package are specified as {{typeName}}.
	 *
	 * It is unknown whether the package containing the type actually exists.
	 *
	 * NOTE: This method can be used to find a member type using its
	 * internal name A$B, but the source file for A is answered if the binary
	 * file is inconsistent.
	 */

	public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
		StringBuilder sb = new StringBuilder();
		if (compoundTypeName.length > 1) {
			for (int i = 0; i < compoundTypeName.length - 1; i++) {
				sb.append(compoundTypeName[i]);
				sb.append('.');
			}		
		}
		sb.append(compoundTypeName[compoundTypeName.length-1]);
		return findType(sb.toString());
	}
	
	/** 
	 * Returns a IBinaryType for class with given name or null
	 * if there's no such class. 
	 * @param name
	 * @return binary type or null (if no type is found)
	 */
	protected IBinaryType findTypeForClassNamed(String name) {
		IBinaryType type;
		
		type = types.get(name);
		if (type != null) return type;
		
		try {
			Class<?> c = Class.forName(name, false, classloader);
			InputStream cfs = findClassFileForClass(c);
			if (cfs == null) {
				return null;
			} else {
				types.put(name, cfs);
				return types.get(name);
			}
		} catch (ClassNotFoundException cnfe) {
			return null;
		} catch (RuntimeException e) {
			e.printStackTrace();
			return null;
		}		
	}
	
	protected NameEnvironmentAnswer findType(String name) {
		IBinaryType type = findTypeForClassNamed(name);
		if (type != null) {
			return new NameEnvironmentAnswer(type, null);
		} else {
			return null;
		}
	}
	/**
	 * Find a type named <typeName> in the package <packageName>.
	 * Answer the binary form of the type if it is known to be consistent.
	 * Otherwise, answer the compilation unit which defines the type
	 * or null if the type does not exist.
	 * The default package is indicated by char[0][].
	 *
	 * It is known that the package containing the type exists.
	 *
	 * NOTE: This method can be used to find a member type using its
	 * internal name A$B, but the source file for A is answered if the binary
	 * file is inconsistent.
	 */

	public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < packageName.length; i++) {
			sb.append(packageName[i]);
			sb.append('.');
		}
		sb.append(typeName);
		return findType(sb.toString());
		
	}
	/**
	 * Answer whether packageName is the name of a known subpackage inside
	 * the package parentPackageName. A top level package is found relative to null.
	 * The default package is always assumed to exist.
	 *
	 * For example:
	 *      isPackage({{java}, {awt}}, {event});
	 *      isPackage(null, {java});
	 */

	public boolean isPackage(char[][] parentPackageName, char[] packageName) {
		return Character.isLowerCase(packageName[0]);
	}

	/**
	 * This method cleans the environment uo. It is responsible for releasing the memory
	 * and freeing resources. Passed that point, the name environment is no longer usable.
	 *
	 * A name environment can have a long life cycle, therefore it is the responsibility of
	 * the code which created it to decide when it is a good time to clean it up.
	 */
	public void cleanup() {

	}
	
	/**
	 * Given a class, return an InputStream on corresponding .class file. 
	 * @return InputStream or null
	 */
	public InputStream findClassFileForClass(Class<?> c) {
		/* STX:LIBJAVA specific: ask the class for its classfile bytes... */
		if (System.getProperty("java.vm.name").equals("Smalltalk/X")) {
			byte[] bytes = findClassBytesForClass0(c);
			if (bytes != null) {
				return new ByteArrayInputStream(bytes);
			}
		}
	
		ClassLoader cl = c.getClassLoader();
		if (cl == null) { 
			cl = ClassLoader.getSystemClassLoader();
		}
		String cfilename = (new String(c.getName())).replace('.', '/') + ".class";
		return cl.getResourceAsStream(cfilename);		
	}
	
	public native byte[] findClassBytesForClass0(Class<?> c); 
	
	
	
	/**
	 * A registry for binary types. Eventually will do some caching in the future...
	 * 
	 * @author Jan Vrany
	 *
	 */
	public static class TypeRegistry {
	    protected Map<String, IBinaryType> typeMap = new HashMap<String, IBinaryType>();
	    
	    public IBinaryType get(String name) {
	        return typeMap.get(name);
	    }
	    
	    public void put(String name, IBinaryType type) {
	        typeMap.put(name,type);
	    }
	        
	    public void put(String name, InputStream classfile) {
	        try {
	            put(name, ClassFileReader.read(classfile, (new String(name).replace('.', '/') + ".class")));
	        } catch (ClassFormatException e) {
	            throw new RuntimeException(e);
	        } catch (IOException e) {
	            throw new RuntimeException(e);
	        }
	    }
	    
	    public void put(String name, byte[] classfile) {
	        put(name, new ByteArrayInputStream(classfile));
	    }
	}

}