/*
* xtc - The eXTensible Compiler
* Copyright (C) 2006-2007 IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.lang;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import xtc.tree.Attribute;
import xtc.type.AliasT;
import xtc.type.ClassT;
import xtc.type.InterfaceT;
import xtc.type.MethodT;
import xtc.type.Type;
import xtc.type.VariableT;
import xtc.type.VoidT;
import xtc.util.SymbolTable;
import xtc.util.Utilities;
/**
* Uses reflection to construct externally visible types and fill in the symbol
* table for entities for which no source code is available. This is not a
* visitor, but has similar method names to emphasize the similarities with
* JavaExternalAnalyzer.
*
* @author Martin Hirzel
* @version $Revision: 1.27 $
*/
public final class JavaNoSourceAnalyzer {
public final SymbolTable _table;
public JavaNoSourceAnalyzer(final SymbolTable table) {
_table = table;
}
private final Type defineMethod(final List<Attribute> modifiers, MethodT result, final String symbol) {
for (final Attribute mod : modifiers)
result.addAttribute(mod);
_table.current().define(symbol, result);
_table.enter(symbol);
result.scope(_table.current().getQualifiedName());
_table.exit();
JavaEntities.currentType(_table).getMethods().add(result);
assert result.isMethod();
return result;
}
public final void visitClassBody(final Class clazz) {
final Class[] classes = clazz.getDeclaredClasses();
for (int i = 0; i < classes.length; i++)
visitClassOrInterface(classes[i]);
final Constructor[] constructors = clazz.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++)
visitMethodDeclaration(constructors[i]);
final Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
visitFieldDeclaration(fields[i]);
final Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++)
visitMethodDeclaration(methods[i]);
}
private static String getQName(final Class clazz) {
final Class declaringClass = clazz.getDeclaringClass();
if (null == declaringClass)
return clazz.getName();
return Utilities.qualify(getQName(declaringClass), clazz.getSimpleName());
}
public final Type visitClassDeclaration(final Class clazz) {
if (clazz.isInterface())
throw new Error(clazz.getName());
final List<Attribute> modifiers = visitModifiers(clazz.getModifiers());
final String canonicalName = getQName(clazz);
final String simpleName;
{
final String name = Utilities.getName(canonicalName);
final int i = name.lastIndexOf('$');
if (-1 == i)
simpleName = name;
else
simpleName = name.substring(1 + i);
}
final Type parent;
final Class superClass = clazz.getSuperclass();
if (null == superClass) {
parent = null;
if (!"java.lang.Object".equals(clazz.getName()))
throw new Error();
} else {
parent = visitType(clazz.getSuperclass());
}
final List<Type> interfaces = visitTypeList(clazz.getInterfaces());
final ClassT result = new ClassT(canonicalName, parent, interfaces,
new ArrayList<Type>(), new ArrayList<Type>());
for (final Attribute mod : modifiers)
result.addAttribute(mod);
final String tagName = SymbolTable.toTagName(simpleName);
_table.current().define(tagName, result);
_table.enter(simpleName);
result.scope(_table.current().getQualifiedName());
visitClassBody(clazz);
_table.exit();
assert result.isClass();
return result;
}
public final Type visitClassOrInterface(final Class clazz) {
return clazz.isInterface() ? visitInterfaceDeclaration(clazz)
: visitClassDeclaration(clazz);
}
public final Type visitFieldDeclaration(final Field field) {
final Type type = visitType(field.getType());
final VariableT result = VariableT.newField(type, field.getName());
for (final Attribute mod : visitModifiers(field.getModifiers()))
result.addAttribute(mod);
_table.current().define(field.getName(), result);
result.scope(_table.current().getQualifiedName());
JavaEntities.currentType(_table).getFields().add(result);
assert JavaEntities.isFieldT(result);
return result;
}
public final List<Type> visitFormalParameters(final Class[] types) {
final List<Type> result = new ArrayList<Type>(types.length);
for (int i = 0; i < types.length; i++) {
final VariableT p = VariableT.newParam(visitType(types[i]), "x" + i);
assert JavaEntities.isParameterT(p);
result.add(p);
}
return result;
}
public final Type visitInterfaceDeclaration(final Class interfaze) {
if (!interfaze.isInterface())
throw new Error(interfaze.getName());
final List<Attribute> modifiers = visitModifiers(interfaze.getModifiers());
final String canonicalName = interfaze.getName();
final String simpleName;
{
final String name = Utilities.getName(canonicalName);
final int i = name.lastIndexOf('$');
if (-1 == i)
simpleName = name;
else
simpleName = name.substring(1 + i);
}
final List<Type> interfaces = visitTypeList(interfaze.getInterfaces());
final InterfaceT result = new InterfaceT(canonicalName, interfaces,
new ArrayList<Type>(), new ArrayList<Type>());
for (final Attribute mod : modifiers)
result.addAttribute(mod);
final String tagName = SymbolTable.toTagName(simpleName);
_table.current().define(tagName, result);
_table.enter(simpleName);
result.scope(_table.current().getQualifiedName());
visitClassBody(interfaze);
_table.exit();
assert result.isInterface();
return result;
}
public final Type visitMethodDeclaration(final Constructor method) {
final List<Attribute> modifiers = visitModifiers(method.getModifiers());
final Type base = visitType(method.getDeclaringClass());
final List<Type> exceptions = visitTypeList(method.getExceptionTypes());
final String symbol = JavaEntities.methodSymbolFromConstructor(method);
final List<Type> parameters = visitFormalParameters(method.getParameterTypes());
final MethodT methodT = JavaEntities.newRawConstructor(base, parameters, exceptions);
final Type result = defineMethod(modifiers, methodT, symbol);
return result;
}
public final Type visitMethodDeclaration(final Method method) {
final List<Attribute> modifiers = visitModifiers(method.getModifiers());
final Type returnType = visitType(method.getReturnType());
final String name = method.getName();
final List<Type> exceptions = visitTypeList(method.getExceptionTypes());
final String symbol = JavaEntities.methodSymbolFromMethod(method);
final List<Type> parameters = visitFormalParameters(method.getParameterTypes());
final MethodT methodT = new MethodT(returnType, name, parameters, false, exceptions);
final Type result = defineMethod(modifiers, methodT, symbol);
return result;
}
public final List<Attribute> visitModifiers(final int modifiers) {
final List<Attribute> result = new ArrayList<Attribute>();
if (Modifier.isAbstract(modifiers))
result.add(JavaEntities.nameToModifier("abstract"));
if (Modifier.isFinal(modifiers))
result.add(JavaEntities.nameToModifier("final"));
if (Modifier.isNative(modifiers))
result.add(JavaEntities.nameToModifier("native"));
if (Modifier.isPrivate(modifiers))
result.add(JavaEntities.nameToModifier("private"));
if (Modifier.isProtected(modifiers))
result.add(JavaEntities.nameToModifier("protected"));
if (Modifier.isPublic(modifiers))
result.add(JavaEntities.nameToModifier("public"));
if (Modifier.isStatic(modifiers))
result.add(JavaEntities.nameToModifier("static"));
if (Modifier.isStrict(modifiers))
result.add(JavaEntities.nameToModifier("strictfp"));
if (Modifier.isSynchronized(modifiers))
result.add(JavaEntities.nameToModifier("synchronized"));
if (Modifier.isTransient(modifiers))
result.add(JavaEntities.nameToModifier("transient"));
if (Modifier.isVolatile(modifiers))
result.add(JavaEntities.nameToModifier("volatile"));
return result;
}
public final Type visitType(final Class clazz) {
Class componentC = clazz;
int dimensions = 0;
while (componentC.isArray()) {
componentC = componentC.getComponentType();
dimensions++;
}
final Type componentT = componentC.isPrimitive()
? visitTypeName(componentC.getName()) : new AliasT(componentC.getName());
final Type result = JavaEntities.typeWithDimensions(componentT, dimensions);
assert JavaEntities.isReturnT(result);
return result;
}
public final List<Type> visitTypeList(final Class[] types) {
final List<Type> result = new ArrayList<Type>(types.length);
for (int i = 0; i < types.length; i++)
result.add(visitType(types[i]));
return result;
}
public final Type visitTypeName(final String name) {
if (1 == name.length()) {
switch (name.charAt(0)) {
case 'Z':
return JavaEntities.nameToBaseType("boolean");
case 'B':
return JavaEntities.nameToBaseType("byte");
case 'C':
return JavaEntities.nameToBaseType("char");
case 'D':
return JavaEntities.nameToBaseType("double");
case 'F':
return JavaEntities.nameToBaseType("float");
case 'I':
return JavaEntities.nameToBaseType("int");
case 'J':
return JavaEntities.nameToBaseType("long");
case 'S':
return JavaEntities.nameToBaseType("short");
}
}
final Type result = JavaEntities.nameToBaseType(name);
assert result.isBoolean() || result.isNumber()
|| result instanceof VoidT;
return result;
}
}