From f44ac29cde909e63eb394748c2f7e02bc460c6b6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 12 Jul 2011 18:18:08 +0200 Subject: [PATCH] simplest case of enum classes --- .../jetbrains/jet/codegen/ClassCodegen.java | 6 ++- .../codegen/ImplementationBodyCodegen.java | 9 ++++- .../jet/codegen/InterfaceBodyCodegen.java | 40 +++++++++++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 10 +++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 2ba069000ab..07dee13f7da 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -25,13 +25,15 @@ public class ClassCodegen { else { generateInterface(parentContext, aClass); generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION); - generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION); + if (!ImplementationBodyCodegen.isEnum(aClass)) { + generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION); + } } ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass); final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION); for (JetDeclaration declaration : aClass.getDeclarations()) { - if (declaration instanceof JetClass) { + if (declaration instanceof JetClass && !(declaration instanceof JetEnumEntry)) { generate(contextForInners, (JetClass) declaration); } } diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 12870900569..c87f0aff109 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -146,11 +146,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void generatePrimaryConstructor() { ConstructorDescriptor constructorDescriptor = state.getBindingContext().getConstructorDescriptor((JetElement) myClass); - if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration)) return; + if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return; Method method; CallableMethod callableMethod; - if (myClass instanceof JetObjectDeclaration) { + if (myClass instanceof JetObjectDeclaration || isEnum(myClass)) { method = new Method("", Type.VOID_TYPE, new Type[0]); callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.emptyList()); } @@ -278,6 +278,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv.visitEnd(); } + static boolean isEnum(JetClassOrObject myClass) { + final JetModifierList modifierList = myClass.getModifierList(); + return modifierList != null && modifierList.hasModifier(JetTokens.ENUM_KEYWORD); + } + @Nullable private ClassDescriptor getOuterClassDescriptor() { if (myClass.getParent() instanceof JetClassObject) { diff --git a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java index 2c7fb25aa0b..a9f67f3b5da 100644 --- a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java @@ -4,12 +4,17 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetDelegationSpecifier; +import org.jetbrains.jet.lang.psi.JetEnumEntry; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -18,6 +23,8 @@ import java.util.Set; * @author yole */ public class InterfaceBodyCodegen extends ClassBodyCodegen { + private final List myEnumConstants = new ArrayList(); + public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) { super(aClass, context, v, state); assert context.getContextKind() == OwnerKind.INTERFACE; @@ -73,4 +80,37 @@ public class InterfaceBodyCodegen extends ClassBodyCodegen { } return superInterfaces; } + + @Override + protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { + if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) { + String name = declaration.getName(); + final String desc = "L" + state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE) + ";"; + v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null); + if (myEnumConstants.isEmpty()) { + staticInitializerChunks.add(new CodeChunk() { + @Override + public void generate(InstructionAdapter v) { + initializeEnumConstants(v); + } + }); + } + myEnumConstants.add((JetEnumEntry) declaration); + } + else { + super.generateDeclaration(propertyCodegen, declaration, functionCodegen); + } + } + + private void initializeEnumConstants(InstructionAdapter v) { + for (JetEnumEntry enumConstant : myEnumConstants) { + // TODO type and constructor parameters + String intfClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE); + String implClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); + v.anew(Type.getObjectType(implClass)); + v.dup(); + v.invokespecial(implClass, "", "()V"); + v.putstatic(intfClass, enumConstant.getName(), "L" + intfClass + ";"); + } + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index b051e854244..d23f3c67b49 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.codegen; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; @@ -130,4 +131,13 @@ public class ClassGenTest extends CodegenTestCase { Object result = method.invoke(null); assertInstanceOf(result, Runnable.class); } + + public void testEnumClass() throws Exception { + loadText("enum class Direction { NORTH; SOUTH; EAST; WEST }"); + System.out.println(generateToText()); + final Class direction = loadAllClasses(generateClassesInFile()).get("Direction"); + final Field north = direction.getField("NORTH"); + assertEquals(direction, north.getType()); + assertInstanceOf(north.get(null), direction); + } }