Merge remote branch 'origin/master'
This commit is contained in:
@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
@@ -27,6 +28,8 @@ public class ClassCodegen {
|
|||||||
private final Codegens factory;
|
private final Codegens factory;
|
||||||
private final JetTypeMapper typeMapper;
|
private final JetTypeMapper typeMapper;
|
||||||
|
|
||||||
|
private static final Type TYPEINFO_TYPE = Type.getType(TypeInfo.class);
|
||||||
|
|
||||||
public ClassCodegen(Project project, Codegens factory, BindingContext bindingContext) {
|
public ClassCodegen(Project project, Codegens factory, BindingContext bindingContext) {
|
||||||
this.project = project;
|
this.project = project;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
@@ -73,11 +76,17 @@ public class ClassCodegen {
|
|||||||
JetTypeMapper.jvmName(descriptor, kind),
|
JetTypeMapper.jvmName(descriptor, kind),
|
||||||
null,
|
null,
|
||||||
superClass,
|
superClass,
|
||||||
new String[] {JetTypeMapper.jvmNameForInterface(descriptor)}
|
new String[] { "jet/JetObject", JetTypeMapper.jvmNameForInterface(descriptor) }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
|
||||||
|
|
||||||
|
generateStaticInitializer(descriptor, v);
|
||||||
|
|
||||||
generatePrimaryConstructor(aClass, v, kind);
|
generatePrimaryConstructor(aClass, v, kind);
|
||||||
|
|
||||||
|
generateGetTypeInfo(aClass, v);
|
||||||
|
|
||||||
generateClassBody(aClass, v, kind);
|
generateClassBody(aClass, v, kind);
|
||||||
|
|
||||||
v.visitEnd();
|
v.visitEnd();
|
||||||
@@ -349,4 +358,37 @@ public class ClassCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateStaticInitializer(ClassDescriptor descriptor, ClassVisitor cv) {
|
||||||
|
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
|
"<clinit>", "()V", null, null);
|
||||||
|
mv.visitCode();
|
||||||
|
|
||||||
|
InstructionAdapter v = new InstructionAdapter(mv);
|
||||||
|
v.anew(TYPEINFO_TYPE);
|
||||||
|
v.dup();
|
||||||
|
v.aconst(Type.getObjectType(JetTypeMapper.jvmNameForInterface(descriptor)));
|
||||||
|
v.invokespecial("jet/typeinfo/TypeInfo", "<init>", "(Ljava/lang/Class;)V");
|
||||||
|
v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||||
|
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateGetTypeInfo(JetClass aClass, ClassVisitor cv) {
|
||||||
|
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC,
|
||||||
|
"getTypeInfo",
|
||||||
|
"()Ljet/typeinfo/TypeInfo;",
|
||||||
|
null /* TODO */,
|
||||||
|
null);
|
||||||
|
mv.visitCode();
|
||||||
|
InstructionAdapter v = new InstructionAdapter(mv);
|
||||||
|
ClassDescriptor descriptor = bindingContext.getClassDescriptor(aClass);
|
||||||
|
v.getstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||||
|
v.areturn(TYPEINFO_TYPE);
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ import org.objectweb.asm.util.TraceClassVisitor;
|
|||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
@@ -22,7 +19,7 @@ public class Codegens {
|
|||||||
private final Project project;
|
private final Project project;
|
||||||
private final boolean isText;
|
private final boolean isText;
|
||||||
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||||
private final Map<String, ClassVisitor> generators = new HashMap<String, ClassVisitor>();
|
private final Map<String, ClassVisitor> generators = new LinkedHashMap<String, ClassVisitor>();
|
||||||
private boolean isDone = false;
|
private boolean isDone = false;
|
||||||
|
|
||||||
public Codegens(Project project, boolean text) {
|
public Codegens(Project project, boolean text) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.intellij.psi.search.ProjectScope;
|
|||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import jet.IntRange;
|
import jet.IntRange;
|
||||||
|
import jet.JetObject;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
@@ -44,6 +45,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
|
|
||||||
private static final Type ITERATOR_TYPE = Type.getType(Iterator.class);
|
private static final Type ITERATOR_TYPE = Type.getType(Iterator.class);
|
||||||
private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class);
|
private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class);
|
||||||
|
private static final Type JET_OBJECT_TYPE = Type.getType(JetObject.class);
|
||||||
|
|
||||||
private final Stack<Label> myContinueTargets = new Stack<Label>();
|
private final Stack<Label> myContinueTargets = new Stack<Label>();
|
||||||
private final Stack<Label> myBreakTargets = new Stack<Label>();
|
private final Stack<Label> myBreakTargets = new Stack<Label>();
|
||||||
@@ -1248,6 +1250,12 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeofExpression(JetTypeofExpression expression) {
|
||||||
|
gen(expression.getBaseExpression(), JET_OBJECT_TYPE);
|
||||||
|
v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;");
|
||||||
|
}
|
||||||
|
|
||||||
private static class CompilationException extends RuntimeException {
|
private static class CompilationException extends RuntimeException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ public class NamespaceCodegen {
|
|||||||
|
|
||||||
private void generateStaticInitializers(JetNamespace namespace, BindingContext bindingContext) {
|
private void generateStaticInitializers(JetNamespace namespace, BindingContext bindingContext) {
|
||||||
MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
"<clinit>", new Method("<clinit>", Type.VOID_TYPE, new Type[0]).getDescriptor(),
|
"<clinit>", "()V", null, null);
|
||||||
null, null);
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
|
|
||||||
FrameMap frameMap = new FrameMap();
|
FrameMap frameMap = new FrameMap();
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class Point() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = new Point()
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Point() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val p = new Point();
|
||||||
|
return typeof(p);
|
||||||
|
}
|
||||||
@@ -46,10 +46,7 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
public void testNewInstanceExplicitConstructor() throws Exception {
|
public void testNewInstanceExplicitConstructor() throws Exception {
|
||||||
loadFile("classes/newInstanceDefaultConstructor.jet");
|
loadFile("classes/newInstanceDefaultConstructor.jet");
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
final Codegens codegens = generateClassesInFile();
|
final Method method = generateFunction("test");
|
||||||
loadImplementationClass(codegens, "SimpleClass");
|
|
||||||
Class ns = loadRootNamespaceClass(codegens);
|
|
||||||
final Method method = findMethodByName(ns, "test");
|
|
||||||
final Integer returnValue = (Integer) method.invoke(null);
|
final Integer returnValue = (Integer) method.invoke(null);
|
||||||
assertEquals(610, returnValue.intValue());
|
assertEquals(610, returnValue.intValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.testFramework.LightProjectDescriptor;
|
import com.intellij.testFramework.LightProjectDescriptor;
|
||||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -12,7 +13,10 @@ import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
|||||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.channels.NonWritableChannelException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yole
|
* @author yole
|
||||||
@@ -40,6 +44,14 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
|||||||
myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/" + name);
|
myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void loadFile() {
|
||||||
|
loadFile(getPrefix() + "/" + getTestName(true) + ".jet");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getPrefix() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
protected void blackBoxFile(String filename) throws Exception {
|
protected void blackBoxFile(String filename) throws Exception {
|
||||||
loadFile(filename);
|
loadFile(filename);
|
||||||
//System.out.println(generateToText());
|
//System.out.println(generateToText());
|
||||||
@@ -86,7 +98,8 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
|||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
final JetNamespace namespace = jetFile.getRootNamespace();
|
||||||
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", ".");
|
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", ".");
|
||||||
return loadClass(fqName, state);
|
Map<String, Class> classMap = loadAllClasses(state);
|
||||||
|
return classMap.get(fqName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Class loadClass(String fqName, Codegens state) {
|
protected Class loadClass(String fqName, Codegens state) {
|
||||||
@@ -102,6 +115,17 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Map<String, Class> loadAllClasses(Codegens state) {
|
||||||
|
Map<String, Class> result = new HashMap<String, Class>();
|
||||||
|
for (String fileName : state.files()) {
|
||||||
|
String className = StringUtil.trimEnd(fileName, ".class").replace('/', '.');
|
||||||
|
byte[] data = state.asBytes(fileName);
|
||||||
|
Class aClass = myClassLoader.doDefineClass(className, data);
|
||||||
|
result.put(className, aClass);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected Codegens generateClassesInFile() {
|
protected Codegens generateClassesInFile() {
|
||||||
Codegens state = new Codegens(getProject(), false);
|
Codegens state = new Codegens(getProject(), false);
|
||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
|
|||||||
@@ -8,18 +8,23 @@ import java.lang.reflect.Modifier;
|
|||||||
* @author yole
|
* @author yole
|
||||||
*/
|
*/
|
||||||
public class PropertyGenTest extends CodegenTestCase {
|
public class PropertyGenTest extends CodegenTestCase {
|
||||||
|
@Override
|
||||||
|
protected String getPrefix() {
|
||||||
|
return "properties";
|
||||||
|
}
|
||||||
|
|
||||||
public void testPrivateVal() throws Exception {
|
public void testPrivateVal() throws Exception {
|
||||||
loadFile("properties/privateVal.jet");
|
loadFile();
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVal");
|
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVal");
|
||||||
final Field[] fields = aClass.getDeclaredFields();
|
final Field[] fields = aClass.getDeclaredFields();
|
||||||
assertEquals(1, fields.length);
|
assertEquals(2, fields.length); // $typeInfo, prop
|
||||||
final Field field = fields[0];
|
final Field field = fields[1];
|
||||||
assertEquals("prop", field.getName());
|
assertEquals("prop", field.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrivateVar() throws Exception {
|
public void testPrivateVar() throws Exception {
|
||||||
loadFile("properties/privateVar.jet");
|
loadFile();
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar");
|
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar");
|
||||||
final Object instance = aClass.newInstance();
|
final Object instance = aClass.newInstance();
|
||||||
@@ -73,7 +78,7 @@ public class PropertyGenTest extends CodegenTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testFieldSetter() throws Exception {
|
public void testFieldSetter() throws Exception {
|
||||||
loadFile("properties/fieldSetter.jet");
|
loadFile();
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
final Method method = generateFunction("append");
|
final Method method = generateFunction("append");
|
||||||
method.invoke(null, "IntelliJ ");
|
method.invoke(null, "IntelliJ ");
|
||||||
@@ -82,7 +87,7 @@ public class PropertyGenTest extends CodegenTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testFieldSetterPlusEq() throws Exception {
|
public void testFieldSetterPlusEq() throws Exception {
|
||||||
loadFile("properties/fieldSetterPlusEq.jet");
|
loadFile();
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
final Method method = generateFunction("append");
|
final Method method = generateFunction("append");
|
||||||
method.invoke(null, "IntelliJ ");
|
method.invoke(null, "IntelliJ ");
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import jet.JetObject;
|
||||||
|
import jet.typeinfo.TypeInfo;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yole
|
||||||
|
*/
|
||||||
|
public class TypeInfoTest extends CodegenTestCase {
|
||||||
|
@Override
|
||||||
|
protected String getPrefix() {
|
||||||
|
return "typeInfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetTypeInfo() throws Exception {
|
||||||
|
loadFile();
|
||||||
|
Method foo = generateFunction();
|
||||||
|
JetObject jetObject = (JetObject) foo.invoke(null);
|
||||||
|
TypeInfo<?> typeInfo = jetObject.getTypeInfo();
|
||||||
|
assertNotNull(typeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeOfOperator() throws Exception {
|
||||||
|
loadFile();
|
||||||
|
Method foo = generateFunction();
|
||||||
|
TypeInfo typeInfo = (TypeInfo) foo.invoke(null);
|
||||||
|
assertNotNull(typeInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -8,7 +8,12 @@ import jet.JetObject;
|
|||||||
public class TypeInfo<T> implements JetObject {
|
public class TypeInfo<T> implements JetObject {
|
||||||
|
|
||||||
private TypeInfo<?> typeInfo;
|
private TypeInfo<?> typeInfo;
|
||||||
private final TypeInfo<?> typeArgument;
|
private TypeInfo<?> typeArgument;
|
||||||
|
private Class<T> theClass;
|
||||||
|
|
||||||
|
public TypeInfo(Class<T> theClass) {
|
||||||
|
this.theClass = theClass;
|
||||||
|
}
|
||||||
|
|
||||||
private TypeInfo(TypeInfo<?> typeArgument) {
|
private TypeInfo(TypeInfo<?> typeArgument) {
|
||||||
this.typeArgument = typeArgument;
|
this.typeArgument = typeArgument;
|
||||||
|
|||||||
Reference in New Issue
Block a user