initial, barely working implementation of inner classes
This commit is contained in:
@@ -42,6 +42,12 @@ public class ClassCodegen {
|
|||||||
generateInterface(aClass);
|
generateInterface(aClass);
|
||||||
generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
|
generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
|
||||||
generateImplementation(aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
|
generateImplementation(aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
|
||||||
|
|
||||||
|
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||||
|
if (declaration instanceof JetClass) {
|
||||||
|
generate((JetClass) declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateInterface(JetClass aClass) {
|
private void generateInterface(JetClass aClass) {
|
||||||
@@ -70,12 +76,13 @@ public class ClassCodegen {
|
|||||||
String superClass = getSuperClass(aClass, kind);
|
String superClass = getSuperClass(aClass, kind);
|
||||||
|
|
||||||
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor);
|
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor);
|
||||||
|
final String defaultInterfaceName = JetTypeMapper.jvmNameForInterface(descriptor);
|
||||||
v.visit(Opcodes.V1_6,
|
v.visit(Opcodes.V1_6,
|
||||||
Opcodes.ACC_PUBLIC,
|
Opcodes.ACC_PUBLIC,
|
||||||
JetTypeMapper.jetJvmName(descriptor, kind),
|
JetTypeMapper.jetJvmName(descriptor, kind),
|
||||||
null,
|
null,
|
||||||
superClass,
|
superClass,
|
||||||
new String[] { "jet/JetObject", JetTypeMapper.jvmNameForInterface(descriptor) }
|
new String[] { "jet/JetObject", defaultInterfaceName}
|
||||||
);
|
);
|
||||||
|
|
||||||
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
|
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
|
||||||
@@ -180,9 +187,29 @@ public class ClassCodegen {
|
|||||||
String classname = typeMapper.jvmName(classDescriptor, kind);
|
String classname = typeMapper.jvmName(classDescriptor, kind);
|
||||||
final Type classType = Type.getType("L" + classname + ";");
|
final Type classType = Type.getType("L" + classname + ";");
|
||||||
|
|
||||||
|
List<JetDelegationSpecifier> specifiers = aClass.getDelegationSpecifiers();
|
||||||
|
|
||||||
|
if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) {
|
||||||
|
String superClass = getSuperClass(aClass, kind);
|
||||||
|
iv.load(0, Type.getType("L" + superClass + ";"));
|
||||||
|
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (ClassDescriptor outerClassDescriptor : JetTypeMapper.getOuterClassDescriptors(classDescriptor)) {
|
||||||
|
final Type type = JetTypeMapper.jetInterfaceType(outerClassDescriptor);
|
||||||
|
String interfaceDesc = type.getDescriptor();
|
||||||
|
final String fieldName = "this$" + index;
|
||||||
|
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
||||||
|
iv.load(0, classType);
|
||||||
|
iv.load(index + 1, type);
|
||||||
|
iv.putfield(classname, fieldName, interfaceDesc);
|
||||||
|
frameMap.enterTemp();
|
||||||
|
}
|
||||||
|
|
||||||
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||||
String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor();
|
String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor();
|
||||||
v.visitField(Opcodes.ACC_PRIVATE, "$this", interfaceDesc, /*TODO*/null, null);
|
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "$this", interfaceDesc, /*TODO*/null, null);
|
||||||
iv.load(1, argTypes[0]);
|
iv.load(1, argTypes[0]);
|
||||||
iv.putfield(classname, "$this", interfaceDesc);
|
iv.putfield(classname, "$this", interfaceDesc);
|
||||||
frameMap.enterTemp();
|
frameMap.enterTemp();
|
||||||
@@ -204,14 +231,6 @@ public class ClassCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<JetDelegationSpecifier> specifiers = aClass.getDelegationSpecifiers();
|
|
||||||
|
|
||||||
if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) {
|
|
||||||
String superClass = getSuperClass(aClass, kind);
|
|
||||||
iv.load(0, Type.getType("L" + superClass + ";"));
|
|
||||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSet<FunctionDescriptor> overriden = new HashSet<FunctionDescriptor>();
|
HashSet<FunctionDescriptor> overriden = new HashSet<FunctionDescriptor>();
|
||||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||||
if (declaration instanceof JetFunction) {
|
if (declaration instanceof JetFunction) {
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
final Type fieldType = psiTypeToAsm(psiField.getType());
|
final Type fieldType = psiTypeToAsm(psiField.getType());
|
||||||
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
|
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, null);
|
||||||
}
|
}
|
||||||
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
|
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isClass(container, "Array") && propertyDescriptor.getName().equals("size")) {
|
if (isClass(container, "Array") && propertyDescriptor.getName().equals("size")) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, null);
|
||||||
v.arraylength();
|
v.arraylength();
|
||||||
myStack.push(StackValue.onStack(Type.INT_TYPE));
|
myStack.push(StackValue.onStack(Type.INT_TYPE));
|
||||||
}
|
}
|
||||||
@@ -600,7 +600,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
||||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
|
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null);
|
||||||
}
|
}
|
||||||
myStack.push(iValue);
|
myStack.push(iValue);
|
||||||
}
|
}
|
||||||
@@ -709,7 +709,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC);
|
final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC);
|
||||||
|
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, null);
|
||||||
if (expression.getParent() instanceof JetQualifiedExpression) {
|
if (expression.getParent() instanceof JetQualifiedExpression) {
|
||||||
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
|
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
|
||||||
owner = expressionType(receiver).getInternalName();
|
owner = expressionType(receiver).getInternalName();
|
||||||
@@ -727,14 +727,14 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
methodDescriptor = typeMapper.mapSignature(jetFunction);
|
methodDescriptor = typeMapper.mapSignature(jetFunction);
|
||||||
if (functionParent instanceof NamespaceDescriptorImpl) {
|
if (functionParent instanceof NamespaceDescriptorImpl) {
|
||||||
if (jetFunction.getReceiverTypeRef() != null) {
|
if (jetFunction.getReceiverTypeRef() != null) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, null);
|
||||||
}
|
}
|
||||||
pushMethodArguments(expression, methodDescriptor);
|
pushMethodArguments(expression, methodDescriptor);
|
||||||
final String owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
|
final String owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
|
||||||
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
||||||
}
|
}
|
||||||
else if (functionParent instanceof ClassDescriptor) {
|
else if (functionParent instanceof ClassDescriptor) {
|
||||||
ensureReceiverOnStack(expression);
|
ensureReceiverOnStack(expression, (ClassDescriptor) functionParent);
|
||||||
pushMethodArguments(expression, methodDescriptor);
|
pushMethodArguments(expression, methodDescriptor);
|
||||||
final String owner = JetTypeMapper.jvmNameForInterface((ClassDescriptor) functionParent);
|
final String owner = JetTypeMapper.jvmNameForInterface((ClassDescriptor) functionParent);
|
||||||
v.invokeinterface(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
v.invokeinterface(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
||||||
@@ -756,7 +756,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureReceiverOnStack(JetElement expression) {
|
private void ensureReceiverOnStack(JetElement expression, @Nullable ClassDescriptor calleeContainingClass) {
|
||||||
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
|
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
|
||||||
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
||||||
if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
|
if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
|
||||||
@@ -769,6 +769,12 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
|
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
|
||||||
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
||||||
|
if (calleeContainingClass != null && contextType instanceof ClassDescriptor &&
|
||||||
|
calleeContainingClass == contextType.getContainingDeclaration()) {
|
||||||
|
v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION),
|
||||||
|
"this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.INTERFACE).getDescriptor());
|
||||||
|
// TODO handle more levels of class nestng
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1314,9 +1320,14 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
generateNewArray(expression, type);
|
generateNewArray(expression, type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
||||||
|
|
||||||
v.anew(type);
|
v.anew(type);
|
||||||
v.dup();
|
v.dup();
|
||||||
|
|
||||||
|
// TODO typechecker must verify that we're the outer class of the instance being created
|
||||||
|
pushOuterClassArguments(classDecl);
|
||||||
|
|
||||||
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||||
pushMethodArguments(expression, method);
|
pushMethodArguments(expression, method);
|
||||||
|
|
||||||
@@ -1326,7 +1337,6 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
|
ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
|
||||||
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
|
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1336,6 +1346,14 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
myStack.push(StackValue.onStack(type));
|
myStack.push(StackValue.onStack(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pushOuterClassArguments(ClassDescriptor classDecl) {
|
||||||
|
final List<ClassDescriptor> outerClassDescriptors = JetTypeMapper.getOuterClassDescriptors(classDecl);
|
||||||
|
if (outerClassDescriptors.size() > 0) {
|
||||||
|
v.load(0, JetTypeMapper.jetImplementationType(classDecl));
|
||||||
|
}
|
||||||
|
// TODO push further outer classes
|
||||||
|
}
|
||||||
|
|
||||||
private Type generateJavaConstructorCall(JetNewExpression expression, PsiMethod constructor) {
|
private Type generateJavaConstructorCall(JetNewExpression expression, PsiMethod constructor) {
|
||||||
PsiClass javaClass = constructor.getContainingClass();
|
PsiClass javaClass = constructor.getContainingClass();
|
||||||
Type type = JetTypeMapper.psiClassType(javaClass);
|
Type type = JetTypeMapper.psiClassType(javaClass);
|
||||||
|
|||||||
@@ -253,6 +253,9 @@ public class JetTypeMapper {
|
|||||||
List<ValueParameterDescriptor> parameters = descriptor.getUnsubstitutedValueParameters();
|
List<ValueParameterDescriptor> parameters = descriptor.getUnsubstitutedValueParameters();
|
||||||
List<Type> parameterTypes = new ArrayList<Type>();
|
List<Type> parameterTypes = new ArrayList<Type>();
|
||||||
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||||
|
for (ClassDescriptor outerDescriptor : getOuterClassDescriptors(classDescriptor)) {
|
||||||
|
parameterTypes.add(jvmType(outerDescriptor, OwnerKind.IMPLEMENTATION));
|
||||||
|
}
|
||||||
if (delegate) {
|
if (delegate) {
|
||||||
parameterTypes.add(jetInterfaceType(classDescriptor));
|
parameterTypes.add(jetInterfaceType(classDescriptor));
|
||||||
}
|
}
|
||||||
@@ -268,6 +271,16 @@ public class JetTypeMapper {
|
|||||||
return new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
return new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ClassDescriptor> getOuterClassDescriptors(ClassDescriptor classDescriptor) {
|
||||||
|
List<ClassDescriptor> result = new ArrayList<ClassDescriptor>();
|
||||||
|
DeclarationDescriptor outerClass = classDescriptor.getContainingDeclaration();
|
||||||
|
while (outerClass instanceof ClassDescriptor) {
|
||||||
|
result.add((ClassDescriptor) outerClass);
|
||||||
|
outerClass = outerClass.getContainingDeclaration();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
|
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
class Outer(val foo: StringBuilder) {
|
||||||
|
class Inner() {
|
||||||
|
fun len() {
|
||||||
|
return foo.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
return new Inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val sb = new StringBuilder("xyzzy")
|
||||||
|
val o = new Outer(sb)
|
||||||
|
val i = o.test()
|
||||||
|
val l = i.len()
|
||||||
|
return if (l != 5) "fail" else "OK"
|
||||||
|
}
|
||||||
@@ -58,4 +58,8 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
final Integer returnValue = (Integer) method.invoke(null);
|
final Integer returnValue = (Integer) method.invoke(null);
|
||||||
assertEquals(610, returnValue.intValue());
|
assertEquals(610, returnValue.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInnerClass() throws Exception {
|
||||||
|
blackBoxFile("classes/innerClass.jet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,8 +65,14 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
|||||||
|
|
||||||
protected void blackBoxFile(String filename) throws Exception {
|
protected void blackBoxFile(String filename) throws Exception {
|
||||||
loadFile(filename);
|
loadFile(filename);
|
||||||
//System.out.println(generateToText());
|
String actual;
|
||||||
assertEquals("OK", blackBox());
|
try {
|
||||||
|
actual = blackBox();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(generateToText());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
assertEquals("OK", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String blackBox() throws Exception {
|
protected String blackBox() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user