Merge branch 'master' of ssh://git.labs.intellij.net/jet
This commit is contained in:
Generated
+3
-1
@@ -4,6 +4,8 @@
|
||||
<root url="jar://$PROJECT_DIR$/lib/asm-util-3.3.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<SOURCES>
|
||||
<root url="file://$USER_HOME$/libs/asm-3.3.1/src" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public interface ClassBuilderFactory {
|
||||
ClassBuilder newClassBuilder();
|
||||
String asText(ClassBuilder builder);
|
||||
byte[] asBytes(ClassBuilder builder);
|
||||
|
||||
ClassBuilderFactory TEXT = new ClassBuilderFactory() {
|
||||
@Override
|
||||
public ClassBuilder newClassBuilder() {
|
||||
return new ClassBuilder(new TraceClassVisitor(new PrintWriter(new StringWriter())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asText(ClassBuilder builder) {
|
||||
TraceClassVisitor visitor = (TraceClassVisitor) builder.getVisitor();
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
visitor.print(new PrintWriter(writer));
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes(ClassBuilder builder) {
|
||||
throw new UnsupportedOperationException("TEXT generator asked for bytes");
|
||||
}
|
||||
};
|
||||
|
||||
ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
|
||||
@Override
|
||||
public ClassBuilder newClassBuilder() {
|
||||
return new ClassBuilder(new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asText(ClassBuilder builder) {
|
||||
throw new UnsupportedOperationException("BINARIES generator asked for text");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes(ClassBuilder builder) {
|
||||
ClassWriter visitor = (ClassWriter) builder.getVisitor();
|
||||
return visitor.toByteArray();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,42 +1,26 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ClassFileFactory {
|
||||
private final Project project;
|
||||
private final boolean isText;
|
||||
private final ClassBuilderFactory builderFactory;
|
||||
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
private final Map<String, ClassBuilder> generators = new LinkedHashMap<String, ClassBuilder>();
|
||||
private boolean isDone = false;
|
||||
public final GenerationState state;
|
||||
|
||||
public ClassFileFactory(Project project, boolean text, GenerationState state) {
|
||||
this.project = project;
|
||||
isText = text;
|
||||
public ClassFileFactory(ClassBuilderFactory builderFactory, GenerationState state) {
|
||||
this.builderFactory = builderFactory;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
ClassBuilder newVisitor(String filePath) {
|
||||
ClassVisitor visitor;
|
||||
if (isText) {
|
||||
visitor = new TraceClassVisitor(new PrintWriter(new StringWriter()));
|
||||
}
|
||||
else {
|
||||
visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
}
|
||||
|
||||
final ClassBuilder answer = new ClassBuilder(visitor);
|
||||
final ClassBuilder answer = builderFactory.newClassBuilder();
|
||||
generators.put(filePath, answer);
|
||||
return answer;
|
||||
}
|
||||
@@ -68,25 +52,13 @@ public class ClassFileFactory {
|
||||
}
|
||||
|
||||
public String asText(String file) {
|
||||
assert isText : "Need to create with text=true";
|
||||
|
||||
done();
|
||||
|
||||
TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file).getVisitor();
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
visitor.print(new PrintWriter(writer));
|
||||
|
||||
return writer.toString();
|
||||
return builderFactory.asText(generators.get(file));
|
||||
}
|
||||
|
||||
public byte[] asBytes(String file) {
|
||||
assert !isText : "This is debug stuff, only produces texts.";
|
||||
|
||||
done();
|
||||
|
||||
ClassWriter visitor = (ClassWriter) generators.get(file).getVisitor();
|
||||
return visitor.toByteArray();
|
||||
return builderFactory.asBytes(generators.get(file));
|
||||
}
|
||||
|
||||
public List<String> files() {
|
||||
|
||||
@@ -69,7 +69,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
signatureWriter.visitEnd();
|
||||
|
||||
cv.defineClass(V1_6,
|
||||
ACC_PUBLIC,
|
||||
ACC_PUBLIC/*|ACC_SUPER*/,
|
||||
name,
|
||||
null,
|
||||
funClass,
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
@@ -67,39 +62,4 @@ public class CodegenUtil {
|
||||
|
||||
return hasOuterTypeInfo(outerClassDescriptor);
|
||||
}
|
||||
|
||||
public static boolean hasTypeInfoField(JetType type) {
|
||||
if(type.getConstructor().getParameters().size() > 0)
|
||||
return true;
|
||||
|
||||
for (JetType jetType : type.getConstructor().getSupertypes()) {
|
||||
if(hasTypeInfoField(jetType))
|
||||
return true;
|
||||
}
|
||||
|
||||
ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor());
|
||||
if(outerClassDescriptor == null)
|
||||
return false;
|
||||
|
||||
return hasTypeInfoField(outerClassDescriptor.getDefaultType());
|
||||
}
|
||||
|
||||
public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
|
||||
if(!exceptOwn) {
|
||||
if(!isInterface(type))
|
||||
if(hasTypeInfoField(type))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (JetType jetType : type.getConstructor().getSupertypes()) {
|
||||
if(hasDerivedTypeInfoField(jetType, false))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Type arrayElementType(Type type) {
|
||||
return Type.getType(type.getDescriptor().substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,23 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) {
|
||||
throw new UnsupportedOperationException("Codegen for named functions is not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
||||
// final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||
// if (descriptor instanceof ClassDescriptor) {
|
||||
// return generateThisOrOuter((ClassDescriptor) descriptor);
|
||||
// }
|
||||
// else {
|
||||
// return thisExpression();
|
||||
// }
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitParenthesizedExpression(JetParenthesizedExpression expression, StackValue receiver) {
|
||||
return genQualified(receiver, expression.getExpression());
|
||||
@@ -285,7 +302,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
// if(hND != null)
|
||||
// invokeFunctionNoParams(hND, Type.BOOLEAN_TYPE, v);
|
||||
// else
|
||||
intermediateValueForProperty((PropertyDescriptor) hasNextDescriptor, false, false).put(Type.BOOLEAN_TYPE, v);
|
||||
intermediateValueForProperty((PropertyDescriptor) hasNextDescriptor, false, false, false).put(Type.BOOLEAN_TYPE, v);
|
||||
}
|
||||
v.ifeq(end);
|
||||
|
||||
@@ -793,16 +810,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
else {
|
||||
boolean isStatic = container instanceof NamespaceDescriptorImpl;
|
||||
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
||||
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL ;
|
||||
JetExpression r = getReceiverForSelector(expression);
|
||||
final boolean forceInterface = r != null && !(r instanceof JetThisExpression);
|
||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface);
|
||||
final boolean isSuper = r instanceof JetSuperExpression;
|
||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface, isSuper);
|
||||
if (!isStatic) {
|
||||
if (receiver == StackValue.none()) {
|
||||
receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration());
|
||||
}
|
||||
JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, r);
|
||||
receiver.put(receiverType != null ? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v);
|
||||
receiver.put(receiverType != null && !isSuper? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v);
|
||||
if(receiverType != null) {
|
||||
ClassDescriptor propReceiverDescriptor = (ClassDescriptor) propertyDescriptor.getContainingDeclaration();
|
||||
if(!CodegenUtil.isInterface(propReceiverDescriptor) && CodegenUtil.isInterface(receiverType.getConstructor().getDeclarationDescriptor())) {
|
||||
@@ -895,11 +913,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v);
|
||||
}
|
||||
|
||||
public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) {
|
||||
public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface, boolean isSuper) {
|
||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
|
||||
propertyDescriptor = propertyDescriptor.getOriginal();
|
||||
boolean isInsideClass = !forceInterface && containingDeclaration == context.getContextClass();
|
||||
boolean isInsideClass = !forceInterface && containingDeclaration == context.getContextClass() && contextKind() != OwnerKind.TRAIT_IMPL;
|
||||
Method getter;
|
||||
Method setter;
|
||||
if (forceField) {
|
||||
@@ -909,10 +927,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
else {
|
||||
//noinspection ConstantConditions
|
||||
getter = isInsideClass && (propertyDescriptor.getGetter() == null || propertyDescriptor.getGetter().isDefault())
|
||||
? null : typeMapper.mapGetterSignature(propertyDescriptor);
|
||||
? null : typeMapper.mapGetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
//noinspection ConstantConditions
|
||||
setter = isInsideClass && (propertyDescriptor.getSetter() == null || propertyDescriptor.getSetter().isDefault())
|
||||
? null : typeMapper.mapSetterSignature(propertyDescriptor);
|
||||
? null : typeMapper.mapSetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
}
|
||||
|
||||
String owner;
|
||||
@@ -931,7 +949,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
}
|
||||
|
||||
return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(propertyDescriptor.getOutType()), isStatic, isInterface, getter, setter);
|
||||
return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(propertyDescriptor.getOutType()), isStatic, isInterface, isSuper, getter, setter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1009,10 +1027,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
private DeclarationDescriptor resolveCalleeDescriptor(JetCallExpression call) {
|
||||
JetExpression callee = call.getCalleeExpression();
|
||||
if (!(callee instanceof JetSimpleNameExpression)) {
|
||||
if (!(callee instanceof JetReferenceExpression)) {
|
||||
throw new UnsupportedOperationException("Don't know how to generate a call to " + callee);
|
||||
}
|
||||
DeclarationDescriptor funDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) callee);
|
||||
DeclarationDescriptor funDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) callee);
|
||||
if (funDescriptor == null) {
|
||||
throw new CompilationException("Cannot resolve: " + callee.getText());
|
||||
}
|
||||
@@ -1883,7 +1901,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
Type type = JetTypeMapper.psiClassType(javaClass);
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructor);
|
||||
final CallableMethod callableMethod = JetTypeMapper.mapToCallableMethod(constructor);
|
||||
invokeMethodWithArguments(callableMethod, expression, StackValue.none());
|
||||
return type;
|
||||
}
|
||||
@@ -2071,6 +2089,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return generateThisOrOuter((ClassDescriptor) descriptor);
|
||||
}
|
||||
else {
|
||||
// estension function or ???
|
||||
return thisExpression();
|
||||
}
|
||||
}
|
||||
@@ -2260,7 +2279,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
|
||||
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if (jetType.getArguments().size() > 0 || !(descriptor instanceof ClassDescriptor)) {
|
||||
boolean javaClass = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor) instanceof PsiClass;
|
||||
if (!javaClass && (jetType.getArguments().size() > 0 || !(descriptor instanceof ClassDescriptor))) {
|
||||
generateTypeInfo(jetType);
|
||||
expressionToGen.put(OBJECT_TYPE, v);
|
||||
if (leaveExpressionOnStack) {
|
||||
@@ -2306,7 +2326,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!CodegenUtil.hasTypeInfoField(jetType)) {
|
||||
if(!typeMapper.hasTypeInfoField(jetType) && !(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetType.getConstructor().getDeclarationDescriptor()) instanceof PsiClass)) {
|
||||
// TODO: we need some better checks here
|
||||
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
@@ -2368,7 +2388,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
ownerType = JetTypeMapper.boxType(ownerType);
|
||||
if (containingDeclaration == context.getContextClass()) {
|
||||
if(!CodegenUtil.isInterface(descriptor)) {
|
||||
if (CodegenUtil.hasTypeInfoField(defaultType)) {
|
||||
if (typeMapper.hasTypeInfoField(defaultType)) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
@@ -2481,7 +2501,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call);
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
v.load(subjectLocal, subjectType);
|
||||
conditionValue = intermediateValueForProperty((PropertyDescriptor) descriptor, false, false);
|
||||
conditionValue = intermediateValueForProperty((PropertyDescriptor) descriptor, false, false, false);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("unknown simple name resolve result: " + descriptor);
|
||||
|
||||
@@ -28,10 +28,10 @@ public class GenerationState {
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final IntrinsicMethods intrinsics;
|
||||
|
||||
public GenerationState(Project project, boolean text) {
|
||||
public GenerationState(Project project, ClassBuilderFactory builderFactory) {
|
||||
this.project = project;
|
||||
this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
||||
this.factory = new ClassFileFactory(project, text, this);
|
||||
this.factory = new ClassFileFactory(builderFactory, this);
|
||||
this.intrinsics = new IntrinsicMethods(project, standardLibrary);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
v.defineClass(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0) | (isInterface
|
||||
? Opcodes.ACC_INTERFACE
|
||||
: 0),
|
||||
: 0/*Opcodes.ACC_SUPER*/),
|
||||
jvmName(),
|
||||
null,
|
||||
superClass,
|
||||
@@ -339,7 +339,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.putfield(classname, fieldName, interfaceDesc);
|
||||
}
|
||||
|
||||
if (CodegenUtil.hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) {
|
||||
if (state.getTypeMapper().hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) {
|
||||
generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv);
|
||||
}
|
||||
|
||||
@@ -652,7 +652,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
if(propertyDescriptor.getOutType().isNullable())
|
||||
type = JetTypeMapper.boxType(type);
|
||||
codegen.gen(initializer, type);
|
||||
codegen.intermediateValueForProperty(propertyDescriptor, false, false).store(iv);
|
||||
codegen.intermediateValueForProperty(propertyDescriptor, false, false, false).store(iv);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -706,8 +706,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
return;
|
||||
|
||||
JetType defaultType = descriptor.getDefaultType();
|
||||
if(CodegenUtil.hasTypeInfoField(defaultType)) {
|
||||
if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) {
|
||||
if(state.getTypeMapper().hasTypeInfoField(defaultType)) {
|
||||
if(!state.getTypeMapper().hasDerivedTypeInfoField(defaultType, true)) {
|
||||
v.newField(myClass, Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
|
||||
|
||||
MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null);
|
||||
|
||||
@@ -186,6 +186,39 @@ public class JetTypeMapper {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean hasTypeInfoField(JetType type) {
|
||||
if(type.getConstructor().getParameters().size() > 0) {
|
||||
if(!(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getConstructor().getDeclarationDescriptor()) instanceof PsiClass))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (JetType jetType : type.getConstructor().getSupertypes()) {
|
||||
if(hasTypeInfoField(jetType))
|
||||
return true;
|
||||
}
|
||||
|
||||
ClassDescriptor outerClassDescriptor = CodegenUtil.getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor());
|
||||
if(outerClassDescriptor == null)
|
||||
return false;
|
||||
|
||||
return hasTypeInfoField(outerClassDescriptor.getDefaultType());
|
||||
}
|
||||
|
||||
public boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
|
||||
if(!exceptOwn) {
|
||||
if(!CodegenUtil.isInterface(type))
|
||||
if(hasTypeInfoField(type))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (JetType jetType : type.getConstructor().getSupertypes()) {
|
||||
if(hasDerivedTypeInfoField(jetType, false))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String jvmName(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass);
|
||||
if (declaration instanceof PsiClass) {
|
||||
@@ -627,18 +660,29 @@ public class JetTypeMapper {
|
||||
answer.append(p.getName()); // TODO: BOUND!
|
||||
}
|
||||
|
||||
public Method mapGetterSignature(PropertyDescriptor descriptor) {
|
||||
public Method mapGetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
|
||||
Type returnType = mapType(descriptor.getOutType());
|
||||
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]);
|
||||
if(kind != OwnerKind.TRAIT_IMPL)
|
||||
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]);
|
||||
else {
|
||||
ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[] { mapType(containingDeclaration.getDefaultType()) });
|
||||
}
|
||||
}
|
||||
|
||||
public Method mapSetterSignature(PropertyDescriptor descriptor) {
|
||||
public Method mapSetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
|
||||
final JetType inType = descriptor.getInType();
|
||||
if (inType == null) {
|
||||
return null;
|
||||
}
|
||||
Type paramType = mapType(inType);
|
||||
return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType });
|
||||
if(kind != OwnerKind.TRAIT_IMPL) {
|
||||
return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType });
|
||||
}
|
||||
else {
|
||||
ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { mapType(containingDeclaration.getDefaultType()), paramType });
|
||||
}
|
||||
}
|
||||
|
||||
private Method mapConstructorSignature(ConstructorDescriptor descriptor, List<Type> valueParameterTypes) {
|
||||
@@ -654,9 +698,12 @@ public class JetTypeMapper {
|
||||
valueParameterTypes.add(type);
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = classDescriptor.getTypeConstructor().getParameters();
|
||||
for (int n = typeParameters.size(); n > 0; n--) {
|
||||
parameterTypes.add(TYPE_TYPEINFO);
|
||||
PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
|
||||
if(!(psiElement instanceof PsiClass)) {
|
||||
List<TypeParameterDescriptor> typeParameters = classDescriptor.getTypeConstructor().getParameters();
|
||||
for (int n = typeParameters.size(); n > 0; n--) {
|
||||
parameterTypes.add(TYPE_TYPEINFO);
|
||||
}
|
||||
}
|
||||
|
||||
return new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
@@ -667,7 +714,7 @@ public class JetTypeMapper {
|
||||
final Method method = mapConstructorSignature(descriptor, valueParameterTypes);
|
||||
String owner = jvmName(descriptor.getContainingDeclaration(), kind);
|
||||
final CallableMethod result = new CallableMethod(owner, method, Opcodes.INVOKESPECIAL, valueParameterTypes);
|
||||
result.setAcceptsTypeArguments(true);
|
||||
result.setAcceptsTypeArguments(!(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getContainingDeclaration()) instanceof PsiClass));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class NamespaceCodegen {
|
||||
this.state = state;
|
||||
|
||||
v.defineClass(V1_6,
|
||||
ACC_PUBLIC,
|
||||
ACC_PUBLIC/*|ACC_SUPER*/,
|
||||
getJVMClassName(fqName),
|
||||
null,
|
||||
//"jet/lang/Namespace",
|
||||
@@ -93,7 +93,7 @@ public class NamespaceCodegen {
|
||||
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
||||
final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
|
||||
codegen.genToJVMStack(initializer);
|
||||
codegen.intermediateValueForProperty(descriptor, true, false).store(new InstructionAdapter(mv));
|
||||
codegen.intermediateValueForProperty(descriptor, true, false, false).store(new InstructionAdapter(mv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,9 @@ public class PropertyCodegen {
|
||||
throw new UnsupportedOperationException("expect a property to have a property descriptor");
|
||||
}
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION) {
|
||||
generateBackingField(p, propertyDescriptor);
|
||||
if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind ==OwnerKind.TRAIT_IMPL ) {
|
||||
if(kind != OwnerKind.TRAIT_IMPL)
|
||||
generateBackingField(p, propertyDescriptor);
|
||||
generateGetter(p, propertyDescriptor);
|
||||
generateSetter(p, propertyDescriptor);
|
||||
}
|
||||
@@ -81,7 +82,7 @@ public class PropertyCodegen {
|
||||
final JetPropertyAccessor getter = p.getGetter();
|
||||
if (getter != null) {
|
||||
if (getter.getBodyExpression() != null) {
|
||||
functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor), propertyDescriptor.getGetter());
|
||||
functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind), propertyDescriptor.getGetter());
|
||||
}
|
||||
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
generateDefaultGetter(p, getter);
|
||||
@@ -102,7 +103,7 @@ public class PropertyCodegen {
|
||||
if (setter.getBodyExpression() != null) {
|
||||
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
|
||||
assert setterDescriptor != null;
|
||||
functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor), setterDescriptor);
|
||||
functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind), setterDescriptor);
|
||||
}
|
||||
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
generateDefaultSetter(p, setter);
|
||||
@@ -120,6 +121,10 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) {
|
||||
if (kind == OwnerKind.TRAIT_IMPL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
@@ -129,7 +134,7 @@ public class PropertyCodegen {
|
||||
if(isTrait && !(kind instanceof OwnerKind.DelegateKind))
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
|
||||
final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor();
|
||||
final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind).getDescriptor();
|
||||
String getterName = getterName(propertyDescriptor.getName());
|
||||
MethodVisitor mv = v.newMethod(origin, flags, getterName, signature, null, null);
|
||||
if (!isTrait || kind instanceof OwnerKind.DelegateKind) {
|
||||
@@ -162,6 +167,10 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) {
|
||||
if (kind == OwnerKind.TRAIT_IMPL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
@@ -171,7 +180,7 @@ public class PropertyCodegen {
|
||||
if(isTrait && !(kind instanceof OwnerKind.DelegateKind))
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
|
||||
final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor();
|
||||
final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind).getDescriptor();
|
||||
MethodVisitor mv = v.newMethod(origin, flags, setterName(propertyDescriptor.getName()), signature, null, null);
|
||||
if (!isTrait || kind instanceof OwnerKind.DelegateKind) {
|
||||
mv.visitCode();
|
||||
|
||||
@@ -96,8 +96,8 @@ public abstract class StackValue {
|
||||
return new InstanceField(type, owner, name);
|
||||
}
|
||||
|
||||
public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, Method getter, Method setter) {
|
||||
return new Property(name, owner, getter, setter, isStatic, isInterface, type);
|
||||
public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, boolean isSuper, Method getter, Method setter) {
|
||||
return new Property(name, owner, getter, setter, isStatic, isInterface, isSuper, type);
|
||||
}
|
||||
|
||||
public static StackValue expression(Type type, JetExpression expression, ExpressionCodegen generator) {
|
||||
@@ -623,8 +623,9 @@ public abstract class StackValue {
|
||||
private final String owner;
|
||||
private final boolean isStatic;
|
||||
private final boolean isInterface;
|
||||
private boolean isSuper;
|
||||
|
||||
public Property(String name, String owner, Method getter, Method setter, boolean aStatic, boolean isInterface, Type type) {
|
||||
public Property(String name, String owner, Method getter, Method setter, boolean aStatic, boolean isInterface, boolean isSuper, Type type) {
|
||||
super(type);
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
@@ -632,26 +633,37 @@ public abstract class StackValue {
|
||||
this.setter = setter;
|
||||
isStatic = aStatic;
|
||||
this.isInterface = isInterface;
|
||||
this.isSuper = isSuper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (getter == null) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor());
|
||||
if(isSuper && isInterface) {
|
||||
v.visitMethodInsn(Opcodes.INVOKESTATIC, owner + "$$TImpl", getter.getName(), getter.getDescriptor().replace("(","(L" + owner + ";"));
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor());
|
||||
if (getter == null) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor());
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isSuper ? Opcodes.INVOKESPECIAL : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor());
|
||||
}
|
||||
}
|
||||
coerce(type, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
if (setter == null) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
|
||||
if(isSuper && isInterface) {
|
||||
v.visitMethodInsn(Opcodes.INVOKESTATIC, owner + "$$TImpl", setter.getName(), setter.getDescriptor().replace("(","(L" + owner + ";"));
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor());
|
||||
if (setter == null) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isSuper ? Opcodes.INVOKESPECIAL : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen {
|
||||
@Override
|
||||
protected void generateDeclaration() {
|
||||
v.defineClass(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
|
||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL/*| Opcodes.ACC_SUPER*/,
|
||||
jvmName(),
|
||||
null,
|
||||
"java/lang/Object",
|
||||
|
||||
@@ -4,10 +4,13 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import jet.modules.IModuleBuilder;
|
||||
import jet.modules.IModuleSetBuilder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetCoreEnvironment;
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||
import org.jetbrains.jet.codegen.GeneratedClassLoader;
|
||||
@@ -40,7 +43,7 @@ public class CompileEnvironment {
|
||||
myEnvironment = new JetCoreEnvironment(myRootDisposable);
|
||||
}
|
||||
|
||||
public void setMyErrorStream(PrintStream errorStream) {
|
||||
public void setErrorStream(PrintStream errorStream) {
|
||||
myErrorStream = errorStream;
|
||||
}
|
||||
|
||||
@@ -86,7 +89,35 @@ public class CompileEnvironment {
|
||||
myEnvironment.addToClasspath(rtJarPath);
|
||||
}
|
||||
|
||||
public static File findActiveRtJar() {
|
||||
public static File findRtJar(boolean failOnError) {
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
File rtJar;
|
||||
if (javaHome == null) {
|
||||
rtJar = findActiveRtJar(failOnError);
|
||||
|
||||
if(rtJar == null && failOnError) {
|
||||
throw new CompileEnvironmentException("JAVA_HOME environment variable needs to be defined");
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtJar = findRtJar(javaHome);
|
||||
}
|
||||
|
||||
if ((rtJar == null || !rtJar.exists()) && failOnError) {
|
||||
throw new CompileEnvironmentException("No rt.jar found under JAVA_HOME=" + javaHome);
|
||||
}
|
||||
return rtJar;
|
||||
}
|
||||
|
||||
private static File findRtJar(String javaHome) {
|
||||
File rtJar = new File(javaHome, "jre/lib/rt.jar");
|
||||
if (rtJar.exists()) {
|
||||
return rtJar;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static File findActiveRtJar(boolean failOnError) {
|
||||
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||
if (systemClassLoader instanceof URLClassLoader) {
|
||||
URLClassLoader loader = (URLClassLoader) systemClassLoader;
|
||||
@@ -100,6 +131,17 @@ public class CompileEnvironment {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failOnError) {
|
||||
throw new CompileEnvironmentException("Could not find rt.jar in system class loader: " + StringUtil.join(loader.getURLs(), new Function<URL, String>() {
|
||||
@Override
|
||||
public String fun(URL url) {
|
||||
return url.toString();
|
||||
}
|
||||
}, ", "));
|
||||
}
|
||||
}
|
||||
else if (failOnError) {
|
||||
throw new CompileEnvironmentException("System class loader is not an URLClassLoader: " + systemClassLoader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -113,7 +155,12 @@ public class CompileEnvironment {
|
||||
final String directory = new File(moduleFile).getParent();
|
||||
for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) {
|
||||
ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory);
|
||||
writeToJar(moduleFactory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true);
|
||||
final String path = new File(directory, moduleBuilder.getModuleName() + ".jar").getPath();
|
||||
try {
|
||||
writeToJar(moduleFactory, new FileOutputStream(path), null, true);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new CompileEnvironmentException("Invalid jar path " + path, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +238,7 @@ public class CompileEnvironment {
|
||||
return new File(PathManager.getResourceRoot(CompileEnvironment.class, "/org/jetbrains/jet/compiler/CompileEnvironment.class")).getParentFile().getParentFile().getParent();
|
||||
}
|
||||
|
||||
public static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) {
|
||||
public static void writeToJar(ClassFileFactory factory, final OutputStream fos, @Nullable String mainClass, boolean includeRuntime) {
|
||||
try {
|
||||
Manifest manifest = new Manifest();
|
||||
final Attributes mainAttributes = manifest.getMainAttributes();
|
||||
@@ -200,7 +247,6 @@ public class CompileEnvironment {
|
||||
if (mainClass != null) {
|
||||
mainAttributes.putValue("Main-Class", mainClass);
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(jar);
|
||||
JarOutputStream stream = new JarOutputStream(fos, manifest);
|
||||
try {
|
||||
for (String file : factory.files()) {
|
||||
@@ -286,7 +332,11 @@ public class CompileEnvironment {
|
||||
|
||||
ClassFileFactory factory = session.generate();
|
||||
if (jar != null) {
|
||||
writeToJar(factory, jar, mainClass, true);
|
||||
try {
|
||||
writeToJar(factory, new FileOutputStream(jar), mainClass, true);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new CompileEnvironmentException("Invalid jar path " + jar, e);
|
||||
}
|
||||
}
|
||||
else if (outputDir != null) {
|
||||
writeToOutputDirectory(factory, outputDir);
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import org.jetbrains.jet.JetCoreEnvironment;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactory;
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||
import org.jetbrains.jet.codegen.GenerationState;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
@@ -93,7 +94,7 @@ public class CompileSession {
|
||||
}
|
||||
|
||||
public ClassFileFactory generate() {
|
||||
GenerationState generationState = new GenerationState(myEnvironment.getProject(), false);
|
||||
GenerationState generationState = new GenerationState(myEnvironment.getProject(), ClassBuilderFactory.BINARIES);
|
||||
generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces);
|
||||
return generationState.getFactory();
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironment;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironmentException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
@@ -38,11 +36,8 @@ public class KotlinCompiler {
|
||||
|
||||
CompileEnvironment environment = new CompileEnvironment();
|
||||
|
||||
File rtJar = initJdk();
|
||||
if (rtJar == null) return;
|
||||
|
||||
try {
|
||||
environment.setJavaRuntime(rtJar);
|
||||
environment.setJavaRuntime(CompileEnvironment.findRtJar(true));
|
||||
if (!environment.initializeKotlinRuntime()) {
|
||||
System.out.println("No runtime library found");
|
||||
return;
|
||||
@@ -60,33 +55,4 @@ public class KotlinCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
private static File initJdk() {
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
File rtJar;
|
||||
if (javaHome == null) {
|
||||
rtJar = CompileEnvironment.findActiveRtJar();
|
||||
|
||||
if(rtJar == null) {
|
||||
System.out.println("JAVA_HOME environment variable needs to be defined");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtJar = findRtJar(javaHome);
|
||||
}
|
||||
|
||||
if (rtJar == null || !rtJar.exists()) {
|
||||
System.out.print("No rt.jar found under JAVA_HOME=" + javaHome);
|
||||
return null;
|
||||
}
|
||||
return rtJar;
|
||||
}
|
||||
|
||||
private static File findRtJar(String javaHome) {
|
||||
File rtJar = new File(javaHome, "jre/lib/rt.jar");
|
||||
if (rtJar.exists()) {
|
||||
return rtJar;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,8 @@ public interface Errors {
|
||||
SimpleDiagnosticFactory SUPERTYPE_APPEARS_TWICE = SimpleDiagnosticFactory.create(ERROR, "A supertype appears twice");
|
||||
SimpleDiagnosticFactory FINAL_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "This type is final, so it cannot be inherited from");
|
||||
|
||||
ParameterizedDiagnosticFactory1<String> ILLEGAL_SELECTOR = ParameterizedDiagnosticFactory1.create(ERROR, "Expression ''{0}'' cannot be a selector (occur after a dot)");
|
||||
|
||||
SimpleDiagnosticFactory REF_PARAMETER_WITH_VAL_OR_VAR = SimpleDiagnosticFactory.create(ERROR, "'val' and 'var' are not allowed on ref-parameters");
|
||||
SimpleDiagnosticFactory VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION = SimpleDiagnosticFactory.create(ERROR, "A type annotation is required on a value parameter");
|
||||
SimpleDiagnosticFactory BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = SimpleDiagnosticFactory.create(ERROR, "'break' and 'continue' are only allowed inside a loop");
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -46,7 +49,32 @@ public class JetCallExpression extends JetExpression implements JetCallElement {
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JetExpression> getFunctionLiteralArguments() {
|
||||
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL_EXPRESSION);
|
||||
JetExpression calleeExpression = getCalleeExpression();
|
||||
ASTNode node;
|
||||
if (calleeExpression instanceof JetFunctionLiteralExpression) {
|
||||
node = calleeExpression.getNode().getTreeNext();
|
||||
}
|
||||
else {
|
||||
node = getNode().getFirstChildNode();
|
||||
}
|
||||
List<JetExpression> result = new SmartList<JetExpression>();
|
||||
while (node != null) {
|
||||
PsiElement psi = node.getPsi();
|
||||
if (psi instanceof JetFunctionLiteralExpression) {
|
||||
result.add((JetFunctionLiteralExpression) psi);
|
||||
}
|
||||
else if (psi instanceof JetPrefixExpression) {
|
||||
JetPrefixExpression prefixExpression = (JetPrefixExpression) psi;
|
||||
if (JetTokens.LABELS.contains(prefixExpression.getOperationSign().getReferencedNameElementType())) {
|
||||
JetExpression labeledExpression = prefixExpression.getBaseExpression();
|
||||
if (labeledExpression instanceof JetFunctionLiteralExpression) {
|
||||
result.add(labeledExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -177,7 +177,7 @@ public class CallResolver {
|
||||
else if (calleeExpression != null) {
|
||||
// Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2)
|
||||
ExpressionTypingServices typingServices = new ExpressionTypingServices(semanticServices, trace);
|
||||
JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE);// We are actually expecting a function, but there seems to be no easy way of expressing this
|
||||
JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE); // We are actually expecting a function, but there seems to be no easy way of expressing this
|
||||
|
||||
if (!JetStandardClasses.isFunctionType(calleeType)) {
|
||||
checkTypesWithNoCallee(trace, scope, call);
|
||||
@@ -187,13 +187,17 @@ public class CallResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), "for expression " + calleeExpression.getText());
|
||||
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), "[for expression " + calleeExpression.getText() + "]");
|
||||
FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType);
|
||||
ResolvedCallImpl<FunctionDescriptor> resolvedCall = ResolvedCallImpl.<FunctionDescriptor>create(functionDescriptor);
|
||||
resolvedCall.setReceiverArgument(call.getExplicitReceiver());
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(
|
||||
Collections.singleton(resolvedCall), call, dataFlowInfo));
|
||||
functionReference = new JetReferenceExpression(calleeExpression.getNode()) {
|
||||
};
|
||||
|
||||
// strictly speaking, this is a hack:
|
||||
// we need to pass a reference, but there's no reference in the PSI,
|
||||
// so we wrap what we have into a fake reference and pass it on (unwrap on the other end)
|
||||
functionReference = new JetFakeReference(calleeExpression);
|
||||
}
|
||||
else {
|
||||
checkTypesWithNoCallee(trace, scope, call);
|
||||
@@ -238,9 +242,17 @@ public class CallResolver {
|
||||
// trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor());
|
||||
// }
|
||||
// else {
|
||||
trace.record(REFERENCE_TARGET, reference, descriptor);
|
||||
// }
|
||||
trace.record(RESOLVED_CALL, reference, resolvedCall);
|
||||
if (reference instanceof JetFakeReference) {
|
||||
// This means that the callable being invoked was represented by an expression
|
||||
// rather than a reference expression
|
||||
JetFakeReference fakeReference = (JetFakeReference) reference;
|
||||
trace.record(RESOLVED_CALL, fakeReference.getActualElement(), resolvedCall);
|
||||
}
|
||||
else {
|
||||
trace.record(RESOLVED_CALL, reference, resolvedCall);
|
||||
trace.record(REFERENCE_TARGET, reference, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -471,23 +483,18 @@ public class CallResolver {
|
||||
else {
|
||||
// Explicit type arguments passed
|
||||
|
||||
for (JetTypeProjection typeArgument : jetTypeArguments) {
|
||||
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
// temporaryTrace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning
|
||||
temporaryTrace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeArgument));
|
||||
List<JetType> typeArguments = new ArrayList<JetType>();
|
||||
for (JetTypeProjection projection : jetTypeArguments) {
|
||||
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
temporaryTrace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||
}
|
||||
JetTypeReference typeReference = projection.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference));
|
||||
}
|
||||
}
|
||||
|
||||
int expectedTypeArgumentCount = candidate.getTypeParameters().size();
|
||||
if (expectedTypeArgumentCount == jetTypeArguments.size()) {
|
||||
List<JetType> typeArguments = new ArrayList<JetType>();
|
||||
for (JetTypeProjection projection : jetTypeArguments) {
|
||||
// TODO : check that there's no projection
|
||||
JetTypeReference typeReference = projection.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference));
|
||||
}
|
||||
}
|
||||
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, temporaryTrace);
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is used to wrap an expression that occurs in a reference position, such as a function literal, into a reference expression
|
||||
*
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetFakeReference extends JetReferenceExpression {
|
||||
private final JetElement actualElement;
|
||||
|
||||
public JetFakeReference(@NotNull JetElement actualElement) {
|
||||
super(actualElement.getNode());
|
||||
this.actualElement = actualElement;
|
||||
}
|
||||
|
||||
public JetElement getActualElement() {
|
||||
return actualElement;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -525,8 +525,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO : not a simple name -> resolve in scope, expect property type or a function type
|
||||
context.trace.report(UNSUPPORTED.on(selectorExpression, "getSelectorReturnType"));
|
||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -47,4 +47,36 @@ fun main(args : Array<String>) {
|
||||
<!CALLEE_NOT_A_FUNCTION!>1<!>()
|
||||
<!CALLEE_NOT_A_FUNCTION!>1<!>{}
|
||||
<!CALLEE_NOT_A_FUNCTION!>1<!>(){}
|
||||
}
|
||||
|
||||
fun f() : fun Int.() : Unit = {}
|
||||
|
||||
fun main1(args : Array<String>) {
|
||||
1.{Int.() => 1}();
|
||||
{1}()
|
||||
{(x : Int) => x}(1)
|
||||
1.{Int.(x : Int) => x}(1)
|
||||
@l{1}()
|
||||
1.({Int.() => 1})()
|
||||
1.(f())()
|
||||
1.if(true){f()}else{f()}()
|
||||
1.if(true){Int.() => 1}else{f()}()
|
||||
1.if(true){Int.() => 1}else{Int.() => 1}()
|
||||
|
||||
1.<!CALLEE_NOT_A_FUNCTION!>"sdf"<!>()
|
||||
|
||||
1.<!ILLEGAL_SELECTOR!>"sdf"<!>
|
||||
1.<!ILLEGAL_SELECTOR!>{}<!>
|
||||
1.<!ILLEGAL_SELECTOR!>if (true) {}<!>
|
||||
}
|
||||
|
||||
fun test() {
|
||||
{(x : Int) => 1}<!NO_VALUE_FOR_PARAMETER!>()<!>
|
||||
<!MISSING_RECEIVER!>{Int.() => 1}<!>()
|
||||
<!TYPE_MISMATCH!>"sd"<!>.{Int.() => 1}()
|
||||
val i : Int? = null
|
||||
i<!UNSAFE_CALL!>.<!>{Int.() => 1}()
|
||||
{}<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!><Int><!>()
|
||||
1<!UNNECESSARY_SAFE_CALL!>?.<!>{Int.() => 1}()
|
||||
1.<!NO_RECEIVER_ADMITTED!>{}<!>()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun test() {
|
||||
fun <T> foo(){}
|
||||
foo<<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>in Int<!>>()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// KT-439 Support labeled function lliterals in call arguments
|
||||
|
||||
inline fun run1<T>(body : fun() : T) : T = body()
|
||||
|
||||
fun main1(args : Array<String>) {
|
||||
run1 @l{ 1 } // should not be an error
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class N() : java.util.ArrayList<String>() {
|
||||
override fun add(el: String) : Boolean {
|
||||
super.add(el)
|
||||
return super.add(el + el)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = N()
|
||||
n.add("239")
|
||||
if (n.get(0) == "239" && n.get(1) == "239239") return "OK";
|
||||
return "fail";
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
open class M() {
|
||||
open var b: Int = 0
|
||||
}
|
||||
|
||||
class N() : M() {
|
||||
val a : Int
|
||||
get() {
|
||||
super.b = super.b + 1
|
||||
return super.b + 1
|
||||
}
|
||||
override var b: Int = a + 1
|
||||
|
||||
val superb : Int
|
||||
get() = super.b
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = N()
|
||||
System.out?.println("a: " + n.a + " b: " + n.b + " superb: " + n.superb)
|
||||
if (n.b == 3 && n.a == 4 && n.superb == 3) return "OK";
|
||||
return "fail";
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
trait M {
|
||||
var backingB : Int
|
||||
var b : Int
|
||||
get() = backingB
|
||||
set(value: Int) {
|
||||
backingB = value
|
||||
}
|
||||
}
|
||||
|
||||
class N() : M {
|
||||
override var backingB : Int = 0
|
||||
|
||||
val a : Int
|
||||
get() {
|
||||
super.b = super.b + 1
|
||||
return super.b + 1
|
||||
}
|
||||
override var b: Int = a + 1
|
||||
|
||||
val superb : Int
|
||||
get() = super.b
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = N()
|
||||
System.out?.println("a: " + n.a + " b: " + n.b + " superb: " + n.superb)
|
||||
if (n.b == 3 && n.a == 4 && n.superb == 3) return "OK";
|
||||
return "fail";
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class JetTestCaseBuilder {
|
||||
private static FilenameFilter emptyFilter = new FilenameFilter() {
|
||||
public static FilenameFilter emptyFilter = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File file, String name) {
|
||||
return true;
|
||||
@@ -43,6 +43,11 @@ public abstract class JetTestCaseBuilder {
|
||||
@NotNull
|
||||
public static TestSuite suiteForDirectory(String baseDataDir, @NotNull final String dataPath, boolean recursive, final FilenameFilter filter, @NotNull NamedTestFactory factory) {
|
||||
TestSuite suite = new TestSuite(dataPath);
|
||||
appendTestsInDirectory(baseDataDir, dataPath, recursive, filter, factory, suite);
|
||||
return suite;
|
||||
}
|
||||
|
||||
public static void appendTestsInDirectory(String baseDataDir, String dataPath, boolean recursive, final FilenameFilter filter, NamedTestFactory factory, TestSuite suite) {
|
||||
final String extensionJet = ".jet";
|
||||
final String extensionKt = ".kt";
|
||||
final FilenameFilter extensionFilter = new FilenameFilter() {
|
||||
@@ -76,7 +81,7 @@ public abstract class JetTestCaseBuilder {
|
||||
List<File> subdirs = Arrays.asList(files);
|
||||
Collections.sort(subdirs);
|
||||
for (File subdir : subdirs) {
|
||||
suite.addTest(suiteForDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, filter, factory));
|
||||
appendTestsInDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, filter, factory, suite);
|
||||
}
|
||||
}
|
||||
List<File> files = Arrays.asList(dir.listFiles(resultFilter));
|
||||
@@ -87,6 +92,5 @@ public abstract class JetTestCaseBuilder {
|
||||
String extension = fileName.endsWith(extensionJet) ? extensionJet : extensionKt;
|
||||
suite.addTest(factory.createTest(dataPath, fileName.substring(0, fileName.length() - extension.length())));
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public abstract class CodegenTestCase extends JetLiteFixture {
|
||||
}
|
||||
|
||||
protected String generateToText() {
|
||||
GenerationState state = new GenerationState(getProject(), true);
|
||||
GenerationState state = new GenerationState(getProject(), ClassBuilderFactory.TEXT);
|
||||
AnalyzingUtils.checkForSyntacticErrors(myFile);
|
||||
state.compile(myFile);
|
||||
|
||||
@@ -152,7 +152,7 @@ public abstract class CodegenTestCase extends JetLiteFixture {
|
||||
|
||||
protected ClassFileFactory generateClassesInFile() {
|
||||
try {
|
||||
GenerationState state = new GenerationState(getProject(), false);
|
||||
GenerationState state = new GenerationState(getProject(), ClassBuilderFactory.BINARIES);
|
||||
AnalyzingUtils.checkForSyntacticErrors(myFile);
|
||||
state.compile(myFile);
|
||||
|
||||
|
||||
@@ -80,4 +80,55 @@ public class FunctionGenTest extends CodegenTestCase {
|
||||
public void testKt395 () {
|
||||
blackBoxFile("regressions/kt395.jet");
|
||||
}
|
||||
/*
|
||||
public void testFunction () throws InvocationTargetException, IllegalAccessException {
|
||||
loadText("fun Any.foo() : fun(): String {\n" +
|
||||
" return { \"239\" + this }\n" +
|
||||
"}\n" +
|
||||
"fun box() : String {\n" +
|
||||
" return if((10.foo())() == \"23910\") \"OK\" else \"fail\"" +
|
||||
"}" +
|
||||
"");
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertTrue((Boolean) foo.invoke(null, "lala"));
|
||||
assertFalse((Boolean) foo.invoke(null, "mama"));
|
||||
}
|
||||
|
||||
fun Any.foo() : fun() : Unit {
|
||||
return {}
|
||||
}
|
||||
|
||||
fun Any.foo1() : fun(i : Int) : Unit {
|
||||
return {}
|
||||
}
|
||||
|
||||
fun foo2() : fun(i : fun()) : Unit {
|
||||
return {}
|
||||
}
|
||||
|
||||
fun fooT1<T>(t : T) : fun() : T {
|
||||
return {t}
|
||||
}
|
||||
|
||||
fun fooT2<T>() : fun(t : T) : T {
|
||||
return {it}
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
args.foo()()
|
||||
|
||||
args.foo1()(1)
|
||||
|
||||
foo2()({})
|
||||
(foo2()){}
|
||||
|
||||
val a = fooT1(1)()
|
||||
a : Int
|
||||
|
||||
val b = fooT2<Int>()(1)
|
||||
b : Int
|
||||
fooT2()(1) // : Any?
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
public class SuperGenTest extends CodegenTestCase {
|
||||
public void testBasicProperty () {
|
||||
blackBoxFile("/super/basicproperty.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
|
||||
public void testTraitProperty () {
|
||||
blackBoxFile("/super/traitproperty.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
|
||||
public void testBasicMethod () {
|
||||
blackBoxFile("/super/basicmethod.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,15 @@ import junit.framework.TestCase;
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -23,8 +32,9 @@ public class CompileEnvironmentTest extends TestCase {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testSmoke() {
|
||||
environment.setJavaRuntime(CompileEnvironment.findActiveRtJar());
|
||||
public void testSmoke() throws IOException {
|
||||
final File activeRtJar = CompileEnvironment.findRtJar(true);
|
||||
environment.setJavaRuntime(activeRtJar);
|
||||
environment.initializeKotlinRuntime();
|
||||
final String testDataDir = JetParsingTest.getTestDataDir() + "/compiler/smoke/";
|
||||
final IModuleSetBuilder setBuilder = environment.loadModuleScript(testDataDir + "Smoke.kts");
|
||||
@@ -33,5 +43,23 @@ public class CompileEnvironmentTest extends TestCase {
|
||||
final ClassFileFactory factory = environment.compileModule(moduleBuilder, testDataDir);
|
||||
assertNotNull(factory);
|
||||
assertNotNull(factory.asBytes("Smoke/namespace.class"));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
CompileEnvironment.writeToJar(factory, baos, null, false);
|
||||
JarInputStream is = new JarInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
final List<String> entries = listEntries(is);
|
||||
assertTrue(entries.contains("Smoke/namespace.class"));
|
||||
}
|
||||
|
||||
private List<String> listEntries(JarInputStream is) throws IOException {
|
||||
List<String> entries = new ArrayList<String>();
|
||||
while (true) {
|
||||
final JarEntry jarEntry = is.getNextJarEntry();
|
||||
if (jarEntry == null) {
|
||||
break;
|
||||
}
|
||||
entries.add(jarEntry.getName());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import java.util.concurrent.Executors
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.URLDecoder
|
||||
import java.io.*
|
||||
|
||||
import org.jboss.netty.bootstrap.ServerBootstrap
|
||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory
|
||||
import org.jboss.netty.channel.*
|
||||
import org.jboss.netty.handler.codec.http.*
|
||||
import org.jboss.netty.handler.stream.ChunkedWriteHandler
|
||||
import org.jboss.netty.handler.codec.frame.TooLongFrameException
|
||||
import org.jboss.netty.buffer.ChannelBuffers
|
||||
import org.jboss.netty.util.CharsetUtil
|
||||
import org.jboss.netty.handler.codec.http.HttpResponseStatus.*
|
||||
|
||||
import netty.*
|
||||
import jlstring.*
|
||||
|
||||
namespace jlstring {
|
||||
fun String.replace(c: Char, by: Char) : String = (this as java.lang.String).replace(c, by) as String
|
||||
|
||||
fun String.contains(s: String) : Boolean = (this as java.lang.String).contains(s as java.lang.CharSequence)
|
||||
|
||||
fun java.lang.String.plus(s: Any?) : String = (this as String) + s.toString()
|
||||
}
|
||||
|
||||
namespace netty {
|
||||
fun ChannelPipeline.with(op: fun ChannelPipeline.() ) : ChannelPipeline {
|
||||
this.op()
|
||||
return this
|
||||
}
|
||||
|
||||
fun HttpResponse.set(header: String, value: Any?) : Unit {
|
||||
setHeader(header, value)
|
||||
}
|
||||
|
||||
fun HttpResponse.setContent(content: Any?) : Unit {
|
||||
setContent(ChannelBuffers.copiedBuffer(content.toString() as java.lang.String, CharsetUtil.UTF_8))
|
||||
}
|
||||
|
||||
fun ChannelHandlerContext.sendError(status: HttpResponseStatus?) {
|
||||
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, status)
|
||||
response["Content-Type"] = "text/plain; charset=UTF-8"
|
||||
response.setContent("Failure: " + status.toString() + "\r\n")
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
this.getChannel()?.write(response)?.addListener(ChannelFutureListener.CLOSE)
|
||||
}
|
||||
|
||||
fun String.decodeURI(encoding : String) : String? {
|
||||
try {
|
||||
return URLDecoder.decode(this, encoding)
|
||||
}
|
||||
catch (e : UnsupportedEncodingException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.sanitizeUri() : String? {
|
||||
val path = decodeURI("UTF-8") ?: decodeURI("ISO-8859-1")
|
||||
if (path == null)
|
||||
throw Error()
|
||||
|
||||
val localizedPath : String = path.replace('/', File.separatorChar)
|
||||
return if (localizedPath.contains(File.separator + ".") ||
|
||||
localizedPath.contains("." + File.separator) ||
|
||||
localizedPath.startsWith(".") || endsWith("."))
|
||||
null
|
||||
else
|
||||
localizedPath
|
||||
}
|
||||
|
||||
class StandardPipelineFactory(val config: fun ChannelPipeline.():Unit) : ChannelPipelineFactory {
|
||||
override fun getPipeline() : ChannelPipeline {
|
||||
val pipeline = DefaultChannelPipeline().with {
|
||||
addLast("decoder", HttpRequestDecoder())
|
||||
addLast("aggregator", HttpChunkAggregator(65536))
|
||||
addLast("encoder", HttpResponseEncoder())
|
||||
addLast("chunkedWriter", ChunkedWriteHandler())
|
||||
}
|
||||
pipeline.config () // can not move it inside with{} because of codegen bug
|
||||
return pipeline
|
||||
}
|
||||
}
|
||||
|
||||
fun ServerBootstrap.configPipeline(config: fun ChannelPipeline.(): Unit) =
|
||||
setPipelineFactory(
|
||||
StandardPipelineFactory(config)
|
||||
)
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val bootstrap = ServerBootstrap(
|
||||
NioServerSocketChannelFactory(
|
||||
Executors.newCachedThreadPool(),
|
||||
Executors.newCachedThreadPool()
|
||||
)
|
||||
)
|
||||
bootstrap.configPipeline {
|
||||
addLast("handler", HttpStaticFileServerHandler(args[0]))
|
||||
}
|
||||
bootstrap.bind(InetSocketAddress(8080))
|
||||
}
|
||||
|
||||
class HttpStaticFileServerHandler(val rootDir: String) : SimpleChannelUpstreamHandler() {
|
||||
|
||||
fun messageReceived(ctx : ChannelHandlerContext, e : MessageEvent) {
|
||||
val request = e.getMessage() as HttpRequest
|
||||
if (request.getMethod() != HttpMethod.GET) {
|
||||
ctx.sendError(METHOD_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
val path = request.getUri()?.sanitizeUri()
|
||||
if (path == null) {
|
||||
ctx.sendError(FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
val file = File(rootDir + File.separator + path)
|
||||
if (file.isHidden() || !file.exists()) {
|
||||
ctx.sendError(NOT_FOUND)
|
||||
return
|
||||
}
|
||||
if (!file.isFile()) {
|
||||
ctx.sendError(FORBIDDEN)
|
||||
return
|
||||
}
|
||||
|
||||
var raf = RandomAccessFile(file, "r")
|
||||
|
||||
val fileLength = raf.length()
|
||||
|
||||
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, OK)
|
||||
response["Content-Length"] = fileLength
|
||||
|
||||
val ch = e.getChannel()
|
||||
ch?.write(response)
|
||||
ch?.write(DefaultFileRegion(raf.getChannel(), 0, fileLength))
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.Chunk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactory;
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||
import org.jetbrains.jet.codegen.GenerationState;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
@@ -69,7 +70,7 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
public void run() {
|
||||
VirtualFile[] allFiles = compileContext.getCompileScope().getFiles(null, true);
|
||||
|
||||
GenerationState generationState = new GenerationState(compileContext.getProject(), false);
|
||||
GenerationState generationState = new GenerationState(compileContext.getProject(), ClassBuilderFactory.BINARIES);
|
||||
List<JetNamespace> namespaces = Lists.newArrayList();
|
||||
for (VirtualFile virtualFile : allFiles) {
|
||||
PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile);
|
||||
|
||||
@@ -55,27 +55,27 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||
return new JetPsiCheckerTest(dataPath, name);
|
||||
}
|
||||
}));
|
||||
suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/regression/", false, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
}, suite);
|
||||
JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/regression/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||
return new JetPsiCheckerTest(dataPath, name);
|
||||
}
|
||||
}));
|
||||
suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/infos/", false, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
}, suite);
|
||||
JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/infos/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||
return new JetPsiCheckerTest(dataPath, name).setCheckInfos(true);
|
||||
}
|
||||
}));
|
||||
}, suite);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ namespace io {
|
||||
fun print(message : Float) { System.out?.print(message) }
|
||||
fun print(message : Double) { System.out?.print(message) }
|
||||
|
||||
fun println(message : Any?) {
|
||||
System.out?.println(message)
|
||||
}
|
||||
|
||||
fun println(message : Any?) { System.out?.println(message) }
|
||||
fun println(message : Int) { System.out?.println(message) }
|
||||
fun println(message : Long) { System.out?.println(message) }
|
||||
fun println(message : Byte) { System.out?.println(message) }
|
||||
|
||||
Reference in New Issue
Block a user