"compiler" folder created
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA 10.x" jdkType="IDEA JDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="frontend.java" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="module" module-name="stdlib" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public interface Callable {
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class CallableMethod implements Callable {
|
||||
private String owner;
|
||||
private final Method signature;
|
||||
private final int invokeOpcode;
|
||||
private final List<Type> valueParameterTypes;
|
||||
private boolean acceptsTypeArguments = false;
|
||||
private boolean needsReceiverOnStack = false;
|
||||
private boolean ownerFromCall = false;
|
||||
private ClassDescriptor receiverClass = null;
|
||||
private Type generateCalleeType = null;
|
||||
|
||||
public CallableMethod(String owner, Method signature, int invokeOpcode, List<Type> valueParameterTypes) {
|
||||
this.owner = owner;
|
||||
this.signature = signature;
|
||||
this.invokeOpcode = invokeOpcode;
|
||||
this.valueParameterTypes = valueParameterTypes;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public Method getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public int getInvokeOpcode() {
|
||||
return invokeOpcode;
|
||||
}
|
||||
|
||||
public List<Type> getValueParameterTypes() {
|
||||
return valueParameterTypes;
|
||||
}
|
||||
|
||||
public boolean acceptsTypeArguments() {
|
||||
return acceptsTypeArguments;
|
||||
}
|
||||
|
||||
public void setAcceptsTypeArguments(boolean acceptsTypeArguments) {
|
||||
this.acceptsTypeArguments = acceptsTypeArguments;
|
||||
}
|
||||
|
||||
public void setNeedsReceiver(@Nullable ClassDescriptor receiverClass) {
|
||||
needsReceiverOnStack = true;
|
||||
this.receiverClass = receiverClass;
|
||||
}
|
||||
|
||||
public boolean needsReceiverOnStack() {
|
||||
return needsReceiverOnStack;
|
||||
}
|
||||
|
||||
public boolean isOwnerFromCall() {
|
||||
return ownerFromCall;
|
||||
}
|
||||
|
||||
public void setOwnerFromCall(boolean ownerFromCall) {
|
||||
this.ownerFromCall = ownerFromCall;
|
||||
}
|
||||
|
||||
public ClassDescriptor getReceiverClass() {
|
||||
return receiverClass;
|
||||
}
|
||||
|
||||
void invoke(InstructionAdapter v) {
|
||||
v.visitMethodInsn(getInvokeOpcode(), getOwner(), getSignature().getName(), getSignature().getDescriptor());
|
||||
}
|
||||
|
||||
public void requestGenerateCallee(Type objectType) {
|
||||
generateCalleeType = objectType;
|
||||
}
|
||||
|
||||
public Type getGenerateCalleeType() {
|
||||
return generateCalleeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class ClassBodyCodegen {
|
||||
protected final GenerationState state;
|
||||
|
||||
protected final JetClassOrObject myClass;
|
||||
protected final OwnerKind kind;
|
||||
protected final ClassDescriptor descriptor;
|
||||
protected final ClassVisitor v;
|
||||
protected final ClassContext context;
|
||||
|
||||
protected final List<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>();
|
||||
|
||||
public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
||||
this.state = state;
|
||||
descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
myClass = aClass;
|
||||
this.context = context;
|
||||
this.kind = context.getContextKind();
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
generateDeclaration();
|
||||
|
||||
generateSyntheticParts();
|
||||
|
||||
generateClassBody();
|
||||
|
||||
generateStaticInitializer();
|
||||
|
||||
v.visitEnd();
|
||||
}
|
||||
|
||||
protected abstract void generateDeclaration();
|
||||
|
||||
protected void generateSyntheticParts() {
|
||||
}
|
||||
|
||||
private void generateClassBody() {
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
|
||||
|
||||
for (JetDeclaration declaration : myClass.getDeclarations()) {
|
||||
generateDeclaration(propertyCodegen, declaration, functionCodegen);
|
||||
}
|
||||
|
||||
generatePrimaryConstructorProperties(propertyCodegen);
|
||||
}
|
||||
|
||||
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetNamedFunction) {
|
||||
try {
|
||||
functionCodegen.gen((JetNamedFunction) declaration);
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Error generating method " + myClass.getName() + "." + declaration.getName() + " in " + context, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen) {
|
||||
OwnerKind kind = context.getContextKind();
|
||||
for (JetParameter p : getPrimaryConstructorParameters()) {
|
||||
if (p.getValOrVarNode() != null) {
|
||||
PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
|
||||
if (propertyDescriptor != null) {
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
}
|
||||
|
||||
if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
v.visitField(Opcodes.ACC_PRIVATE, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<JetParameter> getPrimaryConstructorParameters() {
|
||||
if (myClass instanceof JetClass) {
|
||||
return ((JetClass) myClass).getPrimaryConstructorParameters();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private void generateStaticInitializer() {
|
||||
if (staticInitializerChunks.size() > 0) {
|
||||
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||
"<clinit>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
InstructionAdapter v = new InstructionAdapter(mv);
|
||||
|
||||
for (CodeChunk chunk : staticInitializerChunks) {
|
||||
chunk.generate(v);
|
||||
}
|
||||
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ClassCodegen {
|
||||
private final GenerationState state;
|
||||
|
||||
public ClassCodegen(GenerationState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void generate(ClassContext parentContext, JetClassOrObject aClass) {
|
||||
GenerationState.prepareAnonymousClasses((JetElement) aClass, state.getTypeMapper());
|
||||
|
||||
if (aClass instanceof JetObjectDeclaration) {
|
||||
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
|
||||
}
|
||||
else {
|
||||
generateInterface(parentContext, aClass);
|
||||
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
|
||||
}
|
||||
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetClass && !(declaration instanceof JetEnumEntry)) {
|
||||
generate(contextForInners, (JetClass) declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateInterface(ClassContext parentContext, JetClassOrObject aClass) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
final ClassVisitor visitor = state.forClassInterface(descriptor);
|
||||
new InterfaceBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.INTERFACE), visitor, state).generate();
|
||||
}
|
||||
|
||||
private void generateImplementation(ClassContext parentContext, JetClassOrObject aClass, OwnerKind kind) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION
|
||||
? state.forClassImplementation(descriptor)
|
||||
: state.forClassDelegatingImplementation(descriptor);
|
||||
new ImplementationBodyCodegen(aClass, parentContext.intoClass(descriptor, kind), v, state).generate();
|
||||
}
|
||||
|
||||
|
||||
public static void newTypeInfo(InstructionAdapter v, boolean isNullable, Type asmType) {
|
||||
v.aconst(asmType);
|
||||
v.iconst(isNullable?1:0);
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ClassContext {
|
||||
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null, null);
|
||||
private final DeclarationDescriptor contextType;
|
||||
private final OwnerKind contextKind;
|
||||
private final StackValue thisExpression;
|
||||
private final ClassContext parentContext;
|
||||
private final ClosureCodegen closure;
|
||||
private boolean thisWasUsed = false;
|
||||
|
||||
HashMap<JetType,Integer> typeInfoConstants;
|
||||
|
||||
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, ClosureCodegen closureCodegen) {
|
||||
this.contextType = contextType;
|
||||
this.contextKind = contextKind;
|
||||
this.thisExpression = thisExpression;
|
||||
this.parentContext = parentContext;
|
||||
closure = closureCodegen;
|
||||
}
|
||||
|
||||
public DeclarationDescriptor getContextDescriptor() {
|
||||
return contextType;
|
||||
}
|
||||
|
||||
public String getNamespaceClassName() {
|
||||
if(parentContext != STATIC)
|
||||
return parentContext.getNamespaceClassName();
|
||||
|
||||
return NamespaceCodegen.getJVMClassName(contextType.getName());
|
||||
}
|
||||
|
||||
public OwnerKind getContextKind() {
|
||||
return contextKind;
|
||||
}
|
||||
|
||||
public StackValue getThisExpression() {
|
||||
if (parentContext == null) return StackValue.none();
|
||||
|
||||
thisWasUsed = true;
|
||||
if (thisExpression != null) return thisExpression;
|
||||
return parentContext.getThisExpression();
|
||||
}
|
||||
|
||||
public ClassContext intoNamespace(NamespaceDescriptor descriptor) {
|
||||
return new ClassContext(descriptor, OwnerKind.NAMESPACE, null, this, null);
|
||||
}
|
||||
|
||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind) {
|
||||
final StackValue thisValue;
|
||||
thisValue = StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
|
||||
|
||||
return new ClassContext(descriptor, kind, thisValue, this, null);
|
||||
}
|
||||
|
||||
public ClassContext intoFunction(FunctionDescriptor descriptor) {
|
||||
int thisIdx = -1;
|
||||
if (getContextKind() != OwnerKind.NAMESPACE) {
|
||||
thisIdx++;
|
||||
}
|
||||
|
||||
final boolean hasReceiver = descriptor.getReceiverType() != null;
|
||||
if (hasReceiver) {
|
||||
thisIdx++;
|
||||
}
|
||||
|
||||
return new ClassContext(descriptor, getContextKind(), hasReceiver ? StackValue.local(thisIdx, JetTypeMapper.TYPE_OBJECT) : null, this, null);
|
||||
}
|
||||
|
||||
public ClassContext intoClosure(String internalClassName, ClosureCodegen closureCodegen) {
|
||||
final Type type = enclosingClassType(closureCodegen.state.getTypeMapper());
|
||||
StackValue outerClass = type != null
|
||||
? StackValue.instanceField(type, internalClassName, "this$0")
|
||||
: StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
|
||||
return new ClassContext(null, OwnerKind.IMPLEMENTATION, outerClass, this, closureCodegen);
|
||||
}
|
||||
|
||||
public FrameMap prepareFrame() {
|
||||
FrameMap frameMap = new FrameMap();
|
||||
|
||||
if (getContextKind() != OwnerKind.NAMESPACE) {
|
||||
frameMap.enterTemp(); // 0 slot for this
|
||||
}
|
||||
|
||||
if (hasReceiver()) {
|
||||
frameMap.enterTemp(); // Next slot for fake this
|
||||
}
|
||||
|
||||
return frameMap;
|
||||
}
|
||||
|
||||
private JetType receiverType() {
|
||||
return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiverType() : null;
|
||||
}
|
||||
|
||||
private boolean hasReceiver() {
|
||||
return receiverType() != null;
|
||||
}
|
||||
|
||||
public ClassContext getParentContext() {
|
||||
return parentContext;
|
||||
}
|
||||
|
||||
public Type jvmType(JetTypeMapper mapper) {
|
||||
if (contextType instanceof ClassDescriptor) {
|
||||
return mapper.jvmType((ClassDescriptor) contextType, contextKind);
|
||||
}
|
||||
else if (closure != null) {
|
||||
return Type.getObjectType(closure.name);
|
||||
}
|
||||
else {
|
||||
return parentContext != null ? parentContext.jvmType(mapper) : JetTypeMapper.TYPE_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
public DeclarationDescriptor getContextClass() {
|
||||
DeclarationDescriptor descriptor = getContextDescriptor();
|
||||
if (descriptor == null || descriptor instanceof ClassDescriptor || descriptor instanceof NamespaceDescriptor) return descriptor;
|
||||
|
||||
final ClassContext parent = getParentContext();
|
||||
return parent != null ? parent.getContextClass() : null;
|
||||
}
|
||||
|
||||
public boolean isThisWasUsed() {
|
||||
return thisWasUsed;
|
||||
}
|
||||
|
||||
public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v) {
|
||||
final ClosureCodegen top = closure;
|
||||
if (top != null) {
|
||||
final StackValue answer = top.lookupInContext(d);
|
||||
if (answer != null) return answer;
|
||||
|
||||
final StackValue thisContext = getThisExpression();
|
||||
thisContext.put(thisContext.type, v);
|
||||
}
|
||||
|
||||
return parentContext != null ? parentContext.lookupInContext(d, v) : null;
|
||||
}
|
||||
|
||||
public Type enclosingClassType(JetTypeMapper mapper) {
|
||||
DeclarationDescriptor descriptor = getContextDescriptor();
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return Type.getObjectType(mapper.jvmName((ClassDescriptor) descriptor, OwnerKind.INTERFACE));
|
||||
}
|
||||
|
||||
if (descriptor instanceof NamespaceDescriptor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (closure != null) {
|
||||
return Type.getObjectType(closure.name);
|
||||
}
|
||||
|
||||
final ClassContext parent = getParentContext();
|
||||
return parent != null ? parent.enclosingClassType(mapper) : null;
|
||||
}
|
||||
|
||||
public int getTypeInfoConstantIndex(JetType type) {
|
||||
if(parentContext != STATIC)
|
||||
return parentContext.getTypeInfoConstantIndex(type);
|
||||
|
||||
if(typeInfoConstants == null)
|
||||
typeInfoConstants = new HashMap<JetType, Integer>();
|
||||
|
||||
Integer index = typeInfoConstants.get(type);
|
||||
if(index == null) {
|
||||
index = typeInfoConstants.size();
|
||||
typeInfoConstants.put(type, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
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 Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
private final Map<String, ClassVisitor> generators = new LinkedHashMap<String, ClassVisitor>();
|
||||
private boolean isDone = false;
|
||||
public final GenerationState state;
|
||||
|
||||
public ClassFileFactory(Project project, boolean text, GenerationState state) {
|
||||
this.project = project;
|
||||
isText = text;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
ClassVisitor newVisitor(String filePath) {
|
||||
ClassVisitor visitor;
|
||||
if (isText) {
|
||||
visitor = new TraceClassVisitor(new PrintWriter(new StringWriter()));
|
||||
}
|
||||
else {
|
||||
visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
}
|
||||
|
||||
generators.put(filePath, visitor);
|
||||
return visitor;
|
||||
}
|
||||
|
||||
ClassVisitor forAnonymousSubclass(String className) {
|
||||
return newVisitor(className + ".class");
|
||||
}
|
||||
|
||||
NamespaceCodegen forNamespace(JetNamespace namespace) {
|
||||
assert !isDone : "Already done!";
|
||||
String fqName = namespace.getFQName();
|
||||
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
||||
if (codegen == null) {
|
||||
final ClassVisitor classVisitor = newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class");
|
||||
codegen = new NamespaceCodegen(classVisitor, fqName, state, namespace.getContainingFile());
|
||||
ns2codegen.put(fqName, codegen);
|
||||
}
|
||||
|
||||
return codegen;
|
||||
}
|
||||
|
||||
private void done() {
|
||||
if (!isDone) {
|
||||
isDone = true;
|
||||
for (NamespaceCodegen codegen : ns2codegen.values()) {
|
||||
codegen.done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String asText(String file) {
|
||||
assert isText : "Need to create with text=true";
|
||||
|
||||
done();
|
||||
|
||||
TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file);
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
visitor.print(new PrintWriter(writer));
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public byte[] asBytes(String file) {
|
||||
assert !isText : "This is debug stuff, only produces texts.";
|
||||
|
||||
done();
|
||||
|
||||
ClassWriter visitor = (ClassWriter) generators.get(file);
|
||||
return visitor.toByteArray();
|
||||
}
|
||||
|
||||
public List<String> files() {
|
||||
done();
|
||||
return new ArrayList<String>(generators.keySet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
import org.objectweb.asm.signature.SignatureWriter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClosureCodegen {
|
||||
public final GenerationState state;
|
||||
private final ExpressionCodegen exprContext;
|
||||
private final ClassContext context;
|
||||
private ClassVisitor cv = null;
|
||||
public String name = null;
|
||||
|
||||
private Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
|
||||
|
||||
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) {
|
||||
this.state = state;
|
||||
this.exprContext = exprContext;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public static Method erasedInvokeSignature(FunctionDescriptor fd) {
|
||||
boolean isExtensionFunction = fd.getReceiverType() != null;
|
||||
int paramCount = fd.getValueParameters().size();
|
||||
if (isExtensionFunction) {
|
||||
paramCount++;
|
||||
}
|
||||
|
||||
Type[] args = new Type[paramCount];
|
||||
Arrays.fill(args, JetTypeMapper.TYPE_OBJECT);
|
||||
return new Method("invoke", JetTypeMapper.TYPE_OBJECT, args);
|
||||
}
|
||||
|
||||
public Method invokeSignature(FunctionDescriptor fd) {
|
||||
return state.getTypeMapper().mapSignature("invoke", fd);
|
||||
}
|
||||
|
||||
public StackValue lookupInContext(DeclarationDescriptor d) {
|
||||
if (d instanceof VariableDescriptor) {
|
||||
VariableDescriptor vd = (VariableDescriptor) d;
|
||||
|
||||
EnclosedValueDescriptor answer = closure.get(vd);
|
||||
if (answer != null) return answer.getInnerValue();
|
||||
|
||||
final int idx = exprContext.lookupLocal(vd);
|
||||
if (idx < 0) return null;
|
||||
|
||||
final Type type = state.getTypeMapper().mapType(vd.getOutType());
|
||||
|
||||
StackValue outerValue = StackValue.local(idx, type);
|
||||
final String fieldName = "$" + (closure.size() + 1);
|
||||
StackValue innerValue = StackValue.field(type, name, fieldName, false);
|
||||
cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
|
||||
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
|
||||
closure.put(d, answer);
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) {
|
||||
final Pair<String, ClassVisitor> nameAndVisitor = state.forAnonymousSubclass(fun);
|
||||
|
||||
final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, fun);
|
||||
|
||||
cv = nameAndVisitor.getSecond();
|
||||
name = nameAndVisitor.getFirst();
|
||||
|
||||
SignatureWriter signatureWriter = new SignatureWriter();
|
||||
|
||||
final List<ValueParameterDescriptor> parameters = funDescriptor.getValueParameters();
|
||||
final String funClass = getInternalClassName(funDescriptor);
|
||||
signatureWriter.visitClassType(funClass);
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
appendType(signatureWriter, parameter.getOutType(), '=');
|
||||
}
|
||||
|
||||
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
|
||||
signatureWriter.visitEnd();
|
||||
|
||||
cv.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
name,
|
||||
null,
|
||||
funClass,
|
||||
new String[0]
|
||||
);
|
||||
cv.visitSource(fun.getContainingFile().getName(), null);
|
||||
|
||||
|
||||
generateBridge(name, funDescriptor, cv);
|
||||
boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
||||
final Type enclosingType = context.enclosingClassType(state.getTypeMapper());
|
||||
if (enclosingType == null) captureThis = false;
|
||||
|
||||
final Method constructor = generateConstructor(funClass, captureThis);
|
||||
|
||||
if (captureThis) {
|
||||
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null);
|
||||
}
|
||||
|
||||
cv.visitEnd();
|
||||
|
||||
final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis);
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor);
|
||||
answer.addArg(valueDescriptor.getOuterValue());
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
|
||||
final ClassContext closureContext = context.intoClosure(name, this);
|
||||
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
|
||||
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
|
||||
return closureContext.isThisWasUsed();
|
||||
}
|
||||
|
||||
private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) {
|
||||
final Method bridge = erasedInvokeSignature(funDescriptor);
|
||||
final Method delegate = invokeSignature(funDescriptor);
|
||||
|
||||
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]);
|
||||
mv.visitCode();
|
||||
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
iv.load(0, Type.getObjectType(className));
|
||||
|
||||
final JetType receiverType = funDescriptor.getReceiverType();
|
||||
int count = 1;
|
||||
if (receiverType != null) {
|
||||
StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
StackValue.onStack(JetTypeMapper.TYPE_OBJECT).upcast(state.getTypeMapper().mapType(receiverType), iv);
|
||||
count++;
|
||||
}
|
||||
|
||||
final List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
|
||||
for (ValueParameterDescriptor param : params) {
|
||||
StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
StackValue.onStack(JetTypeMapper.TYPE_OBJECT).upcast(state.getTypeMapper().mapType(param.getOutType()), iv);
|
||||
count++;
|
||||
}
|
||||
|
||||
iv.invokespecial(className, "invoke", delegate.getDescriptor());
|
||||
StackValue.onStack(delegate.getReturnType()).put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
|
||||
iv.areturn(JetTypeMapper.TYPE_OBJECT);
|
||||
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private Method generateConstructor(String funClass, boolean captureThis) {
|
||||
int argCount = closure.size();
|
||||
|
||||
if (captureThis) {
|
||||
argCount++;
|
||||
}
|
||||
|
||||
Type[] argTypes = new Type[argCount];
|
||||
|
||||
|
||||
int i = 0;
|
||||
if (captureThis) {
|
||||
i = 1;
|
||||
argTypes[0] = context.enclosingClassType(state.getTypeMapper());
|
||||
}
|
||||
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
argTypes[i++] = state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType());
|
||||
}
|
||||
|
||||
final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
|
||||
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
iv.load(0, Type.getObjectType(funClass));
|
||||
iv.invokespecial(funClass, "<init>", "()V");
|
||||
|
||||
i = 1;
|
||||
for (Type type : argTypes) {
|
||||
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
StackValue.local(i, type).put(type, iv);
|
||||
final String fieldName;
|
||||
if (captureThis && i == 1) {
|
||||
fieldName = "this$0";
|
||||
captureThis = false;
|
||||
}
|
||||
else {
|
||||
fieldName = "$" + (i);
|
||||
i++;
|
||||
}
|
||||
|
||||
StackValue.field(type, name, fieldName, false).store(iv);
|
||||
}
|
||||
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public static String getInternalClassName(FunctionDescriptor descriptor) {
|
||||
final int paramCount = descriptor.getValueParameters().size();
|
||||
if (descriptor.getReceiverType() != null) {
|
||||
return "jet/ExtensionFunction" + paramCount;
|
||||
}
|
||||
else {
|
||||
return "jet/Function" + paramCount;
|
||||
}
|
||||
}
|
||||
|
||||
private void appendType(SignatureWriter signatureWriter, JetType type, char variance) {
|
||||
signatureWriter.visitTypeArgument(variance);
|
||||
|
||||
final JetTypeMapper typeMapper = state.getTypeMapper();
|
||||
final Type rawRetType = typeMapper.boxType(typeMapper.mapType(type));
|
||||
signatureWriter.visitClassType(rawRetType.getInternalName());
|
||||
signatureWriter.visitEnd();
|
||||
}
|
||||
|
||||
public static CallableMethod asCallableMethod(FunctionDescriptor fd) {
|
||||
Method descriptor = erasedInvokeSignature(fd);
|
||||
String owner = getInternalClassName(fd);
|
||||
final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
|
||||
if (fd.getReceiverType() != null) {
|
||||
result.setNeedsReceiver(null);
|
||||
}
|
||||
result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd)));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public interface CodeChunk {
|
||||
void generate(InstructionAdapter v);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ConstructorFrameMap extends FrameMap {
|
||||
private int myOuterThisIndex = -1;
|
||||
private int myFirstTypeParameter = -1;
|
||||
private int myTypeParameterCount = 0;
|
||||
|
||||
public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, OwnerKind kind) {
|
||||
enterTemp(); // this
|
||||
ClassDescriptor classDescriptor = null;
|
||||
if (descriptor != null) {
|
||||
classDescriptor = descriptor.getContainingDeclaration();
|
||||
if (classDescriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
myOuterThisIndex = enterTemp(); // outer class instance
|
||||
}
|
||||
}
|
||||
|
||||
List<Type> explicitArgTypes = callableMethod.getValueParameterTypes();
|
||||
|
||||
List<ValueParameterDescriptor> paramDescrs = descriptor != null
|
||||
? descriptor.getValueParameters()
|
||||
: Collections.<ValueParameterDescriptor>emptyList();
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
enter(parameter, explicitArgTypes.get(i).getSize());
|
||||
}
|
||||
|
||||
|
||||
if (classDescriptor != null) {
|
||||
myTypeParameterCount = classDescriptor.getTypeConstructor().getParameters().size();
|
||||
if (kind == OwnerKind.IMPLEMENTATION) {
|
||||
if (myTypeParameterCount > 0) {
|
||||
myFirstTypeParameter = enterTemp();
|
||||
for (int i = 1; i < myTypeParameterCount; i++) {
|
||||
enterTemp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getOuterThisIndex() {
|
||||
return myOuterThisIndex;
|
||||
}
|
||||
|
||||
public int getFirstTypeParameter() {
|
||||
return myFirstTypeParameter;
|
||||
}
|
||||
|
||||
public int getTypeParameterCount() {
|
||||
return myTypeParameterCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
public class EnclosedValueDescriptor {
|
||||
private final DeclarationDescriptor descriptor;
|
||||
private final StackValue innerValue;
|
||||
private final StackValue outerValue;
|
||||
|
||||
public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, StackValue outerValue) {
|
||||
this.descriptor = descriptor;
|
||||
this.innerValue = innerValue;
|
||||
this.outerValue = outerValue;
|
||||
}
|
||||
|
||||
public DeclarationDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public StackValue getInnerValue() {
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
public StackValue getOuterValue() {
|
||||
return outerValue;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import gnu.trove.TObjectIntIterator;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class FrameMap {
|
||||
private final TObjectIntHashMap<DeclarationDescriptor> myVarIndex = new TObjectIntHashMap<DeclarationDescriptor>();
|
||||
private final TObjectIntHashMap<DeclarationDescriptor> myVarSizes = new TObjectIntHashMap<DeclarationDescriptor>();
|
||||
private int myMaxIndex = 0;
|
||||
|
||||
public void enter(DeclarationDescriptor descriptor, int size) {
|
||||
myVarIndex.put(descriptor, myMaxIndex);
|
||||
myMaxIndex += size;
|
||||
myVarSizes.put(descriptor, size);
|
||||
}
|
||||
|
||||
public int leave(DeclarationDescriptor descriptor) {
|
||||
int size = myVarSizes.get(descriptor);
|
||||
myMaxIndex -= size;
|
||||
myVarSizes.remove(descriptor);
|
||||
return myVarIndex.remove(descriptor);
|
||||
}
|
||||
|
||||
public int enterTemp() {
|
||||
return myMaxIndex++;
|
||||
}
|
||||
|
||||
public int enterTemp(int size) {
|
||||
int result = myMaxIndex;
|
||||
myMaxIndex += size;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void leaveTemp() {
|
||||
myMaxIndex--;
|
||||
}
|
||||
|
||||
public void leaveTemp(int size) {
|
||||
myMaxIndex -= size;
|
||||
}
|
||||
|
||||
public int getIndex(DeclarationDescriptor descriptor) {
|
||||
return myVarIndex.contains(descriptor) ? myVarIndex.get(descriptor) : -1;
|
||||
}
|
||||
|
||||
public Mark mark() {
|
||||
return new Mark(myMaxIndex);
|
||||
}
|
||||
|
||||
public class Mark {
|
||||
private final int myIndex;
|
||||
|
||||
public Mark(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
public void dropTo() {
|
||||
List<DeclarationDescriptor> descriptorsToDrop = new ArrayList<DeclarationDescriptor>();
|
||||
TObjectIntIterator<DeclarationDescriptor> iterator = myVarIndex.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
iterator.advance();
|
||||
if (iterator.value() >= myIndex) {
|
||||
descriptorsToDrop.add(iterator.key());
|
||||
}
|
||||
}
|
||||
for (DeclarationDescriptor declarationDescriptor : descriptorsToDrop) {
|
||||
myVarIndex.remove(declarationDescriptor);
|
||||
myVarSizes.remove(declarationDescriptor);
|
||||
}
|
||||
myMaxIndex = myIndex;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
*/
|
||||
public class FunctionCodegen {
|
||||
private final ClassContext owner;
|
||||
private final ClassVisitor v;
|
||||
private final GenerationState state;
|
||||
|
||||
public FunctionCodegen(ClassContext owner, ClassVisitor v, GenerationState state) {
|
||||
this.owner = owner;
|
||||
this.v = v;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void gen(JetNamedFunction f) {
|
||||
Method method = state.getTypeMapper().mapToCallableMethod(f).getSignature();
|
||||
final FunctionDescriptor functionDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, f);
|
||||
generateMethod(f, method, functionDescriptor);
|
||||
}
|
||||
|
||||
public void generateMethod(JetDeclarationWithBody f, Method jvmMethod, FunctionDescriptor functionDescriptor) {
|
||||
ClassContext funContext = owner.intoFunction(functionDescriptor);
|
||||
|
||||
final JetExpression bodyExpression = f.getBodyExpression();
|
||||
generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor);
|
||||
}
|
||||
|
||||
private void generateBridgeMethod(Method function, Method overriden)
|
||||
{
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO.
|
||||
|
||||
final MethodVisitor mv = v.visitMethod(flags, function.getName(), overriden.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
|
||||
Type[] argTypes = function.getArgumentTypes();
|
||||
InstructionAdapterEx iv = new InstructionAdapterEx(mv);
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||
Type argType = argTypes[i];
|
||||
iv.load(reg, argType);
|
||||
reg += argType.getSize();
|
||||
}
|
||||
|
||||
iv.invokevirtual(state.getTypeMapper().jvmName((ClassDescriptor) owner.getContextDescriptor(), OwnerKind.IMPLEMENTATION), function.getName(), function.getDescriptor());
|
||||
if(JetTypeMapper.isPrimitive(function.getReturnType()) && !JetTypeMapper.isPrimitive(overriden.getReturnType()))
|
||||
iv.valueOf(function.getReturnType());
|
||||
if(function.getReturnType() == Type.VOID_TYPE)
|
||||
iv.aconst(null);
|
||||
iv.areturn(overriden.getReturnType());
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generatedMethod(JetExpression bodyExpressions,
|
||||
Method jvmSignature,
|
||||
ClassContext context,
|
||||
FunctionDescriptor functionDescriptor)
|
||||
{
|
||||
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
|
||||
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
|
||||
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO.
|
||||
|
||||
OwnerKind kind = context.getContextKind();
|
||||
|
||||
boolean isStatic = kind == OwnerKind.NAMESPACE;
|
||||
if (isStatic) flags |= Opcodes.ACC_STATIC;
|
||||
|
||||
boolean isAbstract = kind == OwnerKind.INTERFACE || bodyExpressions == null;
|
||||
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
|
||||
|
||||
if (isAbstract && (kind == OwnerKind.IMPLEMENTATION )) {
|
||||
return;
|
||||
}
|
||||
|
||||
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
|
||||
if (kind != OwnerKind.INTERFACE) {
|
||||
mv.visitCode();
|
||||
FrameMap frameMap = context.prepareFrame();
|
||||
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
|
||||
|
||||
Type[] argTypes = jvmSignature.getArgumentTypes();
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
frameMap.enter(parameter, argTypes[i].getSize());
|
||||
}
|
||||
|
||||
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
|
||||
int slot = frameMap.enterTemp();
|
||||
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
|
||||
}
|
||||
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
Type argType = argTypes[i];
|
||||
iv.load(i + 1, argType);
|
||||
}
|
||||
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
iv.areturn(jvmSignature.getReturnType());
|
||||
}
|
||||
else if (!isAbstract) {
|
||||
codegen.returnExpression(bodyExpressions);
|
||||
}
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
|
||||
Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors();
|
||||
if(overriddenFunctions.size() > 0) {
|
||||
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
|
||||
// TODO should we check params here as well?
|
||||
if(!TypeUtils.equalClasses(overriddenFunction.getOriginal().getReturnType(), functionDescriptor.getReturnType())) {
|
||||
generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GeneratedAnonymousClassDescriptor {
|
||||
private final String classname;
|
||||
private Method constructor;
|
||||
private final boolean captureThis;
|
||||
private List<StackValue> args = new ArrayList<StackValue>();
|
||||
|
||||
public GeneratedAnonymousClassDescriptor(String classname, Method constructor, boolean captureThis) {
|
||||
this.classname = classname;
|
||||
this.constructor = constructor;
|
||||
this.captureThis = captureThis;
|
||||
}
|
||||
|
||||
public String getClassname() {
|
||||
return classname;
|
||||
}
|
||||
|
||||
public Method getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public void addArg(StackValue local) {
|
||||
args.add(local);
|
||||
}
|
||||
|
||||
public List<StackValue> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public boolean isCaptureThis() {
|
||||
return captureThis;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.jet.lang.ErrorHandler;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
public class GenerationState {
|
||||
private final ClassFileFactory factory;
|
||||
private final Project project;
|
||||
|
||||
private JetTypeMapper typeMapper;
|
||||
private final Stack<BindingContext> bindingContexts = new Stack<BindingContext>();
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final IntrinsicMethods intrinsics;
|
||||
|
||||
public GenerationState(Project project, boolean text) {
|
||||
this.project = project;
|
||||
this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
||||
this.factory = new ClassFileFactory(project, text, this);
|
||||
this.intrinsics = new IntrinsicMethods(project, standardLibrary);
|
||||
}
|
||||
|
||||
public ClassFileFactory getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public JetTypeMapper getTypeMapper() {
|
||||
return typeMapper;
|
||||
}
|
||||
|
||||
public BindingContext getBindingContext() {
|
||||
return bindingContexts.peek();
|
||||
}
|
||||
|
||||
public JetStandardLibrary getStandardLibrary() {
|
||||
return standardLibrary;
|
||||
}
|
||||
|
||||
public IntrinsicMethods getIntrinsics() {
|
||||
return intrinsics;
|
||||
}
|
||||
|
||||
public ClassVisitor forClassInterface(ClassDescriptor aClass) {
|
||||
return factory.newVisitor(JetTypeMapper.jvmNameForInterface(aClass) + ".class");
|
||||
}
|
||||
|
||||
public ClassCodegen forClass() {
|
||||
return new ClassCodegen(this);
|
||||
}
|
||||
|
||||
public ClassVisitor forClassImplementation(ClassDescriptor aClass) {
|
||||
return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.IMPLEMENTATION) + ".class");
|
||||
}
|
||||
|
||||
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
|
||||
return factory.newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class");
|
||||
}
|
||||
|
||||
public Pair<String, ClassVisitor> forAnonymousSubclass(JetExpression expression) {
|
||||
String className = typeMapper.classNameForAnonymousClass(expression);
|
||||
ClassVisitor visitor = factory.forAnonymousSubclass(className);
|
||||
return Pair.create(className, visitor);
|
||||
}
|
||||
|
||||
public NamespaceCodegen forNamespace(JetNamespace namespace) {
|
||||
return factory.forNamespace(namespace);
|
||||
}
|
||||
|
||||
public void compile(JetFile psiFile) {
|
||||
final JetNamespace namespace = psiFile.getRootNamespace();
|
||||
NamespaceCodegen codegen = forNamespace(namespace);
|
||||
final BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY);
|
||||
bindingContexts.push(bindingContext);
|
||||
typeMapper = new JetTypeMapper(standardLibrary, bindingContext);
|
||||
try {
|
||||
ErrorHandler.applyHandler(ErrorHandler.THROW_EXCEPTION, bindingContext);
|
||||
codegen.generate(namespace);
|
||||
}
|
||||
finally {
|
||||
bindingContexts.pop();
|
||||
typeMapper = null;
|
||||
}
|
||||
}
|
||||
|
||||
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
|
||||
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration());
|
||||
|
||||
final ClassContext objectContext = classContext.intoClass(getBindingContext().get(BindingContext.CLASS, literal.getObjectDeclaration()), OwnerKind.IMPLEMENTATION);
|
||||
|
||||
new ImplementationBodyCodegen(literal.getObjectDeclaration(), objectContext, nameAndVisitor.getSecond(), this).generate();
|
||||
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V"), false);
|
||||
}
|
||||
|
||||
public static void prepareAnonymousClasses(JetElement aClass, final JetTypeMapper typeMapper) {
|
||||
aClass.acceptChildren(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
super.visitJetElement(element);
|
||||
element.acceptChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
|
||||
typeMapper.classNameForAnonymousClass(expression.getObjectDeclaration());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.Variance;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
*/
|
||||
public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
public ImplementationBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
||||
super(aClass, context, v, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateDeclaration() {
|
||||
String superClass = getSuperClass();
|
||||
|
||||
List<String> interfaces = new ArrayList<String>();
|
||||
interfaces.add("jet/JetObject");
|
||||
if (!(myClass instanceof JetObjectDeclaration)) {
|
||||
interfaces.add(JetTypeMapper.jvmNameForInterface(descriptor));
|
||||
}
|
||||
else {
|
||||
interfaces.addAll(InterfaceBodyCodegen.getSuperInterfaces(myClass, state.getBindingContext()));
|
||||
}
|
||||
|
||||
boolean isAbstract = myClass instanceof JetClass && ((JetClass) myClass).hasModifier(JetTokens.ABSTRACT_KEYWORD);
|
||||
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0),
|
||||
jvmName(),
|
||||
null,
|
||||
superClass,
|
||||
interfaces.toArray(new String[interfaces.size()])
|
||||
);
|
||||
v.visitSource(myClass.getContainingFile().getName(), null);
|
||||
}
|
||||
|
||||
private String jvmName() {
|
||||
return state.getTypeMapper().jvmName(descriptor, kind);
|
||||
}
|
||||
|
||||
protected String getSuperClass() {
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = myClass.getDelegationSpecifiers();
|
||||
|
||||
if (delegationSpecifiers.isEmpty()) return "java/lang/Object";
|
||||
|
||||
JetDelegationSpecifier first = delegationSpecifiers.get(0);
|
||||
if (first instanceof JetDelegatorToSuperClass || first instanceof JetDelegatorToSuperCall) {
|
||||
JetType superType = state.getBindingContext().get(BindingContext.TYPE, first.getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
final PsiElement declaration = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor);
|
||||
if (declaration instanceof PsiClass && ((PsiClass) declaration).isInterface()) {
|
||||
return "java/lang/Object";
|
||||
}
|
||||
return state.getTypeMapper().jvmName(superClassDescriptor, kind);
|
||||
}
|
||||
|
||||
return "java/lang/Object";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticParts() {
|
||||
generateFieldForTypeInfo();
|
||||
generateFieldForObjectInstance();
|
||||
generateFieldForClassObject();
|
||||
|
||||
try {
|
||||
generatePrimaryConstructor();
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
throw new RuntimeException("Error generating primary constructor of class " + myClass.getName() + " with kind " + kind, e);
|
||||
}
|
||||
|
||||
generateGetTypeInfo();
|
||||
}
|
||||
|
||||
private void generateFieldForTypeInfo() {
|
||||
final boolean typeInfoIsStatic = descriptor.getTypeConstructor().getParameters().size() == 0;
|
||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | (typeInfoIsStatic ? Opcodes.ACC_STATIC : 0), "$typeInfo",
|
||||
"Ljet/typeinfo/TypeInfo;", null, null);
|
||||
if (typeInfoIsStatic) {
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
@Override
|
||||
public void generate(InstructionAdapter v) {
|
||||
JetTypeMapper typeMapper = state.getTypeMapper();
|
||||
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
|
||||
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFieldForObjectInstance() {
|
||||
if (isNonLiteralObject()) {
|
||||
Type type = JetTypeMapper.jetImplementationType(descriptor);
|
||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
|
||||
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
@Override
|
||||
public void generate(InstructionAdapter v) {
|
||||
String name = jvmName();
|
||||
v.anew(Type.getObjectType(name));
|
||||
v.dup();
|
||||
v.invokespecial(name, "<init>", "()V");
|
||||
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFieldForClassObject() {
|
||||
final JetClassObject classObject = getClassObject();
|
||||
if (classObject != null) {
|
||||
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
|
||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
|
||||
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
@Override
|
||||
public void generate(InstructionAdapter v) {
|
||||
String name = state.getTypeMapper().jvmName(classObject);
|
||||
final Type classObjectType = Type.getObjectType(name);
|
||||
v.anew(classObjectType);
|
||||
v.dup();
|
||||
v.invokespecial(name, "<init>", "()V");
|
||||
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
|
||||
classObjectType.getDescriptor());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void generatePrimaryConstructor() {
|
||||
ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, myClass);
|
||||
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return;
|
||||
|
||||
Method method;
|
||||
CallableMethod callableMethod;
|
||||
if (constructorDescriptor == null) {
|
||||
method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
||||
callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.<Type>emptyList());
|
||||
}
|
||||
else {
|
||||
callableMethod = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
||||
method = callableMethod.getSignature();
|
||||
}
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO
|
||||
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
|
||||
Type[] argTypes = method.getArgumentTypes();
|
||||
List<ValueParameterDescriptor> paramDescrs = constructorDescriptor != null
|
||||
? constructorDescriptor.getValueParameters()
|
||||
: Collections.<ValueParameterDescriptor>emptyList();
|
||||
|
||||
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind);
|
||||
|
||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
|
||||
|
||||
String classname = state.getTypeMapper().jvmName(descriptor, kind);
|
||||
final Type classType = Type.getType("L" + classname + ";");
|
||||
|
||||
List<JetDelegationSpecifier> specifiers = myClass.getDelegationSpecifiers();
|
||||
|
||||
if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) {
|
||||
// TODO correct calculation of super class
|
||||
String superClass = "java/lang/Object";
|
||||
if (!specifiers.isEmpty()) {
|
||||
final JetType superType = state.getBindingContext().get(BindingContext.TYPE, specifiers.get(0).getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
if (superClassDescriptor.hasConstructors()) {
|
||||
superClass = getSuperClass();
|
||||
}
|
||||
}
|
||||
iv.load(0, Type.getType("L" + superClass + ";"));
|
||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||
}
|
||||
|
||||
final ClassDescriptor outerDescriptor = getOuterClassDescriptor();
|
||||
if (outerDescriptor != null && outerDescriptor.getKind() != ClassKind.OBJECT) {
|
||||
final Type type = JetTypeMapper.jetImplementationType(outerDescriptor);
|
||||
String interfaceDesc = type.getDescriptor();
|
||||
final String fieldName = "this$0";
|
||||
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
||||
iv.load(0, classType);
|
||||
iv.load(frameMap.getOuterThisIndex(), type);
|
||||
iv.putfield(classname, fieldName, interfaceDesc);
|
||||
}
|
||||
|
||||
HashSet<FunctionDescriptor> overridden = new HashSet<FunctionDescriptor>();
|
||||
for (JetDeclaration declaration : myClass.getDeclarations()) {
|
||||
if (declaration instanceof JetFunction) {
|
||||
overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenDescriptors());
|
||||
}
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (JetDelegationSpecifier specifier : specifiers) {
|
||||
boolean delegateOnStack = specifier instanceof JetDelegatorToSuperCall && n > 0 ||
|
||||
specifier instanceof JetDelegatorByExpressionSpecifier;
|
||||
|
||||
if (delegateOnStack) {
|
||||
iv.load(0, classType);
|
||||
}
|
||||
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
ConstructorDescriptor constructorDescriptor1 = (ConstructorDescriptor) state.getBindingContext().get(BindingContext.REFERENCE_TARGET, ((JetDelegatorToSuperCall) specifier).getCalleeExpression().getConstructorReferenceExpression());
|
||||
generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) specifier, constructorDescriptor1, n == 0, frameMap);
|
||||
}
|
||||
else if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression());
|
||||
}
|
||||
|
||||
if (delegateOnStack) {
|
||||
JetType superType = state.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
String delegateField = "$delegate_" + n;
|
||||
Type fieldType = JetTypeMapper.jetInterfaceType(superClassDescriptor);
|
||||
String fieldDesc = fieldType.getDescriptor();
|
||||
v.visitField(Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
|
||||
iv.putfield(classname, delegateField, fieldDesc);
|
||||
|
||||
JetClass superClass = (JetClass) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor);
|
||||
final ClassContext delegateContext = context.intoClass(superClassDescriptor,
|
||||
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
|
||||
JetTypeMapper.jvmNameForInterface(superClassDescriptor)));
|
||||
generateDelegates(superClass, delegateContext, overridden);
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if (frameMap.getFirstTypeParameter() > 0 && kind == OwnerKind.IMPLEMENTATION) {
|
||||
generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv);
|
||||
}
|
||||
|
||||
generateInitializers(codegen, iv);
|
||||
|
||||
int curParam = 0;
|
||||
List<JetParameter> constructorParameters = getPrimaryConstructorParameters();
|
||||
for (JetParameter parameter : constructorParameters) {
|
||||
if (parameter.getValOrVarNode() != null) {
|
||||
VariableDescriptor descriptor = paramDescrs.get(curParam);
|
||||
Type type = state.getTypeMapper().mapType(descriptor.getOutType());
|
||||
iv.load(0, classType);
|
||||
iv.load(frameMap.getIndex(descriptor), type);
|
||||
iv.putfield(classname, descriptor.getName(), type.getDescriptor());
|
||||
}
|
||||
curParam++;
|
||||
}
|
||||
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
|
||||
return outerDescriptor instanceof ClassDescriptor ? (ClassDescriptor) outerDescriptor : null;
|
||||
}
|
||||
|
||||
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall,
|
||||
ConstructorDescriptor constructorDescriptor, boolean isJavaSuperclass,
|
||||
ConstructorFrameMap frameMap) {
|
||||
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
|
||||
PsiElement declaration = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDecl);
|
||||
Type type;
|
||||
if (declaration instanceof PsiClass) {
|
||||
type = JetTypeMapper.psiClassType((PsiClass) declaration);
|
||||
}
|
||||
else {
|
||||
type = JetTypeMapper.jetImplementationType(classDecl);
|
||||
}
|
||||
|
||||
if (isJavaSuperclass) {
|
||||
iv.load(0, type);
|
||||
}
|
||||
else {
|
||||
iv.anew(type);
|
||||
iv.dup();
|
||||
}
|
||||
|
||||
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
iv.load(frameMap.getOuterThisIndex(), state.getTypeMapper().jvmType((ClassDescriptor) descriptor.getContainingDeclaration(), OwnerKind.IMPLEMENTATION));
|
||||
}
|
||||
|
||||
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
||||
codegen.invokeMethodWithArguments(method, constructorCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
|
||||
if (declaration instanceof JetConstructor) {
|
||||
generateSecondaryConstructor((JetConstructor) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetClassObject) {
|
||||
generateClassObject((JetClassObject) declaration);
|
||||
}
|
||||
else {
|
||||
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSecondaryConstructor(JetConstructor constructor) {
|
||||
ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
|
||||
if (constructorDescriptor == null) {
|
||||
throw new UnsupportedOperationException("failed to get descriptor for secondary constructor");
|
||||
}
|
||||
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO
|
||||
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getSignature().getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
|
||||
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind);
|
||||
|
||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
|
||||
|
||||
for (JetDelegationSpecifier initializer : constructor.getInitializers()) {
|
||||
if (initializer instanceof JetDelegatorToThisCall) {
|
||||
JetDelegatorToThisCall thisCall = (JetDelegatorToThisCall) initializer;
|
||||
DeclarationDescriptor thisDescriptor = state.getBindingContext().get(BindingContext.REFERENCE_TARGET, thisCall.getThisReference());
|
||||
if (!(thisDescriptor instanceof ConstructorDescriptor)) {
|
||||
throw new UnsupportedOperationException("expected 'this' delegator to resolve to constructor");
|
||||
}
|
||||
generateDelegatorToConstructorCall(iv, codegen, thisCall, (ConstructorDescriptor) thisDescriptor, true, frameMap);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("unknown initializer type");
|
||||
}
|
||||
}
|
||||
|
||||
JetExpression bodyExpression = constructor.getBodyExpression();
|
||||
if (bodyExpression != null) {
|
||||
codegen.gen(bodyExpression, Type.VOID_TYPE);
|
||||
}
|
||||
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
protected void generateTypeInfoInitializer(int firstTypeParameter, int typeParamCount, InstructionAdapter iv) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
|
||||
iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE));
|
||||
iv.iconst(0);
|
||||
iv.iconst(typeParamCount);
|
||||
iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
|
||||
|
||||
for (int i = 0; i < typeParamCount; i++) {
|
||||
iv.dup();
|
||||
iv.iconst(i);
|
||||
iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT);
|
||||
ExpressionCodegen.genTypeInfoToProjection(iv, Variance.INVARIANT);
|
||||
iv.astore(JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
|
||||
iv.putfield(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
|
||||
protected void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) {
|
||||
for (JetDeclaration declaration : myClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
|
||||
if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||
if (initializer != null) {
|
||||
CompileTimeConstant<?> compileTimeValue = state.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
|
||||
if(compileTimeValue != null) {
|
||||
assert compileTimeValue != null;
|
||||
Object value = compileTimeValue.getValue();
|
||||
Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
|
||||
if(JetTypeMapper.isPrimitive(type)) {
|
||||
if( !propertyDescriptor.getOutType().isNullable() && value instanceof Number) {
|
||||
if(type == Type.INT_TYPE && ((Number)value).intValue() == 0)
|
||||
continue;
|
||||
if(type == Type.BYTE_TYPE && ((Number)value).byteValue() == 0)
|
||||
continue;
|
||||
if(type == Type.LONG_TYPE && ((Number)value).longValue() == 0L)
|
||||
continue;
|
||||
if(type == Type.SHORT_TYPE && ((Number)value).shortValue() == 0)
|
||||
continue;
|
||||
if(type == Type.DOUBLE_TYPE && ((Number)value).doubleValue() == 0d)
|
||||
continue;
|
||||
if(type == Type.FLOAT_TYPE && ((Number)value).byteValue() == 0f)
|
||||
continue;
|
||||
}
|
||||
if(type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean)value))
|
||||
continue;
|
||||
if(type == Type.CHAR_TYPE && value instanceof Character && ((Character)value) == 0)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if(value == null)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
Type type = codegen.expressionType(initializer);
|
||||
if(propertyDescriptor.getOutType().isNullable())
|
||||
type = state.getTypeMapper().boxType(type);
|
||||
codegen.gen(initializer, type);
|
||||
codegen.intermediateValueForProperty(propertyDescriptor, false, false).store(iv);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof JetClassInitializer) {
|
||||
codegen.gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void generateDelegates(JetClass toClass, ClassContext delegateContext, Set<FunctionDescriptor> overriden) {
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(delegateContext, v, state);
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(delegateContext, v, functionCodegen, state);
|
||||
|
||||
for (JetDeclaration declaration : toClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetFunction) {
|
||||
if (!overriden.contains(state.getBindingContext().get(BindingContext.FUNCTION, declaration))) {
|
||||
functionCodegen.gen((JetNamedFunction) declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (JetParameter p : toClass.getPrimaryConstructorParameters()) {
|
||||
if (p.getValOrVarNode() != null) {
|
||||
PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
|
||||
if (propertyDescriptor != null) {
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetClassObject getClassObject() {
|
||||
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
|
||||
}
|
||||
|
||||
private boolean isNonLiteralObject() {
|
||||
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral() &&
|
||||
!(myClass.getParent() instanceof JetClassObject);
|
||||
}
|
||||
|
||||
private void generateGetTypeInfo() {
|
||||
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC,
|
||||
"getTypeInfo",
|
||||
"()Ljet/typeinfo/TypeInfo;",
|
||||
null /* TODO */,
|
||||
null);
|
||||
mv.visitCode();
|
||||
InstructionAdapter v = new InstructionAdapter(mv);
|
||||
ExpressionCodegen.loadTypeInfo(state.getTypeMapper(), descriptor, v);
|
||||
v.areturn(JetTypeMapper.TYPE_TYPEINFO);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateClassObject(JetClassObject declaration) {
|
||||
state.forClass().generate(context, declaration.getObjectDeclaration());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
public class InstructionAdapterEx extends InstructionAdapter {
|
||||
private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
|
||||
|
||||
private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
|
||||
|
||||
private static final Method INT_VALUE = Method.getMethod("int intValue()");
|
||||
|
||||
private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
|
||||
|
||||
private static final Method LONG_VALUE = Method.getMethod("long longValue()");
|
||||
|
||||
private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
|
||||
|
||||
public InstructionAdapterEx(MethodVisitor methodVisitor) {
|
||||
super(methodVisitor);
|
||||
}
|
||||
|
||||
private static Type getBoxedType(final Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.BYTE:
|
||||
return JetTypeMapper.JL_BYTE_TYPE;
|
||||
case Type.BOOLEAN:
|
||||
return JetTypeMapper.JL_BOOLEAN_TYPE;
|
||||
case Type.SHORT:
|
||||
return JetTypeMapper.JL_SHORT_TYPE;
|
||||
case Type.CHAR:
|
||||
return JetTypeMapper.JL_CHAR_TYPE;
|
||||
case Type.INT:
|
||||
return JetTypeMapper.JL_INTEGER_TYPE;
|
||||
case Type.FLOAT:
|
||||
return JetTypeMapper.JL_FLOAT_TYPE;
|
||||
case Type.LONG:
|
||||
return JetTypeMapper.JL_LONG_TYPE;
|
||||
case Type.DOUBLE:
|
||||
return JetTypeMapper.JL_DOUBLE_TYPE;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public void valueOf(final Type type) {
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
return;
|
||||
}
|
||||
if (type == Type.VOID_TYPE) {
|
||||
aconst(null);
|
||||
} else {
|
||||
Type boxed = getBoxedType(type);
|
||||
invokestatic(boxed.getInternalName(), "valueOf", "(" + type.getDescriptor() + ")" + boxed.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
public void unbox(final Type type) {
|
||||
Type t = JetTypeMapper.JL_NUMBER_TYPE;
|
||||
Method sig = null;
|
||||
switch (type.getSort()) {
|
||||
case Type.VOID:
|
||||
return;
|
||||
case Type.CHAR:
|
||||
t = JetTypeMapper.JL_CHAR_TYPE;
|
||||
sig = CHAR_VALUE;
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
t = JetTypeMapper.JL_BOOLEAN_TYPE;
|
||||
sig = BOOLEAN_VALUE;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
sig = DOUBLE_VALUE;
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
sig = FLOAT_VALUE;
|
||||
break;
|
||||
case Type.LONG:
|
||||
sig = LONG_VALUE;
|
||||
break;
|
||||
case Type.INT:
|
||||
case Type.SHORT:
|
||||
case Type.BYTE:
|
||||
sig = INT_VALUE;
|
||||
}
|
||||
|
||||
checkcast(t);
|
||||
invokevirtual(t.getInternalName(), sig.getName(), sig.getDescriptor());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
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.ConstructorDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class InterfaceBodyCodegen extends ClassBodyCodegen {
|
||||
private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
|
||||
|
||||
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
||||
super(aClass, context, v, state);
|
||||
assert context.getContextKind() == OwnerKind.INTERFACE;
|
||||
}
|
||||
|
||||
protected void generateDeclaration() {
|
||||
Set<String> superInterfaces = getSuperInterfaces(myClass, state.getBindingContext());
|
||||
|
||||
String fqName = JetTypeMapper.jvmNameForInterface(descriptor);
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT,
|
||||
fqName,
|
||||
null,
|
||||
"java/lang/Object",
|
||||
superInterfaces.toArray(new String[superInterfaces.size()])
|
||||
);
|
||||
v.visitSource(myClass.getContainingFile().getName(), null);
|
||||
}
|
||||
|
||||
static Set<String> getSuperInterfaces(JetClassOrObject aClass, final BindingContext bindingContext) {
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = aClass.getDelegationSpecifiers();
|
||||
String superClassName = null;
|
||||
Set<String> superInterfaces = new LinkedHashSet<String>();
|
||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
||||
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
PsiElement superPsi = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor);
|
||||
|
||||
if (superPsi instanceof PsiClass) {
|
||||
PsiClass psiClass = (PsiClass) superPsi;
|
||||
String fqn = psiClass.getQualifiedName();
|
||||
if (psiClass.isInterface()) {
|
||||
superInterfaces.add(fqn.replace('.', '/'));
|
||||
}
|
||||
else {
|
||||
if (superClassName == null) {
|
||||
superClassName = fqn.replace('.', '/');
|
||||
|
||||
while (psiClass != null) {
|
||||
for (PsiClass ifs : psiClass.getInterfaces()) {
|
||||
superInterfaces.add(ifs.getQualifiedName().replace('.', '/'));
|
||||
}
|
||||
psiClass = psiClass.getSuperClass();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("Cannot determine single class to inherit from");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
superInterfaces.add(JetTypeMapper.jvmNameForInterface(superClassDescriptor));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state);
|
||||
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);
|
||||
|
||||
final List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
|
||||
if (delegationSpecifiers.size() > 1) {
|
||||
throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
|
||||
}
|
||||
|
||||
v.anew(Type.getObjectType(implClass));
|
||||
v.dup();
|
||||
|
||||
if (delegationSpecifiers.size() == 1) {
|
||||
final JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
final JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) state.getBindingContext().get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
|
||||
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
codegen.invokeMethodWithArguments(method, superCall);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
|
||||
}
|
||||
}
|
||||
else {
|
||||
v.invokespecial(implClass, "<init>", "()V");
|
||||
}
|
||||
v.putstatic(intfClass, enumConstant.getName(), "L" + intfClass + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,687 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import jet.JetObject;
|
||||
import jet.typeinfo.TypeInfo;
|
||||
import jet.typeinfo.TypeInfoProjection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class JetTypeMapper {
|
||||
public static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object");
|
||||
public static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class);
|
||||
public static final Type TYPE_TYPEINFOPROJECTION = Type.getType(TypeInfoProjection.class);
|
||||
public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class);
|
||||
public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing");
|
||||
public static final Type JL_INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
|
||||
public static final Type JL_LONG_TYPE = Type.getObjectType("java/lang/Long");
|
||||
public static final Type JL_SHORT_TYPE = Type.getObjectType("java/lang/Short");
|
||||
public static final Type JL_BYTE_TYPE = Type.getObjectType("java/lang/Byte");
|
||||
public static final Type JL_CHAR_TYPE = Type.getObjectType("java/lang/Character");
|
||||
public static final Type JL_FLOAT_TYPE = Type.getObjectType("java/lang/Float");
|
||||
public static final Type JL_DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
|
||||
public static final Type JL_BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
|
||||
public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number");
|
||||
public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder");
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final BindingContext bindingContext;
|
||||
private final Map<JetExpression, String> classNamesForAnonymousClasses = new HashMap<JetExpression, String>();
|
||||
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
|
||||
|
||||
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
|
||||
this.standardLibrary = standardLibrary;
|
||||
this.bindingContext = bindingContext;
|
||||
}
|
||||
|
||||
static String jvmName(PsiClass psiClass) {
|
||||
final String qName = psiClass.getQualifiedName();
|
||||
if (qName == null) {
|
||||
throw new UnsupportedOperationException("can't evaluate JVM name for anonymous class " + psiClass);
|
||||
}
|
||||
return qName.replace(".", "/");
|
||||
}
|
||||
|
||||
public static boolean isIntPrimitive(Type type) {
|
||||
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
|
||||
}
|
||||
|
||||
public static boolean isPrimitive(Type type) {
|
||||
return type == Type.INT_TYPE
|
||||
|| type == Type.SHORT_TYPE
|
||||
|| type == Type.BYTE_TYPE
|
||||
|| type == Type.CHAR_TYPE
|
||||
|| type == Type.SHORT_TYPE
|
||||
|| type == Type.FLOAT_TYPE
|
||||
|| type == Type.DOUBLE_TYPE
|
||||
|| type == Type.LONG_TYPE
|
||||
|| type == Type.BOOLEAN_TYPE
|
||||
|| type == Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
static Type psiTypeToAsm(PsiType type) {
|
||||
if(type instanceof PsiArrayType) {
|
||||
PsiArrayType psiArrayType = (PsiArrayType) type;
|
||||
return Type.getType("[" + psiTypeToAsm(psiArrayType.getComponentType()).getDescriptor());
|
||||
}
|
||||
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
if (type == PsiType.VOID) {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
if (type == PsiType.INT) {
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
if (type == PsiType.LONG) {
|
||||
return Type.LONG_TYPE;
|
||||
}
|
||||
if (type == PsiType.BOOLEAN) {
|
||||
return Type.BOOLEAN_TYPE;
|
||||
}
|
||||
if (type == PsiType.BYTE) {
|
||||
return Type.BYTE_TYPE;
|
||||
}
|
||||
if (type == PsiType.SHORT) {
|
||||
return Type.SHORT_TYPE;
|
||||
}
|
||||
if (type == PsiType.CHAR) {
|
||||
return Type.CHAR_TYPE;
|
||||
}
|
||||
if (type == PsiType.FLOAT) {
|
||||
return Type.FLOAT_TYPE;
|
||||
}
|
||||
if (type == PsiType.DOUBLE) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
}
|
||||
}
|
||||
if (type instanceof PsiClassType) {
|
||||
PsiClass psiClass = ((PsiClassType) type).resolve();
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
final PsiClassType[] extendsListTypes = psiClass.getExtendsListTypes();
|
||||
if (extendsListTypes.length > 0) {
|
||||
throw new UnsupportedOperationException("should return common supertype");
|
||||
}
|
||||
return TYPE_OBJECT;
|
||||
}
|
||||
if (psiClass == null) {
|
||||
throw new UnsupportedOperationException("unresolved PsiClassType: " + type);
|
||||
}
|
||||
return psiClassType(psiClass);
|
||||
}
|
||||
throw new UnsupportedOperationException("don't know how to map type " + type + " to ASM");
|
||||
}
|
||||
|
||||
static Method getMethodDescriptor(PsiMethod method) {
|
||||
Type returnType = method.isConstructor() ? Type.VOID_TYPE : psiTypeToAsm(method.getReturnType());
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
Type[] parameterTypes = new Type[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameterTypes[i] = psiTypeToAsm(parameters[i].getType());
|
||||
}
|
||||
return new Method(method.isConstructor() ? "<init>" : method.getName(), Type.getMethodDescriptor(returnType, parameterTypes));
|
||||
}
|
||||
|
||||
static CallableMethod mapToCallableMethod(PsiMethod method) {
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
String owner = jvmName(containingClass);
|
||||
Method signature = getMethodDescriptor(method);
|
||||
List<Type> valueParameterTypes = new ArrayList<Type>();
|
||||
Collections.addAll(valueParameterTypes, signature.getArgumentTypes());
|
||||
int opcode;
|
||||
boolean needsReceiver = false;
|
||||
boolean ownerFromCall = false;
|
||||
if (method.isConstructor()) {
|
||||
opcode = Opcodes.INVOKESPECIAL;
|
||||
}
|
||||
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
opcode = Opcodes.INVOKESTATIC;
|
||||
}
|
||||
else {
|
||||
needsReceiver = true;
|
||||
if (containingClass.isInterface()) {
|
||||
opcode = Opcodes.INVOKEINTERFACE;
|
||||
}
|
||||
else {
|
||||
opcode = Opcodes.INVOKEVIRTUAL;
|
||||
}
|
||||
ownerFromCall = true;
|
||||
}
|
||||
final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes);
|
||||
if (needsReceiver) {
|
||||
result.setNeedsReceiver(null);
|
||||
}
|
||||
result.setOwnerFromCall(ownerFromCall);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String jvmName(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass);
|
||||
if (declaration instanceof PsiClass) {
|
||||
return jvmName((PsiClass) declaration);
|
||||
}
|
||||
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
|
||||
final PsiElement parent = declaration.getParent();
|
||||
if (parent instanceof JetClassObject) {
|
||||
JetClass containingClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
|
||||
final ClassDescriptor containingClassDescriptor = bindingContext.get(BindingContext.CLASS, containingClass);
|
||||
return jvmName(containingClassDescriptor, OwnerKind.INTERFACE) + "$$ClassObj";
|
||||
}
|
||||
String className = classNamesForAnonymousClasses.get(declaration);
|
||||
if (className == null) {
|
||||
throw new UnsupportedOperationException("Unexpected forward reference to anonymous class " + declaration);
|
||||
}
|
||||
return className;
|
||||
}
|
||||
return jetJvmName(jetClass, kind);
|
||||
}
|
||||
|
||||
public String jvmName(JetClassObject classObject) {
|
||||
final ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
|
||||
return jvmName(descriptor, OwnerKind.IMPLEMENTATION);
|
||||
}
|
||||
|
||||
public boolean isInterface(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass);
|
||||
if (declaration instanceof JetObjectDeclaration) {
|
||||
return false;
|
||||
}
|
||||
return kind == OwnerKind.INTERFACE;
|
||||
}
|
||||
|
||||
private static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
if (jetClass.getKind() == ClassKind.OBJECT) {
|
||||
return jvmNameForImplementation(jetClass);
|
||||
}
|
||||
if (kind == OwnerKind.INTERFACE) {
|
||||
return jvmNameForInterface(jetClass);
|
||||
}
|
||||
else if (kind == OwnerKind.IMPLEMENTATION) {
|
||||
return jvmNameForImplementation(jetClass);
|
||||
}
|
||||
else {
|
||||
assert false : "Unsuitable kind";
|
||||
return "java/lang/Object";
|
||||
}
|
||||
}
|
||||
|
||||
public Type jvmType(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
if (jetClass == standardLibrary.getString()) {
|
||||
return Type.getType(String.class);
|
||||
}
|
||||
return Type.getType("L" + jvmName(jetClass, kind) + ";");
|
||||
}
|
||||
|
||||
static Type psiClassType(PsiClass psiClass) {
|
||||
return Type.getType("L" + jvmName(psiClass) + ";");
|
||||
}
|
||||
|
||||
static Type jetInterfaceType(ClassDescriptor classDescriptor) {
|
||||
return Type.getType("L" + jvmNameForInterface(classDescriptor) + ";");
|
||||
}
|
||||
|
||||
static Type jetImplementationType(ClassDescriptor classDescriptor) {
|
||||
return Type.getType("L" + jvmNameForImplementation(classDescriptor) + ";");
|
||||
}
|
||||
|
||||
static Type jetDelegatingImplementationType(ClassDescriptor classDescriptor) {
|
||||
return Type.getType("L" + jvmNameForDelegatingImplementation(classDescriptor) + ";");
|
||||
}
|
||||
|
||||
public static String jvmName(JetNamespace namespace) {
|
||||
return NamespaceCodegen.getJVMClassName(namespace.getFQName());
|
||||
}
|
||||
|
||||
static String jvmName(NamespaceDescriptor namespace) {
|
||||
return NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(namespace));
|
||||
}
|
||||
|
||||
public static String jvmNameForInterface(ClassDescriptor descriptor) {
|
||||
return DescriptorRenderer.getFQName(descriptor).replace('.', '/');
|
||||
}
|
||||
|
||||
public static String jvmNameForImplementation(ClassDescriptor descriptor) {
|
||||
return jvmNameForInterface(descriptor) + "$$Impl";
|
||||
}
|
||||
|
||||
public static String jvmNameForDelegatingImplementation(ClassDescriptor descriptor) {
|
||||
return jvmNameForInterface(descriptor) + "$$DImpl";
|
||||
}
|
||||
|
||||
public String getOwner(DeclarationDescriptor descriptor, OwnerKind kind) {
|
||||
String owner;
|
||||
if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptorImpl) {
|
||||
owner = jvmName((NamespaceDescriptor) descriptor.getContainingDeclaration());
|
||||
}
|
||||
else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
kind = OwnerKind.INTERFACE;
|
||||
}
|
||||
else if (classDescriptor.getKind() == ClassKind.OBJECT) {
|
||||
kind = OwnerKind.IMPLEMENTATION;
|
||||
}
|
||||
owner = jvmName(classDescriptor, kind);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate owner for parent " + descriptor.getContainingDeclaration());
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
||||
@NotNull public Type mapReturnType(@NotNull final JetType jetType, OwnerKind kind) {
|
||||
if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
return mapType(jetType, kind);
|
||||
}
|
||||
|
||||
@NotNull public Type mapReturnType(final JetType jetType) {
|
||||
return mapReturnType(jetType, OwnerKind.INTERFACE);
|
||||
}
|
||||
|
||||
@NotNull public Type mapType(final JetType jetType) {
|
||||
return mapType(jetType, OwnerKind.INTERFACE);
|
||||
}
|
||||
|
||||
@NotNull public Type mapType(@NotNull final JetType jetType, OwnerKind kind) {
|
||||
if (jetType.equals(JetStandardClasses.getNothingType()) || jetType.equals(JetStandardClasses.getNullableNothingType())) {
|
||||
return TYPE_NOTHING;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getIntType())) {
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableIntType())) {
|
||||
return JL_INTEGER_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getLongType())) {
|
||||
return Type.LONG_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableLongType())) {
|
||||
return JL_LONG_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getShortType())) {
|
||||
return Type.SHORT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableShortType())) {
|
||||
return JL_SHORT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getByteType())) {
|
||||
return Type.BYTE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableByteType())) {
|
||||
return JL_BYTE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getCharType())) {
|
||||
return Type.CHAR_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableCharType())) {
|
||||
return JL_CHAR_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getFloatType())) {
|
||||
return Type.FLOAT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableFloatType())) {
|
||||
return JL_FLOAT_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getDoubleType())) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableDoubleType())) {
|
||||
return JL_DOUBLE_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getBooleanType())) {
|
||||
return Type.BOOLEAN_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableBooleanType())) {
|
||||
return JL_BOOLEAN_TYPE;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
|
||||
return Type.getType(String.class);
|
||||
}
|
||||
|
||||
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if (standardLibrary.getArray().equals(descriptor)) {
|
||||
if (jetType.getArguments().size() != 1) {
|
||||
throw new UnsupportedOperationException("arrays must have one type argument");
|
||||
}
|
||||
TypeProjection memberType = jetType.getArguments().get(0);
|
||||
Type elementType = mapType(memberType.getType());
|
||||
return Type.getType("[" + elementType.getDescriptor());
|
||||
}
|
||||
if (JetStandardClasses.getAny().equals(descriptor)) {
|
||||
return Type.getType(Object.class);
|
||||
}
|
||||
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return Type.getObjectType(jvmName((ClassDescriptor) descriptor, kind));
|
||||
}
|
||||
|
||||
if (descriptor instanceof TypeParameterDescriptor) {
|
||||
return mapType(((TypeParameterDescriptor) descriptor).getBoundsAsType(), kind);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown type " + jetType);
|
||||
}
|
||||
|
||||
public Type boxType(Type asmType) {
|
||||
switch (asmType.getSort()) {
|
||||
case Type.VOID:
|
||||
return Type.VOID_TYPE;
|
||||
case Type.BYTE:
|
||||
return JL_BYTE_TYPE;
|
||||
case Type.BOOLEAN:
|
||||
return JL_BOOLEAN_TYPE;
|
||||
case Type.SHORT:
|
||||
return JL_SHORT_TYPE;
|
||||
case Type.CHAR:
|
||||
return JL_CHAR_TYPE;
|
||||
case Type.INT:
|
||||
return JL_INTEGER_TYPE;
|
||||
case Type.FLOAT:
|
||||
return JL_FLOAT_TYPE;
|
||||
case Type.LONG:
|
||||
return JL_LONG_TYPE;
|
||||
case Type.DOUBLE:
|
||||
return JL_DOUBLE_TYPE;
|
||||
}
|
||||
|
||||
return asmType;
|
||||
}
|
||||
|
||||
|
||||
private static Type getBoxedType(final Type type) {
|
||||
switch (type.getSort()) {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private Method mapSignature(JetNamedFunction f, List<Type> valueParameterTypes) {
|
||||
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
|
||||
final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef);
|
||||
final List<JetParameter> parameters = f.getValueParameters();
|
||||
List<Type> parameterTypes = new ArrayList<Type>();
|
||||
if (receiverType != null) {
|
||||
parameterTypes.add(mapType(receiverType));
|
||||
}
|
||||
for (JetParameter parameter : parameters) {
|
||||
final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference()));
|
||||
valueParameterTypes.add(type);
|
||||
parameterTypes.add(type);
|
||||
}
|
||||
for (JetTypeParameter p: f.getTypeParameters()) {
|
||||
parameterTypes.add(TYPE_TYPEINFO);
|
||||
}
|
||||
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
|
||||
Type returnType;
|
||||
if (returnTypeRef == null) {
|
||||
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
|
||||
final JetType type = functionDescriptor.getReturnType();
|
||||
returnType = mapReturnType(type);
|
||||
}
|
||||
else {
|
||||
returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef));
|
||||
}
|
||||
return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
|
||||
public CallableMethod mapToCallableMethod(PsiNamedElement declaration) {
|
||||
if (declaration instanceof PsiMethod) {
|
||||
return mapToCallableMethod((PsiMethod) declaration);
|
||||
}
|
||||
if (!(declaration instanceof JetNamedFunction)) {
|
||||
throw new UnsupportedOperationException("unknown declaration type " + declaration);
|
||||
}
|
||||
JetNamedFunction f = (JetNamedFunction) declaration;
|
||||
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
|
||||
final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration();
|
||||
final List<Type> valueParameterTypes = new ArrayList<Type>();
|
||||
Method descriptor = mapSignature(f, valueParameterTypes);
|
||||
String owner;
|
||||
int invokeOpcode;
|
||||
boolean needsReceiver;
|
||||
ClassDescriptor receiverClass = null;
|
||||
if (functionParent instanceof NamespaceDescriptor) {
|
||||
owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
|
||||
invokeOpcode = Opcodes.INVOKESTATIC;
|
||||
needsReceiver = f.getReceiverTypeRef() != null;
|
||||
}
|
||||
else if (functionParent instanceof ClassDescriptor) {
|
||||
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
|
||||
owner = jvmName(containingClass, OwnerKind.INTERFACE);
|
||||
invokeOpcode = isInterface(containingClass, OwnerKind.INTERFACE)
|
||||
? Opcodes.INVOKEINTERFACE
|
||||
: Opcodes.INVOKEVIRTUAL;
|
||||
needsReceiver = true;
|
||||
receiverClass = containingClass;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("unknown function parent");
|
||||
}
|
||||
|
||||
final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes);
|
||||
result.setAcceptsTypeArguments(true);
|
||||
if (needsReceiver) {
|
||||
result.setNeedsReceiver(receiverClass);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Method mapSignature(String name, FunctionDescriptor f) {
|
||||
final JetType receiverType = f.getReceiverType();
|
||||
final List<ValueParameterDescriptor> parameters = f.getValueParameters();
|
||||
List<Type> parameterTypes = new ArrayList<Type>();
|
||||
if (receiverType != null) {
|
||||
parameterTypes.add(mapType(receiverType));
|
||||
}
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
parameterTypes.add(mapType(parameter.getOutType()));
|
||||
}
|
||||
Type returnType = mapReturnType(f.getReturnType());
|
||||
return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
|
||||
public String genericSignature(FunctionDescriptor f) {
|
||||
StringBuffer answer = new StringBuffer();
|
||||
final List<TypeParameterDescriptor> typeParameters = f.getTypeParameters();
|
||||
if (!typeParameters.isEmpty()) {
|
||||
answer.append('<');
|
||||
for (TypeParameterDescriptor p : typeParameters) {
|
||||
appendTypeParameterSignature(answer, p);
|
||||
}
|
||||
answer.append('>');
|
||||
}
|
||||
|
||||
answer.append('(');
|
||||
for (ValueParameterDescriptor p : f.getValueParameters()) {
|
||||
appendType(answer, p.getOutType());
|
||||
}
|
||||
answer.append(')');
|
||||
|
||||
appendType(answer, f.getReturnType());
|
||||
|
||||
return answer.toString();
|
||||
}
|
||||
|
||||
private void appendType(StringBuffer answer, JetType type) {
|
||||
answer.append(mapType(type).getDescriptor()); // TODO: type parameter references!
|
||||
}
|
||||
|
||||
private void appendTypeParameterSignature(StringBuffer answer, TypeParameterDescriptor p) {
|
||||
answer.append(p.getName()); // TODO: BOUND!
|
||||
}
|
||||
|
||||
public Method mapGetterSignature(PropertyDescriptor descriptor) {
|
||||
Type returnType = mapType(descriptor.getOutType());
|
||||
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]);
|
||||
}
|
||||
|
||||
public Method mapSetterSignature(PropertyDescriptor descriptor) {
|
||||
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 });
|
||||
}
|
||||
|
||||
private Method mapConstructorSignature(ConstructorDescriptor descriptor, OwnerKind kind, List<Type> valueParameterTypes) {
|
||||
List<ValueParameterDescriptor> parameters = descriptor.getOriginal().getValueParameters();
|
||||
List<Type> parameterTypes = new ArrayList<Type>();
|
||||
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
final DeclarationDescriptor outerDescriptor = classDescriptor.getContainingDeclaration();
|
||||
if (outerDescriptor instanceof ClassDescriptor) {
|
||||
parameterTypes.add(jvmType((ClassDescriptor) outerDescriptor, OwnerKind.IMPLEMENTATION));
|
||||
}
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
final Type type = mapType(parameter.getOutType());
|
||||
parameterTypes.add(type);
|
||||
valueParameterTypes.add(type);
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = classDescriptor.getTypeConstructor().getParameters();
|
||||
for (TypeParameterDescriptor typeParameter : typeParameters) {
|
||||
parameterTypes.add(TYPE_TYPEINFO);
|
||||
}
|
||||
|
||||
return new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
|
||||
public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind) {
|
||||
List<Type> valueParameterTypes = new ArrayList<Type>();
|
||||
final Method method = mapConstructorSignature(descriptor, kind, valueParameterTypes);
|
||||
String owner = jvmName(descriptor.getContainingDeclaration(), kind);
|
||||
final CallableMethod result = new CallableMethod(owner, method, Opcodes.INVOKESPECIAL, valueParameterTypes);
|
||||
result.setAcceptsTypeArguments(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
|
||||
int flags = 0;
|
||||
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||
flags |= Opcodes.ACC_PUBLIC;
|
||||
}
|
||||
else if (p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
flags |= Opcodes.ACC_PRIVATE;
|
||||
}
|
||||
else {
|
||||
flags |= defaultFlags;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
String classNameForAnonymousClass(JetExpression expression) {
|
||||
String name = classNamesForAnonymousClasses.get(expression);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
|
||||
JetNamedDeclaration container = PsiTreeUtil.getParentOfType(expression, JetNamespace.class, JetClass.class, JetObjectDeclaration.class);
|
||||
|
||||
String baseName;
|
||||
if (container instanceof JetNamespace) {
|
||||
baseName = NamespaceCodegen.getJVMClassName(((JetNamespace) container).getFQName());
|
||||
}
|
||||
else {
|
||||
ClassDescriptor aClass = bindingContext.get(BindingContext.CLASS, (JetClassOrObject) container);
|
||||
baseName = JetTypeMapper.jvmNameForInterface(aClass);
|
||||
}
|
||||
|
||||
Integer count = anonymousSubclassesCount.get(baseName);
|
||||
if (count == null) count = 0;
|
||||
|
||||
anonymousSubclassesCount.put(baseName, count + 1);
|
||||
|
||||
final String className = baseName + "$" + (count + 1);
|
||||
classNamesForAnonymousClasses.put(expression, className);
|
||||
return className;
|
||||
}
|
||||
|
||||
public Collection<String> allJvmNames(JetClassOrObject jetClass) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, jetClass);
|
||||
if (classDescriptor != null) {
|
||||
result.add(jvmName(classDescriptor, OwnerKind.INTERFACE));
|
||||
result.add(jvmName(classDescriptor, OwnerKind.IMPLEMENTATION));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String isKnownTypeInfo(JetType jetType) {
|
||||
if (jetType.equals(standardLibrary.getIntType())) {
|
||||
return "INT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableIntType())) {
|
||||
return "NULLABLE_INT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getLongType())) {
|
||||
return "LONG_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableLongType())) {
|
||||
return "NULLABLE_LONG_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getShortType())) {
|
||||
return "SHORT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableShortType())) {
|
||||
return "NULLABLE_SHORT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getByteType())) {
|
||||
return "BYTE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableByteType())) {
|
||||
return "NULLABLE_BYTE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getCharType())) {
|
||||
return "CHAR_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableCharType())) {
|
||||
return "NULLABLE_CHAR_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getFloatType())) {
|
||||
return "FLOAT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableFloatType())) {
|
||||
return "NULLABLE_FLOAT_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getDoubleType())) {
|
||||
return "DOUBLE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableDoubleType())) {
|
||||
return "NULLABLE_DOUBLE_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getBooleanType())) {
|
||||
return "BOOLEAN_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableBooleanType())) {
|
||||
return "NULLABLE_BOOLEAN_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getStringType())) {
|
||||
return "STRING_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableStringType())) {
|
||||
return "NULLABLE_STRING_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getTuple0Type())) {
|
||||
return "TUPLE0_TYPE_INFO";
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getNullableTuple0Type())) {
|
||||
return "NULLABLE_TUPLE0_TYPE_INFO";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class MethodCodeGen {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class NamespaceCodegen {
|
||||
private final ClassVisitor v;
|
||||
private final GenerationState state;
|
||||
|
||||
public NamespaceCodegen(ClassVisitor v, String fqName, GenerationState state, PsiFile sourceFile) {
|
||||
this.v = v;
|
||||
this.state = state;
|
||||
|
||||
v.visit(V1_6,
|
||||
ACC_PUBLIC,
|
||||
getJVMClassName(fqName),
|
||||
null,
|
||||
//"jet/lang/Namespace",
|
||||
"java/lang/Object",
|
||||
new String[0]
|
||||
);
|
||||
// TODO figure something out for a namespace that spans multiple files
|
||||
v.visitSource(sourceFile.getName(), null);
|
||||
}
|
||||
|
||||
public void generate(JetNamespace namespace) {
|
||||
final ClassContext context = ClassContext.STATIC.intoNamespace(state.getBindingContext().get(BindingContext.NAMESPACE, namespace));
|
||||
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
|
||||
final ClassCodegen classCodegen = state.forClass();
|
||||
|
||||
GenerationState.prepareAnonymousClasses(namespace, state.getTypeMapper());
|
||||
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetNamedFunction) {
|
||||
try {
|
||||
functionCodegen.gen((JetNamedFunction) declaration);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to generate function " + declaration.getName(), e);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof JetClassOrObject) {
|
||||
classCodegen.generate(context, (JetClassOrObject) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetNamespace) {
|
||||
JetNamespace childNamespace = (JetNamespace) declaration;
|
||||
state.forNamespace(childNamespace).generate(childNamespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNonConstantPropertyInitializers(namespace, context)) {
|
||||
generateStaticInitializers(namespace, context);
|
||||
}
|
||||
|
||||
generateTypeInfoFields(namespace, context);
|
||||
}
|
||||
|
||||
private void generateStaticInitializers(JetNamespace namespace, ClassContext context) {
|
||||
MethodVisitor mv = v.visitMethod(ACC_PUBLIC | ACC_STATIC,
|
||||
"<clinit>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
FrameMap frameMap = new FrameMap();
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, ClassContext.STATIC, state);
|
||||
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
||||
final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, (JetProperty) declaration);
|
||||
codegen.genToJVMStack(initializer);
|
||||
codegen.intermediateValueForProperty(descriptor, true, false).store(new InstructionAdapter(mv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateTypeInfoFields(JetNamespace namespace, ClassContext context) {
|
||||
if(context.typeInfoConstants != null) {
|
||||
String jvmClassName = getJVMClassName(namespace.getName());
|
||||
for(Map.Entry<JetType,Integer> e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.<JetType,Integer>emptyMap()).entrySet()) {
|
||||
String fieldName = "$typeInfoCache$" + e.getValue();
|
||||
v.visitField(ACC_PRIVATE|ACC_STATIC|ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null);
|
||||
|
||||
MethodVisitor mmv = v.visitMethod(ACC_PUBLIC|ACC_STATIC|ACC_SYNTHETIC, "$getCachedTypeInfo$" + e.getValue(), "()Ljet/typeinfo/TypeInfo;", null, null);
|
||||
InstructionAdapterEx v = new InstructionAdapterEx(mmv);
|
||||
v.visitFieldInsn(GETSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
|
||||
v.visitInsn(DUP);
|
||||
Label end = new Label();
|
||||
v.visitJumpInsn(IFNONNULL, end);
|
||||
|
||||
v.pop();
|
||||
generateTypeInfo(context, v, e.getKey(), state.getTypeMapper(), e.getKey());
|
||||
v.dup();
|
||||
|
||||
v.visitFieldInsn(PUTSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;");
|
||||
v.visitLabel(end);
|
||||
v.visitInsn(ARETURN);
|
||||
v.visitMaxs(0, 0);
|
||||
v.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateTypeInfo(ClassContext context, InstructionAdapterEx v, JetType jetType, JetTypeMapper typeMapper, JetType root) {
|
||||
String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
|
||||
if(knownTypeInfo != null) {
|
||||
v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) {
|
||||
// TODO: we need some better checks here
|
||||
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasUnsubstituted = TypeUtils.hasUnsubstitutedTypeParameters(jetType);
|
||||
if(!jetType.equals(root) && !hasUnsubstituted) {
|
||||
int typeInfoConstantIndex = context.getTypeInfoConstantIndex(jetType);
|
||||
v.invokestatic(context.getNamespaceClassName(), "$getCachedTypeInfo$" + typeInfoConstantIndex, "()Ljet/typeinfo/TypeInfo;");
|
||||
return;
|
||||
}
|
||||
|
||||
final Type jvmType = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
|
||||
|
||||
v.aconst(jvmType);
|
||||
v.iconst(jetType.isNullable() ? 1 : 0);
|
||||
List<TypeProjection> arguments = jetType.getArguments();
|
||||
if (arguments.size() > 0) {
|
||||
v.iconst(arguments.size());
|
||||
v.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
|
||||
|
||||
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
|
||||
TypeProjection argument = arguments.get(i);
|
||||
v.dup();
|
||||
v.iconst(i);
|
||||
generateTypeInfo(context, v, argument.getType(), typeMapper, root);
|
||||
ExpressionCodegen.genTypeInfoToProjection(v, argument.getProjectionKind());
|
||||
v.astore(JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
else {
|
||||
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasNonConstantPropertyInitializers(JetNamespace namespace, ClassContext context) {
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void done() {
|
||||
v.visitEnd();
|
||||
}
|
||||
|
||||
public static String getJVMClassName(String fqName) {
|
||||
if (fqName.length() == 0) {
|
||||
return "namespace";
|
||||
}
|
||||
return fqName.replace('.', '/') + "/namespace";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class OwnerKind {
|
||||
private final String name;
|
||||
|
||||
public OwnerKind(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static final OwnerKind NAMESPACE = new OwnerKind("namespace");
|
||||
public static final OwnerKind INTERFACE = new OwnerKind("interface");
|
||||
public static final OwnerKind IMPLEMENTATION = new OwnerKind("implementation");
|
||||
|
||||
public static class DelegateKind extends OwnerKind {
|
||||
private final StackValue delegate;
|
||||
private final String ownerClass;
|
||||
|
||||
public DelegateKind(StackValue delegate, String ownerClass) {
|
||||
super("delegateKind");
|
||||
this.delegate = delegate;
|
||||
this.ownerClass = ownerClass;
|
||||
}
|
||||
|
||||
public StackValue getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public String getOwnerClass() {
|
||||
return ownerClass;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OwnerKind(" + name + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class PropertyCodegen {
|
||||
private final GenerationState state;
|
||||
private final FunctionCodegen functionCodegen;
|
||||
private final ClassVisitor v;
|
||||
private final OwnerKind kind;
|
||||
|
||||
public PropertyCodegen(ClassContext context, ClassVisitor v, FunctionCodegen functionCodegen, GenerationState state) {
|
||||
this.v = v;
|
||||
this.functionCodegen = functionCodegen;
|
||||
this.state = state;
|
||||
this.kind = context.getContextKind();
|
||||
}
|
||||
|
||||
public void gen(JetProperty p) {
|
||||
final VariableDescriptor descriptor = state.getBindingContext().get(BindingContext.VARIABLE, p);
|
||||
if (!(descriptor instanceof PropertyDescriptor)) {
|
||||
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);
|
||||
generateGetter(p, propertyDescriptor);
|
||||
generateSetter(p, propertyDescriptor);
|
||||
}
|
||||
else if (kind == OwnerKind.INTERFACE) {
|
||||
final JetPropertyAccessor getter = p.getGetter();
|
||||
if ((getter != null && !getter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
|
||||
(getter == null && isExternallyAccessible(p)))) {
|
||||
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
|
||||
getterName(p.getName()),
|
||||
state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(),
|
||||
null, null);
|
||||
}
|
||||
final JetPropertyAccessor setter = p.getSetter();
|
||||
if ((setter != null && !setter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
|
||||
(setter == null && isExternallyAccessible(p) && p.isVar()))) {
|
||||
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
|
||||
setterName(p.getName()),
|
||||
state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(),
|
||||
null, null);
|
||||
}
|
||||
}
|
||||
else if (kind instanceof OwnerKind.DelegateKind) {
|
||||
generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBackingField(JetProperty p, PropertyDescriptor propertyDescriptor) {
|
||||
if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
Object value = null;
|
||||
final JetExpression initializer = p.getInitializer();
|
||||
if (initializer != null) {
|
||||
if (initializer instanceof JetConstantExpression) {
|
||||
CompileTimeConstant<?> compileTimeValue = state.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
|
||||
assert compileTimeValue != null;
|
||||
value = compileTimeValue.getValue();
|
||||
}
|
||||
}
|
||||
final int modifiers;
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
int access = isExternallyAccessible(p) ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE;
|
||||
modifiers = access | Opcodes.ACC_STATIC;
|
||||
}
|
||||
else {
|
||||
modifiers = Opcodes.ACC_PRIVATE;
|
||||
}
|
||||
v.visitField(modifiers, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateGetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
|
||||
final JetPropertyAccessor getter = p.getGetter();
|
||||
if (getter != null) {
|
||||
if (getter.getBodyExpression() != null) {
|
||||
functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor), propertyDescriptor.getGetter());
|
||||
}
|
||||
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
generateDefaultGetter(p, getter);
|
||||
}
|
||||
}
|
||||
else if (isExternallyAccessible(p)) {
|
||||
generateDefaultGetter(p, p);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExternallyAccessible(JetProperty p) {
|
||||
return !p.hasModifier(JetTokens.PRIVATE_KEYWORD);
|
||||
}
|
||||
|
||||
private void generateSetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
|
||||
final JetPropertyAccessor setter = p.getSetter();
|
||||
if (setter != null) {
|
||||
if (setter.getBodyExpression() != null) {
|
||||
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
|
||||
assert setterDescriptor != null;
|
||||
functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor), setterDescriptor);
|
||||
}
|
||||
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
generateDefaultSetter(p, setter);
|
||||
}
|
||||
}
|
||||
else if (isExternallyAccessible(p) && p.isVar()) {
|
||||
generateDefaultSetter(p, p);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
|
||||
generateDefaultGetter(propertyDescriptor, flags);
|
||||
}
|
||||
|
||||
public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags) {
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
else if (kind == OwnerKind.INTERFACE) {
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor();
|
||||
String getterName = getterName(propertyDescriptor.getName());
|
||||
MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null);
|
||||
if (kind != OwnerKind.INTERFACE) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
final Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
iv.invokeinterface(dk.getOwnerClass(), getterName, signature);
|
||||
}
|
||||
else {
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
|
||||
state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
}
|
||||
iv.areturn(type);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
|
||||
generateDefaultSetter(propertyDescriptor, flags);
|
||||
}
|
||||
|
||||
public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags) {
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
else if (kind == OwnerKind.INTERFACE) {
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor();
|
||||
MethodVisitor mv = v.visitMethod(flags, setterName(propertyDescriptor.getName()), signature, null, null);
|
||||
if (kind != OwnerKind.INTERFACE) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
final Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
|
||||
int paramCode = 0;
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
paramCode = 1;
|
||||
}
|
||||
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
|
||||
iv.load(paramCode, type);
|
||||
iv.invokeinterface(dk.getOwnerClass(), setterName(propertyDescriptor.getName()), signature);
|
||||
}
|
||||
else {
|
||||
iv.load(paramCode, type);
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
|
||||
state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
}
|
||||
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getterName(String propertyName) {
|
||||
return "get" + StringUtil.capitalizeWithJavaBeanConvention(propertyName);
|
||||
}
|
||||
|
||||
public static String setterName(String propertyName) {
|
||||
return "set" + StringUtil.capitalizeWithJavaBeanConvention(propertyName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,608 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class StackValue {
|
||||
protected final Type type;
|
||||
|
||||
public StackValue(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract void put(Type type, InstructionAdapter v);
|
||||
|
||||
public void store(InstructionAdapter v) {
|
||||
throw new UnsupportedOperationException("cannot store to value " + this);
|
||||
}
|
||||
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
}
|
||||
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
if (this.type == Type.BOOLEAN_TYPE) {
|
||||
put(Type.BOOLEAN_TYPE, v);
|
||||
if (jumpIfFalse) {
|
||||
v.ifeq(label);
|
||||
}
|
||||
else {
|
||||
v.ifne(label);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("can't generate a cond jump for a non-boolean value");
|
||||
}
|
||||
}
|
||||
|
||||
public static StackValue local(int index, Type type) {
|
||||
return new Local(index, type);
|
||||
}
|
||||
|
||||
public static StackValue onStack(Type type) {
|
||||
return type == Type.VOID_TYPE ? none() : new OnStack(type);
|
||||
}
|
||||
|
||||
public static StackValue constant(Object value, Type type) {
|
||||
return new Constant(value, type);
|
||||
}
|
||||
|
||||
public static StackValue cmp(IElementType opToken, Type type) {
|
||||
return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type) : new NumberCompare(opToken, type);
|
||||
}
|
||||
|
||||
public static StackValue not(StackValue stackValue) {
|
||||
return new Invert(stackValue);
|
||||
}
|
||||
|
||||
public static StackValue arrayElement(Type type) {
|
||||
return new ArrayElement(type);
|
||||
}
|
||||
|
||||
public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter) {
|
||||
return new CollectionElement(type, getter, setter);
|
||||
}
|
||||
|
||||
public static StackValue field(Type type, String owner, String name, boolean isStatic) {
|
||||
return new Field(type, owner, name, isStatic);
|
||||
}
|
||||
|
||||
public static StackValue instanceField(Type type, String owner, String name) {
|
||||
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 expression(Type type, JetExpression expression, ExpressionCodegen generator) {
|
||||
return new Expression(type, expression, generator);
|
||||
}
|
||||
|
||||
private static void box(final Type type, final Type toType, InstructionAdapter v) {
|
||||
// TODO handle toType correctly
|
||||
if (type == Type.INT_TYPE || (JetTypeMapper.isIntPrimitive(type) && toType.getInternalName().equals("java/lang/Integer"))) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE) {
|
||||
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
}
|
||||
else if (type == Type.BYTE_TYPE) {
|
||||
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
}
|
||||
}
|
||||
|
||||
private static void unbox(final Type type, InstructionAdapter v) {
|
||||
if (type == Type.INT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "intValue", "()I");
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z");
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokevirtual("java/lang/Character", "charValue", "()C");
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "shortValue", "()S");
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "longValue", "()J");
|
||||
}
|
||||
else if (type == Type.BYTE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "byteValue", "()B");
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "floatValue", "()F");
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "doubleValue", "()D");
|
||||
}
|
||||
}
|
||||
|
||||
public void upcast(Type type, InstructionAdapter v) {
|
||||
if (type.equals(this.type)) return;
|
||||
|
||||
if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) {
|
||||
v.checkcast(type);
|
||||
}
|
||||
else {
|
||||
coerce(type, v);
|
||||
}
|
||||
}
|
||||
|
||||
protected void coerce(Type type, InstructionAdapter v) {
|
||||
if (type.equals(this.type)) return;
|
||||
|
||||
if (type.getSort() == Type.VOID && this.type.getSort() != Type.VOID) {
|
||||
if(this.type.getSize() == 1)
|
||||
v.pop();
|
||||
else
|
||||
v.pop2();
|
||||
}
|
||||
else if (type.getSort() != Type.VOID && this.type.getSort() == Type.VOID) {
|
||||
if(type.getSort() == Type.OBJECT)
|
||||
v.visitFieldInsn(Opcodes.GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;");
|
||||
else if(type == Type.LONG_TYPE)
|
||||
v.lconst(0);
|
||||
else if(type == Type.FLOAT_TYPE)
|
||||
v.fconst(0);
|
||||
else if(type == Type.DOUBLE_TYPE)
|
||||
v.dconst(0);
|
||||
else
|
||||
v.iconst(0);
|
||||
}
|
||||
else if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) {
|
||||
// v.checkcast(type);
|
||||
}
|
||||
else if (type.getSort() == Type.OBJECT) {
|
||||
box(this.type, type, v);
|
||||
}
|
||||
else if (this.type.getSort() == Type.OBJECT && type.getSort() <= Type.DOUBLE) {
|
||||
if (this.type.equals(JetTypeMapper.TYPE_OBJECT)) {
|
||||
if (type.getSort() == Type.BOOLEAN) {
|
||||
v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE);
|
||||
}
|
||||
else {
|
||||
v.checkcast(JetTypeMapper.JL_NUMBER_TYPE);
|
||||
}
|
||||
}
|
||||
unbox(type, v);
|
||||
}
|
||||
else {
|
||||
v.cast(this.type, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected void putAsBoolean(InstructionAdapter v) {
|
||||
Label ifTrue = new Label();
|
||||
Label end = new Label();
|
||||
condJump(ifTrue, false, v);
|
||||
v.iconst(0);
|
||||
v.goTo(end);
|
||||
v.mark(ifTrue);
|
||||
v.iconst(1);
|
||||
v.mark(end);
|
||||
}
|
||||
|
||||
public static StackValue none() {
|
||||
return None.INSTANCE;
|
||||
}
|
||||
|
||||
private static class None extends StackValue {
|
||||
public static None INSTANCE = new None();
|
||||
private None() {
|
||||
super(Type.VOID_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
coerce(type, v);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Local extends StackValue {
|
||||
private final int index;
|
||||
|
||||
public Local(int index, Type type) {
|
||||
super(type);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.load(index, this.type);
|
||||
coerce(type, v);
|
||||
// TODO unbox
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
v.store(index, this.type);
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnStack extends StackValue {
|
||||
public OnStack(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (type == Type.VOID_TYPE && this.type != Type.VOID_TYPE) {
|
||||
if (this.type.getSize() == 2) {
|
||||
v.pop2();
|
||||
}
|
||||
else {
|
||||
v.pop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
coerce(type, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Constant extends StackValue {
|
||||
private final Object value;
|
||||
|
||||
public Constant(Object value, Type type) {
|
||||
super(type);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if(value instanceof Integer)
|
||||
v.iconst((Integer) value);
|
||||
else
|
||||
if(value instanceof Long)
|
||||
v.lconst((Long) value);
|
||||
else
|
||||
if(value instanceof Float)
|
||||
v.fconst((Float) value);
|
||||
else
|
||||
if(value instanceof Double)
|
||||
v.dconst((Double) value);
|
||||
else
|
||||
v.aconst(value);
|
||||
coerce(type, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
if (value instanceof Boolean) {
|
||||
boolean boolValue = (Boolean) value;
|
||||
if (boolValue ^ jumpIfFalse) {
|
||||
v.goTo(label);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate this condjump");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class NumberCompare extends StackValue {
|
||||
protected final IElementType opToken;
|
||||
private final Type operandType;
|
||||
|
||||
public NumberCompare(IElementType opToken, Type operandType) {
|
||||
super(Type.BOOLEAN_TYPE);
|
||||
this.opToken = opToken;
|
||||
this.operandType = operandType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (type == Type.VOID_TYPE) {
|
||||
return;
|
||||
}
|
||||
if (type != Type.BOOLEAN_TYPE) {
|
||||
throw new UnsupportedOperationException("don't know how to put a compare as a non-boolean type " + type);
|
||||
}
|
||||
putAsBoolean(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
int opcode;
|
||||
if (opToken == JetTokens.EQEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFNE : Opcodes.IFEQ;
|
||||
}
|
||||
else if (opToken == JetTokens.EXCLEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFEQ : Opcodes.IFNE;
|
||||
}
|
||||
else if (opToken == JetTokens.GT) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFLE : Opcodes.IFGT;
|
||||
}
|
||||
else if (opToken == JetTokens.GTEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFLT : Opcodes.IFGE;
|
||||
}
|
||||
else if (opToken == JetTokens.LT) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFGE : Opcodes.IFLT;
|
||||
}
|
||||
else if (opToken == JetTokens.LTEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IFGT : Opcodes.IFLE;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate this condjump");
|
||||
}
|
||||
if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) {
|
||||
if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
|
||||
v.cmpg(operandType);
|
||||
}
|
||||
else {
|
||||
v.cmpl(operandType);
|
||||
}
|
||||
}
|
||||
else if (operandType == Type.LONG_TYPE) {
|
||||
v.lcmp();
|
||||
}
|
||||
else {
|
||||
opcode += (Opcodes.IF_ICMPEQ - Opcodes.IFEQ);
|
||||
}
|
||||
v.visitJumpInsn(opcode, label);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ObjectCompare extends NumberCompare {
|
||||
public ObjectCompare(IElementType opToken, Type operandType) {
|
||||
super(opToken, operandType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
int opcode;
|
||||
if (opToken == JetTokens.EQEQEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IF_ACMPNE : Opcodes.IF_ACMPEQ;
|
||||
}
|
||||
else if (opToken == JetTokens.EXCLEQEQEQ) {
|
||||
opcode = jumpIfFalse ? Opcodes.IF_ACMPEQ : Opcodes.IF_ACMPNE;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate this condjump");
|
||||
}
|
||||
v.visitJumpInsn(opcode, label);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Invert extends StackValue {
|
||||
private StackValue myOperand;
|
||||
|
||||
private Invert(StackValue operand) {
|
||||
super(operand.type);
|
||||
myOperand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (type != Type.BOOLEAN_TYPE) {
|
||||
throw new UnsupportedOperationException("don't know how to put a compare as a non-boolean type");
|
||||
}
|
||||
putAsBoolean(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
myOperand.condJump(label, !jumpIfFalse, v);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayElement extends StackValue {
|
||||
public ArrayElement(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.aload(type); // assumes array and index are on the stack
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
v.astore(type); // assumes array and index are on the stack
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
if (below == 1) {
|
||||
v.dup2X1();
|
||||
}
|
||||
else {
|
||||
v.dup2(); // array and index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CollectionElement extends StackValue {
|
||||
private final CallableMethod getter;
|
||||
private final CallableMethod setter;
|
||||
|
||||
public CollectionElement(Type type, CallableMethod getter, CallableMethod setter) {
|
||||
super(type);
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (getter == null) {
|
||||
throw new UnsupportedOperationException("no getter specified");
|
||||
}
|
||||
getter.invoke(v);
|
||||
coerce(type, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
if (setter == null) {
|
||||
throw new UnsupportedOperationException("no setter specified");
|
||||
}
|
||||
setter.invoke(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
if (below == 1) {
|
||||
v.dup2X1();
|
||||
}
|
||||
else {
|
||||
v.dup2(); // collection and index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Field extends StackValue {
|
||||
private final String owner;
|
||||
private final String name;
|
||||
private final boolean isStatic;
|
||||
|
||||
public Field(Type type, String owner, String name, boolean isStatic) {
|
||||
super(type);
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.isStatic = isStatic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
if (!isStatic) {
|
||||
if (below == 1) {
|
||||
v.dupX1();
|
||||
}
|
||||
else {
|
||||
v.dup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
private static class InstanceField extends StackValue {
|
||||
private final String owner;
|
||||
private final String name;
|
||||
|
||||
public InstanceField(Type type, String owner, String name) {
|
||||
super(type);
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
v.getfield(owner, name, this.type.getDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(InstructionAdapter v) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
v.putfield(owner, name, this.type.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Property extends StackValue {
|
||||
private final String name;
|
||||
private final Method getter;
|
||||
private final Method setter;
|
||||
private final String owner;
|
||||
private final boolean isStatic;
|
||||
private final boolean isInterface;
|
||||
|
||||
public Property(String name, String owner, Method getter, Method setter, boolean aStatic, boolean isInterface, Type type) {
|
||||
super(type);
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
isStatic = aStatic;
|
||||
this.isInterface = isInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
if (getter == null) {
|
||||
v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor());
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : 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());
|
||||
}
|
||||
else {
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v, int below) {
|
||||
if (!isStatic) {
|
||||
if (below == 1) {
|
||||
v.dupX1();
|
||||
}
|
||||
else {
|
||||
v.dup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Expression extends StackValue {
|
||||
private final JetExpression expression;
|
||||
private final ExpressionCodegen generator;
|
||||
|
||||
public Expression(Type type, JetExpression expression, ExpressionCodegen generator) {
|
||||
super(type);
|
||||
this.expression = expression;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
generator.gen(expression, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ArraySize implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
v.arraylength();
|
||||
return StackValue.onStack(Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class BinaryOp implements IntrinsicMethod {
|
||||
private final int opcode;
|
||||
|
||||
public BinaryOp(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
if (arguments.size() == 1) {
|
||||
// intrinsic is called as an ordinary function
|
||||
if (receiver != null) {
|
||||
receiver.put(expectedType, v);
|
||||
}
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
}
|
||||
else {
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
codegen.gen(arguments.get(1), expectedType);
|
||||
}
|
||||
v.visitInsn(expectedType.getOpcode(opcode));
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class Concat implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
codegen.generateStringBuilderConstructor();
|
||||
if (receiver == null) { // LHS.plus(RHS)
|
||||
v.swap(); // StringBuilder LHS
|
||||
codegen.invokeAppendMethod(codegen.expressionType(arguments.get(0))); // StringBuilder(LHS)
|
||||
codegen.invokeAppend(arguments.get(0));
|
||||
}
|
||||
else { // LHS + RHS
|
||||
codegen.invokeAppend(arguments.get(0)); // StringBuilder(LHS)
|
||||
codegen.invokeAppend(arguments.get(1));
|
||||
}
|
||||
|
||||
v.invokevirtual(ExpressionCodegen.CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
|
||||
return StackValue.onStack(Type.getObjectType("java/lang/String"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class Increment implements IntrinsicMethod {
|
||||
private final int myDelta;
|
||||
|
||||
public Increment(int delta) {
|
||||
myDelta = delta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
final JetExpression operand = arguments.get(0);
|
||||
if (operand instanceof JetReferenceExpression) {
|
||||
final int index = codegen.indexOfLocal((JetReferenceExpression) operand);
|
||||
if (index >= 0 && JetTypeMapper.isIntPrimitive(expectedType)) {
|
||||
v.iinc(index, myDelta);
|
||||
return StackValue.local(index, expectedType);
|
||||
}
|
||||
}
|
||||
StackValue value = codegen.genQualified(receiver, operand);
|
||||
value.dupReceiver(v, 0);
|
||||
value.put(expectedType, v);
|
||||
if (expectedType == Type.LONG_TYPE) {
|
||||
v.lconst(myDelta);
|
||||
}
|
||||
else if (expectedType == Type.FLOAT_TYPE) {
|
||||
v.fconst(myDelta);
|
||||
}
|
||||
else if (expectedType == Type.DOUBLE_TYPE) {
|
||||
v.dconst(myDelta);
|
||||
}
|
||||
else {
|
||||
v.aconst(myDelta);
|
||||
}
|
||||
v.add(expectedType);
|
||||
value.store(v);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.Callable;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public interface IntrinsicMethod extends Callable {
|
||||
StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class IntrinsicMethods {
|
||||
private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus();
|
||||
private static final IntrinsicMethod NUMBER_CAST = new NumberCast();
|
||||
private static final IntrinsicMethod INV = new Inv();
|
||||
private static final IntrinsicMethod TYPEINFO = new TypeInfo();
|
||||
private static final IntrinsicMethod VALUE_TYPEINFO = new ValueTypeInfo();
|
||||
private static final IntrinsicMethod RANGE_TO = new RangeTo();
|
||||
private static final IntrinsicMethod INC = new Increment(1);
|
||||
private static final IntrinsicMethod DEC = new Increment(-1);
|
||||
|
||||
private static final List<String> PRIMITIVE_NUMBER_TYPES = ImmutableList.of("Boolean", "Byte", "Char", "Short", "Int", "Float", "Long", "Double");
|
||||
|
||||
private final Project myProject;
|
||||
private final JetStandardLibrary myStdLib;
|
||||
private final Map<DeclarationDescriptor, IntrinsicMethod> myMethods = new HashMap<DeclarationDescriptor, IntrinsicMethod>();
|
||||
|
||||
public IntrinsicMethods(Project project, JetStandardLibrary stdlib) {
|
||||
myProject = project;
|
||||
myStdLib = stdlib;
|
||||
List<String> primitiveCastMethods = ImmutableList.of("dbl", "flt", "lng", "int", "chr", "sht", "byt");
|
||||
for (String method : primitiveCastMethods) {
|
||||
declareIntrinsicProperty("Number", method, NUMBER_CAST);
|
||||
}
|
||||
declareIntrinsicProperty("Array", "size", new ArraySize());
|
||||
|
||||
for (String type : PRIMITIVE_NUMBER_TYPES) {
|
||||
declareIntrinsicFunction(type, "minus", 0, UNARY_MINUS);
|
||||
declareIntrinsicFunction(type, "inv", 0, INV);
|
||||
declareIntrinsicFunction(type, "rangeTo", 1, RANGE_TO);
|
||||
declareIntrinsicFunction(type, "inc", 0, INC);
|
||||
declareIntrinsicFunction(type, "dec", 0, DEC);
|
||||
}
|
||||
|
||||
final FunctionGroup typeInfoFunctionGroup = stdlib.getTypeInfoFunctionGroup();
|
||||
declareOverload(typeInfoFunctionGroup, 0, TYPEINFO);
|
||||
declareOverload(typeInfoFunctionGroup, 1, VALUE_TYPEINFO);
|
||||
|
||||
declareBinaryOp("plus", Opcodes.IADD);
|
||||
declareBinaryOp("minus", Opcodes.ISUB);
|
||||
declareBinaryOp("times", Opcodes.IMUL);
|
||||
declareBinaryOp("div", Opcodes.IDIV);
|
||||
declareBinaryOp("mod", Opcodes.IREM);
|
||||
declareBinaryOp("shl", Opcodes.ISHL);
|
||||
declareBinaryOp("shr", Opcodes.ISHR);
|
||||
declareBinaryOp("ushr", Opcodes.IUSHR);
|
||||
declareBinaryOp("and", Opcodes.IAND);
|
||||
declareBinaryOp("or", Opcodes.IOR);
|
||||
declareBinaryOp("xor", Opcodes.IXOR);
|
||||
|
||||
declareIntrinsicFunction("Boolean", "not", 0, new Not());
|
||||
|
||||
declareIntrinsicFunction("String", "plus", 1, new Concat());
|
||||
|
||||
declareIntrinsicStringMethods();
|
||||
declareIntrinsicProperty("String", "length", new StringLength());
|
||||
}
|
||||
|
||||
private void declareIntrinsicStringMethods() {
|
||||
final ClassDescriptor stringClass = myStdLib.getString();
|
||||
final Collection<DeclarationDescriptor> stringMembers = stringClass.getMemberScope(Collections.<TypeProjection>emptyList()).getAllDescriptors();
|
||||
final PsiClass stringPsiClass = JavaPsiFacade.getInstance(myProject).findClass("java.lang.String",
|
||||
ProjectScope.getLibrariesScope(myProject));
|
||||
for (DeclarationDescriptor stringMember : stringMembers) {
|
||||
if (stringMember instanceof FunctionDescriptor) {
|
||||
final FunctionDescriptor stringMethod = (FunctionDescriptor) stringMember;
|
||||
final PsiMethod[] methods = stringPsiClass.findMethodsByName(stringMember.getName(), false);
|
||||
for (PsiMethod method : methods) {
|
||||
if (method.getParameterList().getParametersCount() == stringMethod.getValueParameters().size()) {
|
||||
myMethods.put(stringMethod, new PsiMethodCall(method));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void declareBinaryOp(String methodName, int opcode) {
|
||||
BinaryOp op = new BinaryOp(opcode);
|
||||
for (String type : PRIMITIVE_NUMBER_TYPES) {
|
||||
declareIntrinsicFunction(type, methodName, 1, op);
|
||||
}
|
||||
}
|
||||
|
||||
private void declareIntrinsicProperty(String className, String methodName, IntrinsicMethod implementation) {
|
||||
final JetScope numberScope = getClassMemberScope(className);
|
||||
final VariableDescriptor variable = numberScope.getVariable(methodName);
|
||||
myMethods.put(variable.getOriginal(), implementation);
|
||||
}
|
||||
|
||||
private void declareIntrinsicFunction(String className, String functionName, int arity, IntrinsicMethod implementation) {
|
||||
JetScope memberScope = getClassMemberScope(className);
|
||||
final FunctionGroup group = memberScope.getFunctionGroup(functionName);
|
||||
declareOverload(group, arity, implementation);
|
||||
}
|
||||
|
||||
private void declareOverload(FunctionGroup group, int arity, IntrinsicMethod implementation) {
|
||||
for (FunctionDescriptor descriptor : group.getFunctionDescriptors()) {
|
||||
if (descriptor.getValueParameters().size() == arity) {
|
||||
myMethods.put(descriptor.getOriginal(), implementation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JetScope getClassMemberScope(String className) {
|
||||
final ClassDescriptor descriptor = (ClassDescriptor) myStdLib.getLibraryScope().getClassifier(className);
|
||||
final List<TypeParameterDescriptor> typeParameterDescriptors = descriptor.getTypeConstructor().getParameters();
|
||||
List<TypeProjection> typeParameters = new ArrayList<TypeProjection>();
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
|
||||
typeParameters.add(new TypeProjection(JetStandardClasses.getAnyType()));
|
||||
}
|
||||
return descriptor.getMemberScope(typeParameters);
|
||||
}
|
||||
|
||||
public IntrinsicMethod getIntrinsic(DeclarationDescriptor descriptor) {
|
||||
return myMethods.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class Inv implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(expectedType, v);
|
||||
v.iconst(-1);
|
||||
v.xor(expectedType);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class Not implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
final StackValue stackValue;
|
||||
if (arguments.size() == 1) {
|
||||
stackValue = codegen.gen(arguments.get(0));
|
||||
}
|
||||
else {
|
||||
stackValue = receiver;
|
||||
}
|
||||
return StackValue.not(stackValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class NumberCast implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(expectedType, v);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.jet.codegen.CallableMethod;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PsiMethodCall implements IntrinsicMethod {
|
||||
private final PsiMethod myMethod;
|
||||
|
||||
public PsiMethodCall(PsiMethod method) {
|
||||
myMethod = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element,
|
||||
List<JetExpression> arguments, StackValue receiver) {
|
||||
final CallableMethod callableMethod = codegen.getTypeMapper().mapToCallableMethod(myMethod);
|
||||
codegen.invokeMethodWithArguments(callableMethod, (JetCallExpression) element, receiver);
|
||||
return StackValue.onStack(callableMethod.getSignature().getReturnType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import jet.IntRange;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class RangeTo implements IntrinsicMethod {
|
||||
private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V";
|
||||
private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class);
|
||||
private static final String CLASS_INT_RANGE = "jet/IntRange";
|
||||
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
JetBinaryExpression expression = (JetBinaryExpression) element;
|
||||
final Type leftType = codegen.expressionType(expression.getLeft());
|
||||
if (JetTypeMapper.isIntPrimitive(leftType)) {
|
||||
v.anew(INT_RANGE_TYPE);
|
||||
v.dup();
|
||||
codegen.gen(expression.getLeft(), Type.INT_TYPE);
|
||||
codegen.gen(expression.getRight(), Type.INT_TYPE);
|
||||
v.invokespecial(CLASS_INT_RANGE, "<init>", INT_RANGE_CONSTRUCTOR_DESCRIPTOR);
|
||||
return StackValue.onStack(INT_RANGE_TYPE);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("ranges are only supported for int objects");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class StringLength implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
v.invokevirtual("java/lang/String", "length", "()I");
|
||||
return StackValue.onStack(Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetTypeProjection;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class TypeInfo implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
final List<JetTypeProjection> typeArguments = ((JetCallExpression) element).getTypeArguments();
|
||||
if (typeArguments.size() != 1) {
|
||||
throw new UnsupportedOperationException("one type argument expected");
|
||||
}
|
||||
codegen.pushTypeArgument(typeArguments.get(0));
|
||||
return StackValue.onStack(JetTypeMapper.TYPE_TYPEINFO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class UnaryMinus implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
if (arguments.size() == 1) {
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
}
|
||||
else {
|
||||
receiver.put(expectedType, v);
|
||||
}
|
||||
v.neg(expectedType);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ValueTypeInfo implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
codegen.gen(arguments.get(0), JetTypeMapper.TYPE_JET_OBJECT);
|
||||
v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;");
|
||||
return StackValue.onStack(JetTypeMapper.TYPE_TYPEINFO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA 10.x" jdkType="IDEA JDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor {
|
||||
|
||||
private TypeConstructor typeConstructor;
|
||||
private JavaClassMembersScope unsubstitutedMemberScope;
|
||||
private JetType classObjectType;
|
||||
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
|
||||
private Modality modality;
|
||||
private JetType superclassType;
|
||||
private final ClassKind kind;
|
||||
|
||||
|
||||
public JavaClassDescriptor(DeclarationDescriptor containingDeclaration, @NotNull ClassKind kind) {
|
||||
super(containingDeclaration);
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public void setTypeConstructor(TypeConstructor typeConstructor) {
|
||||
this.typeConstructor = typeConstructor;
|
||||
}
|
||||
|
||||
public void setModality(Modality modality) {
|
||||
this.modality = modality;
|
||||
}
|
||||
|
||||
public void setUnsubstitutedMemberScope(JavaClassMembersScope memberScope) {
|
||||
this.unsubstitutedMemberScope = memberScope;
|
||||
}
|
||||
|
||||
public void setClassObjectMemberScope(JavaClassMembersScope memberScope) {
|
||||
classObjectType = new JetTypeImpl(
|
||||
new TypeConstructorImpl(
|
||||
JavaDescriptorResolver.JAVA_CLASS_OBJECT,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
true,
|
||||
"Class object emulation for " + getName(),
|
||||
Collections.<TypeParameterDescriptor>emptyList(),
|
||||
Collections.<JetType>emptyList()
|
||||
),
|
||||
memberScope
|
||||
);
|
||||
}
|
||||
|
||||
public void addConstructor(ConstructorDescriptor constructorDescriptor) {
|
||||
this.constructors.addFunction(constructorDescriptor);
|
||||
}
|
||||
|
||||
private TypeSubstitutor createTypeSubstitutor(List<TypeProjection> typeArguments) {
|
||||
List<TypeParameterDescriptor> parameters = getTypeConstructor().getParameters();
|
||||
Map<TypeConstructor, TypeProjection> context = TypeUtils.buildSubstitutionContext(parameters, typeArguments);
|
||||
return TypeSubstitutor.create(context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
||||
assert typeArguments.size() == typeConstructor.getParameters().size();
|
||||
|
||||
if (typeArguments.isEmpty()) return unsubstitutedMemberScope;
|
||||
|
||||
TypeSubstitutor substitutor = createTypeSubstitutor(typeArguments);
|
||||
return new SubstitutingScope(unsubstitutedMemberScope, substitutor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getSuperclassType() {
|
||||
return superclassType;
|
||||
}
|
||||
|
||||
public void setSuperclassType(@NotNull JetType superclassType) {
|
||||
this.superclassType = superclassType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionGroup getConstructors() {
|
||||
// assert typeArguments.size() == typeConstructor.getParameters().size();
|
||||
// if (typeArguments.isEmpty()) return constructors;
|
||||
// return new LazySubstitutingFunctionGroup(createTypeSubstitutor(typeArguments), constructors);
|
||||
return constructors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstructors() {
|
||||
return !constructors.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeConstructor getTypeConstructor() {
|
||||
return typeConstructor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getDefaultType() {
|
||||
return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType getClassObjectType() {
|
||||
return classObjectType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClassObjectAValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Modality getModality() {
|
||||
return modality;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitClassDescriptor(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "java class " + typeConstructor;
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaClassMembersScope implements JetScope {
|
||||
private final PsiClass psiClass;
|
||||
private final JavaSemanticServices semanticServices;
|
||||
private final boolean staticMembers;
|
||||
private final DeclarationDescriptor containingDeclaration;
|
||||
private final Map<String, FunctionGroup> functionGroups = Maps.newHashMap();
|
||||
private final Map<String, VariableDescriptor> variables = Maps.newHashMap();
|
||||
private final Map<String, ClassifierDescriptor> classifiers = Maps.newHashMap();
|
||||
private Collection<DeclarationDescriptor> allDescriptors;
|
||||
|
||||
public JavaClassMembersScope(@NotNull DeclarationDescriptor classDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) {
|
||||
this.containingDeclaration = classDescriptor;
|
||||
this.psiClass = psiClass;
|
||||
this.semanticServices = semanticServices;
|
||||
this.staticMembers = staticMembers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor getContainingDeclaration() {
|
||||
return containingDeclaration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<DeclarationDescriptor> getDeclarationsByLabel(String labelName) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassifierDescriptor getClassifier(@NotNull String name) {
|
||||
ClassifierDescriptor classifierDescriptor = classifiers.get(name);
|
||||
if (classifierDescriptor == null) {
|
||||
classifierDescriptor = doGetClassifierDescriptor(name);
|
||||
classifiers.put(name, classifierDescriptor);
|
||||
}
|
||||
return classifierDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DeclarationDescriptor> getAllDescriptors() {
|
||||
if (allDescriptors == null) {
|
||||
allDescriptors = Sets.newHashSet();
|
||||
TypeSubstitutor substitutorForGenericSupertypes;
|
||||
if (containingDeclaration instanceof ClassDescriptor) {
|
||||
substitutorForGenericSupertypes = semanticServices.getDescriptorResolver().createSubstitutorForGenericSupertypes((ClassDescriptor) containingDeclaration);
|
||||
}
|
||||
else {
|
||||
substitutorForGenericSupertypes = TypeSubstitutor.EMPTY;
|
||||
}
|
||||
|
||||
for (HierarchicalMethodSignature signature : psiClass.getVisibleSignatures()) {
|
||||
PsiMethod method = signature.getMethod();
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
|
||||
continue;
|
||||
}
|
||||
FunctionDescriptor functionDescriptor = semanticServices.getDescriptorResolver().resolveMethodToFunctionDescriptor(containingDeclaration, psiClass, substitutorForGenericSupertypes, method);
|
||||
if (functionDescriptor != null) {
|
||||
allDescriptors.add(functionDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiField field : psiClass.getAllFields()) {
|
||||
VariableDescriptor variableDescriptor = semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field);
|
||||
allDescriptors.add(variableDescriptor);
|
||||
}
|
||||
}
|
||||
return allDescriptors;
|
||||
}
|
||||
|
||||
private ClassifierDescriptor doGetClassifierDescriptor(String name) {
|
||||
// TODO : suboptimal, walk the list only once
|
||||
for (PsiClass innerClass : psiClass.getAllInnerClasses()) {
|
||||
if (name.equals(innerClass.getName())) {
|
||||
if (innerClass.hasModifierProperty(PsiModifier.STATIC) != staticMembers) return null;
|
||||
return semanticServices.getDescriptorResolver().resolveClass(innerClass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableDescriptor getVariable(@NotNull String name) {
|
||||
VariableDescriptor variableDescriptor = variables.get(name);
|
||||
if (variableDescriptor == null) {
|
||||
variableDescriptor = doGetVariable(name);
|
||||
variables.put(name, variableDescriptor);
|
||||
}
|
||||
return variableDescriptor;
|
||||
}
|
||||
|
||||
private VariableDescriptor doGetVariable(String name) {
|
||||
PsiField field = psiClass.findFieldByName(name, true);
|
||||
if (field == null) return null;
|
||||
if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor((ClassDescriptor) containingDeclaration, field);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionGroup getFunctionGroup(@NotNull String name) {
|
||||
FunctionGroup functionGroup = functionGroups.get(name);
|
||||
if (functionGroup == null) {
|
||||
functionGroup = semanticServices.getDescriptorResolver().resolveFunctionGroup(
|
||||
containingDeclaration,
|
||||
psiClass,
|
||||
staticMembers ? null : (ClassDescriptor) containingDeclaration,
|
||||
name,
|
||||
staticMembers);
|
||||
functionGroups.put(name, functionGroup);
|
||||
}
|
||||
return functionGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceDescriptor getNamespace(@NotNull String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getThisType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.ImportingStrategy;
|
||||
import org.jetbrains.jet.lang.resolve.WritableScope;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaDefaultImports {
|
||||
public static final ImportingStrategy JAVA_DEFAULT_IMPORTS = new ImportingStrategy() {
|
||||
@Override
|
||||
public void addImports(Project project, JetSemanticServices semanticServices, BindingTrace trace, WritableScope rootScope) {
|
||||
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("").getMemberScope());
|
||||
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("java.lang").getMemberScope());
|
||||
JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, trace);
|
||||
rootScope.importScope(new JavaPackageScope("", null, javaSemanticServices));
|
||||
rootScope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices));
|
||||
}
|
||||
};
|
||||
}
|
||||
+371
@@ -0,0 +1,371 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaDescriptorResolver {
|
||||
|
||||
/*package*/ static final DeclarationDescriptor JAVA_ROOT = new DeclarationDescriptorImpl(null, Collections.<AnnotationDescriptor>emptyList(), "<java_root>") {
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitDeclarationDescriptor(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
/*package*/ static final DeclarationDescriptor JAVA_CLASS_OBJECT = new DeclarationDescriptorImpl(null, Collections.<AnnotationDescriptor>emptyList(), "<java_class_object_emulation>") {
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitDeclarationDescriptor(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
protected final Map<String, ClassDescriptor> classDescriptorCache = new HashMap<String, ClassDescriptor>();
|
||||
protected final Map<PsiTypeParameter, TypeParameterDescriptor> typeParameterDescriptorCache = Maps.newHashMap();
|
||||
protected final Map<PsiMethod, FunctionDescriptor> methodDescriptorCache = Maps.newHashMap();
|
||||
protected final Map<PsiField, VariableDescriptor> fieldDescriptorCache = Maps.newHashMap();
|
||||
protected final Map<String, NamespaceDescriptor> namespaceDescriptorCache = new HashMap<String, NamespaceDescriptor>();
|
||||
protected final JavaPsiFacade javaFacade;
|
||||
protected final GlobalSearchScope javaSearchScope;
|
||||
protected final JavaSemanticServices semanticServices;
|
||||
|
||||
public JavaDescriptorResolver(Project project, JavaSemanticServices semanticServices) {
|
||||
this.javaFacade = JavaPsiFacade.getInstance(project);
|
||||
this.javaSearchScope = GlobalSearchScope.allScope(project);
|
||||
this.semanticServices = semanticServices;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor resolveClass(@NotNull PsiClass psiClass) {
|
||||
String qualifiedName = psiClass.getQualifiedName();
|
||||
ClassDescriptor classDescriptor = classDescriptorCache.get(qualifiedName);
|
||||
if (classDescriptor == null) {
|
||||
classDescriptor = createJavaClassDescriptor(psiClass);
|
||||
classDescriptorCache.put(qualifiedName, classDescriptor);
|
||||
}
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ClassDescriptor resolveClass(@NotNull String qualifiedName) {
|
||||
ClassDescriptor classDescriptor = classDescriptorCache.get(qualifiedName);
|
||||
if (classDescriptor == null) {
|
||||
PsiClass psiClass = javaFacade.findClass(qualifiedName, javaSearchScope);
|
||||
if (psiClass == null) {
|
||||
return null;
|
||||
}
|
||||
classDescriptor = createJavaClassDescriptor(psiClass);
|
||||
}
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
private ClassDescriptor createJavaClassDescriptor(@NotNull final PsiClass psiClass) {
|
||||
assert !classDescriptorCache.containsKey(psiClass.getQualifiedName()) : psiClass.getQualifiedName();
|
||||
classDescriptorCache.put(psiClass.getQualifiedName(), null); // TODO
|
||||
|
||||
String name = psiClass.getName();
|
||||
JavaClassDescriptor classDescriptor = new JavaClassDescriptor(
|
||||
JAVA_ROOT, psiClass.isInterface() ? ClassKind.TRAIT : ClassKind.CLASS
|
||||
);
|
||||
classDescriptor.setName(name);
|
||||
|
||||
List<JetType> supertypes = new ArrayList<JetType>();
|
||||
List<TypeParameterDescriptor> typeParameters = resolveTypeParameters(classDescriptor, psiClass.getTypeParameters());
|
||||
classDescriptor.setTypeConstructor(new TypeConstructorImpl(
|
||||
classDescriptor,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
// TODO
|
||||
psiClass.hasModifierProperty(PsiModifier.FINAL),
|
||||
name,
|
||||
typeParameters,
|
||||
supertypes
|
||||
|
||||
));
|
||||
classDescriptor.setModality(Modality.convertFromFlags(
|
||||
psiClass.hasModifierProperty(PsiModifier.ABSTRACT) || psiClass.isInterface(),
|
||||
!psiClass.hasModifierProperty(PsiModifier.FINAL))
|
||||
);
|
||||
classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor);
|
||||
classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false));
|
||||
classDescriptor.setClassObjectMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, true));
|
||||
// UGLY HACK
|
||||
supertypes.addAll(getSupertypes(psiClass));
|
||||
if (psiClass.isInterface()) {
|
||||
classDescriptor.setSuperclassType(JetStandardClasses.getAnyType()); // TODO : Make it java.lang.Object
|
||||
}
|
||||
else {
|
||||
PsiClassType[] extendsListTypes = psiClass.getExtendsListTypes();
|
||||
assert extendsListTypes.length == 0 || extendsListTypes.length == 1;
|
||||
JetType superclassType = extendsListTypes.length == 0
|
||||
? JetStandardClasses.getAnyType()
|
||||
: semanticServices.getTypeTransformer().transformToType(extendsListTypes[0]);
|
||||
classDescriptor.setSuperclassType(superclassType);
|
||||
}
|
||||
|
||||
PsiMethod[] psiConstructors = psiClass.getConstructors();
|
||||
|
||||
if (psiConstructors.length == 0) {
|
||||
if (!psiClass.hasModifierProperty(PsiModifier.ABSTRACT) && !psiClass.isInterface()) {
|
||||
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
|
||||
classDescriptor,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
false);
|
||||
constructorDescriptor.initialize(typeParameters, Collections.<ValueParameterDescriptor>emptyList(), Modality.FINAL);
|
||||
constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
|
||||
classDescriptor.addConstructor(constructorDescriptor);
|
||||
semanticServices.getTrace().record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (PsiMethod constructor : psiConstructors) {
|
||||
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
|
||||
classDescriptor,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
false);
|
||||
constructorDescriptor.initialize(typeParameters, resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()), Modality.FINAL);
|
||||
constructorDescriptor.setReturnType(classDescriptor.getDefaultType());
|
||||
classDescriptor.addConstructor(constructorDescriptor);
|
||||
semanticServices.getTrace().record(BindingContext.CONSTRUCTOR, constructor, constructorDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
semanticServices.getTrace().record(BindingContext.CLASS, psiClass, classDescriptor);
|
||||
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
private List<TypeParameterDescriptor> resolveTypeParameters(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter[] typeParameters) {
|
||||
List<TypeParameterDescriptor> result = Lists.newArrayList();
|
||||
for (PsiTypeParameter typeParameter : typeParameters) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = resolveTypeParameter(containingDeclaration, typeParameter);
|
||||
result.add(typeParameterDescriptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeParameterDescriptor createJavaTypeParameterDescriptor(@NotNull DeclarationDescriptor owner, @NotNull PsiTypeParameter typeParameter) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification(
|
||||
owner,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
Variance.INVARIANT,
|
||||
typeParameter.getName(),
|
||||
typeParameter.getIndex()
|
||||
);
|
||||
typeParameterDescriptorCache.put(typeParameter, typeParameterDescriptor);
|
||||
PsiClassType[] referencedTypes = typeParameter.getExtendsList().getReferencedTypes();
|
||||
if (referencedTypes.length == 0){
|
||||
typeParameterDescriptor.addUpperBound(JetStandardClasses.getNullableAnyType());
|
||||
}
|
||||
else if (referencedTypes.length == 1) {
|
||||
typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedTypes[0]));
|
||||
}
|
||||
else {
|
||||
for (PsiClassType referencedType : referencedTypes) {
|
||||
typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedType));
|
||||
}
|
||||
}
|
||||
return typeParameterDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TypeParameterDescriptor resolveTypeParameter(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter psiTypeParameter) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = typeParameterDescriptorCache.get(psiTypeParameter);
|
||||
if (typeParameterDescriptor == null) {
|
||||
typeParameterDescriptor = createJavaTypeParameterDescriptor(containingDeclaration, psiTypeParameter);
|
||||
// This is done inside the method: typeParameterDescriptorCache.put(psiTypeParameter, typeParameterDescriptor);
|
||||
}
|
||||
return typeParameterDescriptor;
|
||||
}
|
||||
|
||||
private Collection<? extends JetType> getSupertypes(PsiClass psiClass) {
|
||||
List<JetType> result = new ArrayList<JetType>();
|
||||
result.add(JetStandardClasses.getAnyType());
|
||||
transformSupertypeList(result, psiClass.getExtendsListTypes());
|
||||
transformSupertypeList(result, psiClass.getImplementsListTypes());
|
||||
return result;
|
||||
}
|
||||
|
||||
private void transformSupertypeList(List<JetType> result, PsiClassType[] extendsListTypes) {
|
||||
for (PsiClassType type : extendsListTypes) {
|
||||
JetType transform = semanticServices.getTypeTransformer().transformToType(type);
|
||||
|
||||
result.add(TypeUtils.makeNotNullable(transform));
|
||||
}
|
||||
}
|
||||
|
||||
public NamespaceDescriptor resolveNamespace(String qualifiedName) {
|
||||
NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(qualifiedName);
|
||||
if (namespaceDescriptor == null) {
|
||||
// TODO : packages
|
||||
|
||||
// PsiClass psiClass = javaFacade.findClass(qualifiedName, javaSearchScope);
|
||||
// if (psiClass != null) {
|
||||
// namespaceDescriptor = createJavaNamespaceDescriptor(psiClass);
|
||||
// }
|
||||
// else {
|
||||
PsiPackage psiPackage = javaFacade.findPackage(qualifiedName);
|
||||
if (psiPackage == null) {
|
||||
return null;
|
||||
}
|
||||
namespaceDescriptor = createJavaNamespaceDescriptor(psiPackage);
|
||||
// }
|
||||
namespaceDescriptorCache.put(qualifiedName, namespaceDescriptor);
|
||||
}
|
||||
return namespaceDescriptor;
|
||||
}
|
||||
|
||||
private NamespaceDescriptor createJavaNamespaceDescriptor(PsiPackage psiPackage) {
|
||||
JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor(
|
||||
JAVA_ROOT,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
psiPackage.getName()
|
||||
);
|
||||
namespaceDescriptor.setMemberScope(new JavaPackageScope(psiPackage.getQualifiedName(), namespaceDescriptor, semanticServices));
|
||||
semanticServices.getTrace().record(BindingContext.NAMESPACE, psiPackage, namespaceDescriptor);
|
||||
return namespaceDescriptor;
|
||||
}
|
||||
|
||||
private NamespaceDescriptor createJavaNamespaceDescriptor(@NotNull final PsiClass psiClass) {
|
||||
JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor(
|
||||
JAVA_ROOT,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
psiClass.getName()
|
||||
);
|
||||
namespaceDescriptor.setMemberScope(new JavaClassMembersScope(namespaceDescriptor, psiClass, semanticServices, true));
|
||||
semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor);
|
||||
return namespaceDescriptor;
|
||||
}
|
||||
|
||||
public List<ValueParameterDescriptor> resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) {
|
||||
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
|
||||
for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
String name = parameter.getName();
|
||||
result.add(new ValueParameterDescriptorImpl(
|
||||
containingDeclaration,
|
||||
i,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
name == null ? "p" + i : name,
|
||||
null, // TODO : review
|
||||
semanticServices.getTypeTransformer().transformToType(parameter.getType()),
|
||||
false,
|
||||
parameter.isVarArgs()
|
||||
));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) {
|
||||
VariableDescriptor variableDescriptor = fieldDescriptorCache.get(field);
|
||||
if (variableDescriptor != null) {
|
||||
return variableDescriptor;
|
||||
}
|
||||
JetType type = semanticServices.getTypeTransformer().transformToType(field.getType());
|
||||
boolean isFinal = field.hasModifierProperty(PsiModifier.FINAL);
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
||||
containingDeclaration,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Modality.FINAL,
|
||||
!isFinal,
|
||||
null,
|
||||
field.getName(),
|
||||
isFinal ? null : type,
|
||||
type);
|
||||
semanticServices.getTrace().record(BindingContext.VARIABLE, field, propertyDescriptor);
|
||||
fieldDescriptorCache.put(field, propertyDescriptor);
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionGroup resolveFunctionGroup(@NotNull DeclarationDescriptor owner, @NotNull PsiClass psiClass, @Nullable ClassDescriptor classDescriptor, @NotNull String methodName, boolean staticMembers) {
|
||||
WritableFunctionGroup writableFunctionGroup = new WritableFunctionGroup(methodName);
|
||||
final Collection<HierarchicalMethodSignature> signatures = psiClass.getVisibleSignatures();
|
||||
TypeSubstitutor typeSubstitutor = createSubstitutorForGenericSupertypes(classDescriptor);
|
||||
for (HierarchicalMethodSignature signature: signatures) {
|
||||
PsiMethod method = signature.getMethod();
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
|
||||
continue;
|
||||
}
|
||||
if (!methodName.equals(method.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FunctionDescriptor substitutedFunctionDescriptor = resolveMethodToFunctionDescriptor(owner, psiClass, typeSubstitutor, method);
|
||||
if (substitutedFunctionDescriptor != null) {
|
||||
writableFunctionGroup.addFunction(substitutedFunctionDescriptor);
|
||||
}
|
||||
}
|
||||
return writableFunctionGroup;
|
||||
}
|
||||
|
||||
public TypeSubstitutor createSubstitutorForGenericSupertypes(ClassDescriptor classDescriptor) {
|
||||
TypeSubstitutor typeSubstitutor;
|
||||
if (classDescriptor != null) {
|
||||
typeSubstitutor = TypeUtils.buildDeepSubstitutor(classDescriptor.getDefaultType());
|
||||
}
|
||||
else {
|
||||
typeSubstitutor = TypeSubstitutor.EMPTY;
|
||||
}
|
||||
return typeSubstitutor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FunctionDescriptor resolveMethodToFunctionDescriptor(DeclarationDescriptor owner, PsiClass psiClass, TypeSubstitutor typeSubstitutorForGenericSuperclasses, PsiMethod method) {
|
||||
PsiType returnType = method.getReturnType();
|
||||
if (returnType == null) {
|
||||
return null;
|
||||
}
|
||||
FunctionDescriptor functionDescriptor = methodDescriptorCache.get(method);
|
||||
if (functionDescriptor != null) {
|
||||
if (method.getContainingClass() != psiClass) {
|
||||
functionDescriptor = functionDescriptor.substitute(typeSubstitutorForGenericSuperclasses);
|
||||
}
|
||||
return functionDescriptor;
|
||||
}
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
FunctionDescriptorImpl functionDescriptorImpl = new FunctionDescriptorImpl(
|
||||
owner,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
method.getName()
|
||||
);
|
||||
methodDescriptorCache.put(method, functionDescriptorImpl);
|
||||
functionDescriptorImpl.initialize(
|
||||
null,
|
||||
resolveTypeParameters(functionDescriptorImpl, method.getTypeParameters()),
|
||||
semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters),
|
||||
semanticServices.getTypeTransformer().transformToType(returnType),
|
||||
Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL))
|
||||
);
|
||||
semanticServices.getTrace().record(BindingContext.FUNCTION, method, functionDescriptorImpl);
|
||||
FunctionDescriptor substitutedFunctionDescriptor = functionDescriptorImpl;
|
||||
if (method.getContainingClass() != psiClass) {
|
||||
substitutedFunctionDescriptor = functionDescriptorImpl.substitute(typeSubstitutorForGenericSuperclasses);
|
||||
}
|
||||
return substitutedFunctionDescriptor;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.AbstractNamespaceDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaNamespaceDescriptor extends AbstractNamespaceDescriptorImpl {
|
||||
private JetScope memberScope;
|
||||
|
||||
public JavaNamespaceDescriptor(DeclarationDescriptor containingDeclaration, List<AnnotationDescriptor> annotations, String name) {
|
||||
super(containingDeclaration, annotations, name);
|
||||
}
|
||||
|
||||
public void setMemberScope(@NotNull JetScope memberScope) {
|
||||
this.memberScope = memberScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetScope getMemberScope() {
|
||||
return memberScope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.JetScopeImpl;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaPackageScope extends JetScopeImpl {
|
||||
|
||||
private final JavaSemanticServices semanticServices;
|
||||
private final DeclarationDescriptor containingDescriptor;
|
||||
private final String packagePrefix;
|
||||
|
||||
public JavaPackageScope(@NotNull String packageFQN, DeclarationDescriptor containingDescriptor, JavaSemanticServices semanticServices) {
|
||||
this.semanticServices = semanticServices;
|
||||
this.packagePrefix = packageFQN.isEmpty() ? "" : packageFQN + ".";
|
||||
this.containingDescriptor = containingDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassifierDescriptor getClassifier(@NotNull String name) {
|
||||
return semanticServices.getDescriptorResolver().resolveClass(getQualifiedName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceDescriptor getNamespace(@NotNull String name) {
|
||||
return semanticServices.getDescriptorResolver().resolveNamespace(getQualifiedName(name));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionGroup getFunctionGroup(@NotNull String name) {
|
||||
// ClassifierDescriptor classifier = getClassifier(name);
|
||||
// if (classifier instanceof ClassDescriptor) {
|
||||
// ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
|
||||
// return classDescriptor.getConstructors();
|
||||
// }
|
||||
return FunctionGroup.EMPTY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor getContainingDeclaration() {
|
||||
return containingDescriptor;
|
||||
}
|
||||
|
||||
private String getQualifiedName(String name) {
|
||||
return packagePrefix + name;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaSemanticServices {
|
||||
private final JavaTypeTransformer typeTransformer;
|
||||
private final JavaDescriptorResolver descriptorResolver;
|
||||
private final BindingTrace trace;
|
||||
private final JetSemanticServices jetSemanticServices;
|
||||
|
||||
public JavaSemanticServices(Project project, JetSemanticServices jetSemanticServices, BindingTrace trace) {
|
||||
this.trace = trace;
|
||||
this.descriptorResolver = new JavaDescriptorResolver(project, this);
|
||||
this.typeTransformer = new JavaTypeTransformer(jetSemanticServices.getStandardLibrary(), descriptorResolver);
|
||||
this.jetSemanticServices = jetSemanticServices;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JavaTypeTransformer getTypeTransformer() {
|
||||
return typeTransformer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JavaDescriptorResolver getDescriptorResolver() {
|
||||
return descriptorResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BindingTrace getTrace() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
public JetSemanticServices getJetSemanticServices() {
|
||||
return jetSemanticServices;
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JavaTypeTransformer {
|
||||
|
||||
private final JavaDescriptorResolver resolver;
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private Map<String, JetType> primitiveTypesMap;
|
||||
private Map<String, JetType> classTypesMap;
|
||||
|
||||
public JavaTypeTransformer(JetStandardLibrary standardLibrary, JavaDescriptorResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
this.standardLibrary = standardLibrary;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TypeProjection transformToTypeProjection(@NotNull final PsiType javaType, @NotNull final TypeParameterDescriptor typeParameterDescriptor) {
|
||||
TypeProjection result = javaType.accept(new PsiTypeVisitor<TypeProjection>() {
|
||||
|
||||
@Override
|
||||
public TypeProjection visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeProjection visitWildcardType(PsiWildcardType wildcardType) {
|
||||
if (!wildcardType.isBounded()) {
|
||||
return TypeUtils.makeStarProjection(typeParameterDescriptor);
|
||||
}
|
||||
Variance variance = wildcardType.isExtends() ? Variance.OUT_VARIANCE : Variance.IN_VARIANCE;
|
||||
|
||||
PsiType bound = wildcardType.getBound();
|
||||
assert bound != null;
|
||||
return new TypeProjection(variance, transformToType(bound));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeProjection visitType(PsiType type) {
|
||||
return new TypeProjection(transformToType(type));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType transformToType(@NotNull PsiType javaType) {
|
||||
return javaType.accept(new PsiTypeVisitor<JetType>() {
|
||||
@Override
|
||||
public JetType visitClassType(PsiClassType classType) {
|
||||
PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
|
||||
PsiClass psiClass = classResolveResult.getElement();
|
||||
if (psiClass == null) {
|
||||
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
||||
}
|
||||
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass;
|
||||
TypeParameterDescriptor typeParameterDescriptor = resolver.resolveTypeParameter(JavaDescriptorResolver.JAVA_ROOT, typeParameter);
|
||||
return typeParameterDescriptor.getDefaultType();
|
||||
}
|
||||
else {
|
||||
JetType jetAnalog = getClassTypesMap().get(psiClass.getQualifiedName());
|
||||
if (jetAnalog != null) {
|
||||
return jetAnalog;
|
||||
}
|
||||
|
||||
ClassDescriptor descriptor = resolver.resolveClass(psiClass);
|
||||
|
||||
List<TypeProjection> arguments = Lists.newArrayList();
|
||||
if (classType.isRaw()) {
|
||||
List<TypeParameterDescriptor> parameters = descriptor.getTypeConstructor().getParameters();
|
||||
for (TypeParameterDescriptor parameter : parameters) {
|
||||
arguments.add(TypeUtils.makeStarProjection(parameter));
|
||||
}
|
||||
} else {
|
||||
PsiType[] psiArguments = classType.getParameters();
|
||||
for (int i = 0, psiArgumentsLength = psiArguments.length; i < psiArgumentsLength; i++) {
|
||||
PsiType psiArgument = psiArguments[i];
|
||||
TypeParameterDescriptor typeParameterDescriptor = descriptor.getTypeConstructor().getParameters().get(i);
|
||||
arguments.add(transformToTypeProjection(psiArgument, typeParameterDescriptor));
|
||||
}
|
||||
}
|
||||
return new JetTypeImpl(
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
descriptor.getTypeConstructor(),
|
||||
true,
|
||||
arguments,
|
||||
descriptor.getMemberScope(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitPrimitiveType(PsiPrimitiveType primitiveType) {
|
||||
String canonicalText = primitiveType.getCanonicalText();
|
||||
JetType type = getPrimitiveTypesMap().get(canonicalText);
|
||||
assert type != null : canonicalText;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitArrayType(PsiArrayType arrayType) {
|
||||
JetType type = transformToType(arrayType.getComponentType());
|
||||
return TypeUtils.makeNullable(standardLibrary.getArrayType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitType(PsiType type) {
|
||||
throw new UnsupportedOperationException("Unsupported type: " + type.getPresentableText()); // TODO
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Map<String, JetType> getPrimitiveTypesMap() {
|
||||
if (primitiveTypesMap == null) {
|
||||
primitiveTypesMap = new HashMap<String, JetType>();
|
||||
primitiveTypesMap.put("byte", standardLibrary.getByteType());
|
||||
primitiveTypesMap.put("short", standardLibrary.getShortType());
|
||||
primitiveTypesMap.put("char", standardLibrary.getCharType());
|
||||
primitiveTypesMap.put("int", standardLibrary.getIntType());
|
||||
primitiveTypesMap.put("long", standardLibrary.getLongType());
|
||||
primitiveTypesMap.put("float", standardLibrary.getFloatType());
|
||||
primitiveTypesMap.put("double", standardLibrary.getDoubleType());
|
||||
primitiveTypesMap.put("boolean", standardLibrary.getBooleanType());
|
||||
primitiveTypesMap.put("void", JetStandardClasses.getUnitType());
|
||||
primitiveTypesMap.put("java.lang.Byte", TypeUtils.makeNullable(standardLibrary.getByteType()));
|
||||
primitiveTypesMap.put("java.lang.Short", TypeUtils.makeNullable(standardLibrary.getShortType()));
|
||||
primitiveTypesMap.put("java.lang.Character", TypeUtils.makeNullable(standardLibrary.getCharType()));
|
||||
primitiveTypesMap.put("java.lang.Integer", TypeUtils.makeNullable(standardLibrary.getIntType()));
|
||||
primitiveTypesMap.put("java.lang.Long", TypeUtils.makeNullable(standardLibrary.getLongType()));
|
||||
primitiveTypesMap.put("java.lang.Float", TypeUtils.makeNullable(standardLibrary.getFloatType()));
|
||||
primitiveTypesMap.put("java.lang.Double", TypeUtils.makeNullable(standardLibrary.getDoubleType()));
|
||||
primitiveTypesMap.put("java.lang.Boolean", TypeUtils.makeNullable(standardLibrary.getBooleanType()));
|
||||
}
|
||||
return primitiveTypesMap;
|
||||
}
|
||||
|
||||
public Map<String, JetType> getClassTypesMap() {
|
||||
if (classTypesMap == null) {
|
||||
classTypesMap = new HashMap<String, JetType>();
|
||||
classTypesMap.put("java.lang.Byte", TypeUtils.makeNullable(standardLibrary.getByteType()));
|
||||
classTypesMap.put("java.lang.Short", TypeUtils.makeNullable(standardLibrary.getShortType()));
|
||||
classTypesMap.put("java.lang.Character", TypeUtils.makeNullable(standardLibrary.getCharType()));
|
||||
classTypesMap.put("java.lang.Integer", TypeUtils.makeNullable(standardLibrary.getIntType()));
|
||||
classTypesMap.put("java.lang.Long", TypeUtils.makeNullable(standardLibrary.getLongType()));
|
||||
classTypesMap.put("java.lang.Float", TypeUtils.makeNullable(standardLibrary.getFloatType()));
|
||||
classTypesMap.put("java.lang.Double", TypeUtils.makeNullable(standardLibrary.getDoubleType()));
|
||||
classTypesMap.put("java.lang.Boolean", TypeUtils.makeNullable(standardLibrary.getBooleanType()));
|
||||
classTypesMap.put("java.lang.Object", JetStandardClasses.getNullableAnyType());
|
||||
classTypesMap.put("java.lang.String", standardLibrary.getNullableStringType());
|
||||
}
|
||||
return classTypesMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<project name="Lexer" default="lexer">
|
||||
<property name="home" value="${basedir}"/>
|
||||
<property file="${home}/idea.properties"/>
|
||||
|
||||
<property name="flex.base" value="${idea.home}/tools/lexer/jflex-1.4"/>
|
||||
<property name="out.dir" value="${basedir}/tmpout"/>
|
||||
|
||||
<macrodef name="flex">
|
||||
<attribute name="flexfile"/>
|
||||
<attribute name="destdir"/>
|
||||
<attribute name="skeleton" default="${idea.home}/tools/lexer/idea-flex.skeleton"/>
|
||||
<sequential>
|
||||
<delete dir="${out.dir}"/>
|
||||
<mkdir dir="${out.dir}"/>
|
||||
<java classname="JFlex.Main"
|
||||
jvmargs="-Xmx512M"
|
||||
fork="true"
|
||||
failonerror="true">
|
||||
<arg value="-sliceandcharat"/>
|
||||
<arg value="-skel"/>
|
||||
<arg value="@{skeleton}"/>
|
||||
<arg value="-d"/>
|
||||
<arg value="${out.dir}"/>
|
||||
<arg value="@{flexfile}"/>
|
||||
<classpath>
|
||||
<pathelement location="${flex.base}/lib/JFlex.jar"/>
|
||||
</classpath>
|
||||
</java>
|
||||
<move todir="@{destdir}">
|
||||
<fileset dir="${out.dir}">
|
||||
<include name="*.java"/>
|
||||
</fileset>
|
||||
</move>
|
||||
<delete dir="${out.dir}"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<target name="lexer">
|
||||
<echo message="${flex.base}"/>
|
||||
<flex flexfile="${home}/src/org/jetbrains/jet/lexer/Jet.flex"
|
||||
destdir="${home}//src/org/jetbrains/jet/lexer/"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA 10.x" jdkType="IDEA JDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
namespace jet
|
||||
|
||||
namespace typeinfo {
|
||||
class TypeInfo<T> {
|
||||
fun isSubtypeOf(other : TypeInfo<*>) : Boolean
|
||||
fun isInstance(obj : Any?) : Boolean
|
||||
}
|
||||
|
||||
fun typeinfo<T>() : TypeInfo<T>
|
||||
fun typeinfo<T>(expression : T) : TypeInfo<out T>
|
||||
}
|
||||
|
||||
namespace io {
|
||||
fun print(message : Any?)
|
||||
fun print(message : Int)
|
||||
fun print(message : Long)
|
||||
fun print(message : Byte)
|
||||
fun print(message : Short)
|
||||
fun print(message : Char)
|
||||
fun print(message : Boolean)
|
||||
fun print(message : Float)
|
||||
fun print(message : Double)
|
||||
|
||||
fun println(message : Any?)
|
||||
fun println(message : Int)
|
||||
fun println(message : Long)
|
||||
fun println(message : Byte)
|
||||
fun println(message : Short)
|
||||
fun println(message : Char)
|
||||
fun println(message : Boolean)
|
||||
fun println(message : Float)
|
||||
fun println(message : Double)
|
||||
|
||||
fun readLine() : String?
|
||||
}
|
||||
|
||||
// Can't write a body due to a bootstrapping problem (see JET-74)
|
||||
fun Any?.equals(other : Any?) : Boolean// = this === other
|
||||
|
||||
// Returns "null" for null
|
||||
fun Any?.toString() : String// = this === other
|
||||
|
||||
trait Iterator<out T> {
|
||||
fun next() : T
|
||||
abstract fun hasNext() : Boolean
|
||||
}
|
||||
|
||||
trait Iterable<out T> {
|
||||
fun iterator() : Iterator<T>
|
||||
}
|
||||
|
||||
class Array<T>(val size : Int) {
|
||||
fun get(index : Int) : T
|
||||
fun set(index : Int, value : T) : Unit
|
||||
|
||||
fun iterator() : Iterator<T>
|
||||
}
|
||||
|
||||
trait Comparable<in T> {
|
||||
fun compareTo(other : T) : Int
|
||||
}
|
||||
|
||||
trait Hashable {
|
||||
fun hashCode() : Int
|
||||
fun equals(other : Any?) : Boolean
|
||||
}
|
||||
|
||||
class Boolean : Comparable<Boolean> {
|
||||
fun not() : Boolean
|
||||
|
||||
fun xor(other : Boolean) : Boolean
|
||||
|
||||
fun equals(other : Any?) : Boolean
|
||||
}
|
||||
|
||||
class String() : Comparable<String> {
|
||||
fun get(index : Int) : Char
|
||||
val length : Int
|
||||
|
||||
fun plus(other : Any?) : String
|
||||
|
||||
fun equals(other : Any?) : Boolean
|
||||
fun equalsIgnoreCase(other: String?) : Boolean
|
||||
|
||||
fun substring(start: Int): String
|
||||
fun substring(start: Int, end: Int): String
|
||||
|
||||
fun startsWith(prefix: String, toffset: Int): Boolean
|
||||
fun startsWith(prefix: String): Boolean
|
||||
fun endsWith(suffix: String): Boolean
|
||||
|
||||
fun trim(): String
|
||||
}
|
||||
|
||||
trait Range<in T : Comparable<T>> {
|
||||
fun contains(item : T) : Boolean
|
||||
}
|
||||
|
||||
class IntRange<T : Comparable<T>> : Range<T>, Iterable<T> {
|
||||
|
||||
}
|
||||
|
||||
abstract class Number : Hashable {
|
||||
abstract val dbl : Double
|
||||
abstract val flt : Float
|
||||
abstract val lng : Long
|
||||
abstract val int : Int
|
||||
abstract val chr : Char
|
||||
abstract val sht : Short
|
||||
abstract val byt : Byte
|
||||
// fun equals(other : Double) : Boolean
|
||||
// fun equals(other : Float) : Boolean
|
||||
// fun equals(other : Long) : Boolean
|
||||
// fun equals(other : Byte) : Boolean
|
||||
// fun equals(other : Int) : Boolean
|
||||
// fun equals(other : Short) : Boolean
|
||||
// fun equals(other : Char) : Boolean
|
||||
}
|
||||
|
||||
class Double : Number, Comparable<Double> {
|
||||
override fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Double
|
||||
fun plus(other : Long) : Double
|
||||
fun plus(other : Int) : Double
|
||||
fun plus(other : Short) : Double
|
||||
fun plus(other : Byte) : Double
|
||||
fun plus(other : Char) : Double
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Double
|
||||
fun minus(other : Long) : Double
|
||||
fun minus(other : Int) : Double
|
||||
fun minus(other : Short) : Double
|
||||
fun minus(other : Byte) : Double
|
||||
fun minus(other : Char) : Double
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Double
|
||||
fun times(other : Long) : Double
|
||||
fun times(other : Int) : Double
|
||||
fun times(other : Short) : Double
|
||||
fun times(other : Byte) : Double
|
||||
fun times(other : Char) : Double
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Double
|
||||
fun div(other : Long) : Double
|
||||
fun div(other : Int) : Double
|
||||
fun div(other : Short) : Double
|
||||
fun div(other : Byte) : Double
|
||||
fun div(other : Char) : Double
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Double
|
||||
fun mod(other : Long) : Double
|
||||
fun mod(other : Int) : Double
|
||||
fun mod(other : Short) : Double
|
||||
fun mod(other : Byte) : Double
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Double>
|
||||
fun rangeTo(other : Long) : Range<Double>
|
||||
fun rangeTo(other : Int) : Range<Double>
|
||||
fun rangeTo(other : Short) : Range<Double>
|
||||
fun rangeTo(other : Byte) : Range<Double>
|
||||
fun rangeTo(other : Char) : Range<Double>
|
||||
|
||||
fun inc() : Double
|
||||
fun dec() : Double
|
||||
fun plus() : Double
|
||||
fun minus() : Double
|
||||
}
|
||||
|
||||
class Float : Number, Comparable<Float> {
|
||||
fun compareTo(other : Double) : Int
|
||||
override fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Float
|
||||
fun plus(other : Int) : Float
|
||||
fun plus(other : Short) : Float
|
||||
fun plus(other : Byte) : Float
|
||||
fun plus(other : Char) : Float
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Float
|
||||
fun minus(other : Int) : Float
|
||||
fun minus(other : Short) : Float
|
||||
fun minus(other : Byte) : Float
|
||||
fun minus(other : Char) : Float
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Float
|
||||
fun times(other : Int) : Float
|
||||
fun times(other : Short) : Float
|
||||
fun times(other : Byte) : Float
|
||||
fun times(other : Char) : Float
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Float
|
||||
fun div(other : Int) : Float
|
||||
fun div(other : Short) : Float
|
||||
fun div(other : Byte) : Float
|
||||
fun div(other : Char) : Float
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Float
|
||||
fun mod(other : Int) : Float
|
||||
fun mod(other : Short) : Float
|
||||
fun mod(other : Byte) : Float
|
||||
fun mod(other : Char) : Float
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Float>
|
||||
fun rangeTo(other : Long) : Range<Double>
|
||||
fun rangeTo(other : Int) : Range<Double>
|
||||
fun rangeTo(other : Short) : Range<Float>
|
||||
fun rangeTo(other : Byte) : Range<Float>
|
||||
fun rangeTo(other : Char) : Range<Float>
|
||||
|
||||
fun inc() : Float
|
||||
fun dec() : Float
|
||||
fun plus() : Float
|
||||
fun minus() : Float
|
||||
}
|
||||
|
||||
class Long : Number, Comparable<Long> {
|
||||
fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
override fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Long
|
||||
fun plus(other : Int) : Long
|
||||
fun plus(other : Short) : Long
|
||||
fun plus(other : Byte) : Long
|
||||
fun plus(other : Char) : Long
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Long
|
||||
fun minus(other : Int) : Long
|
||||
fun minus(other : Short) : Long
|
||||
fun minus(other : Byte) : Long
|
||||
fun minus(other : Char) : Long
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Long
|
||||
fun times(other : Int) : Long
|
||||
fun times(other : Short) : Long
|
||||
fun times(other : Byte) : Long
|
||||
fun times(other : Char) : Long
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Long
|
||||
fun div(other : Int) : Long
|
||||
fun div(other : Short) : Long
|
||||
fun div(other : Byte) : Long
|
||||
fun div(other : Char) : Long
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Long
|
||||
fun mod(other : Int) : Long
|
||||
fun mod(other : Short) : Long
|
||||
fun mod(other : Byte) : Long
|
||||
fun mod(other : Char) : Long
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Double>
|
||||
fun rangeTo(other : Long) : IntRange<Long>
|
||||
fun rangeTo(other : Int) : IntRange<Long>
|
||||
fun rangeTo(other : Short) : IntRange<Long>
|
||||
fun rangeTo(other : Byte) : IntRange<Long>
|
||||
fun rangeTo(other : Char) : IntRange<Long>
|
||||
|
||||
fun inc() : Long
|
||||
fun dec() : Long
|
||||
fun plus() : Long
|
||||
fun minus() : Long
|
||||
|
||||
fun shl(bits : Int) : Long
|
||||
fun shr(bits : Int) : Long
|
||||
fun ushr(bits : Int) : Long
|
||||
fun and(other : Long) : Long
|
||||
fun or(other : Long) : Long
|
||||
fun xor(other : Long) : Long
|
||||
fun inv() : Long
|
||||
}
|
||||
|
||||
class Int : Number, Comparable<Int> {
|
||||
fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
override fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Long
|
||||
fun plus(other : Int) : Int
|
||||
fun plus(other : Short) : Int
|
||||
fun plus(other : Byte) : Int
|
||||
fun plus(other : Char) : Int
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Long
|
||||
fun minus(other : Int) : Int
|
||||
fun minus(other : Short) : Int
|
||||
fun minus(other : Byte) : Int
|
||||
fun minus(other : Char) : Int
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Long
|
||||
fun times(other : Int) : Int
|
||||
fun times(other : Short) : Int
|
||||
fun times(other : Byte) : Int
|
||||
fun times(other : Char) : Int
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Long
|
||||
fun div(other : Int) : Int
|
||||
fun div(other : Short) : Int
|
||||
fun div(other : Byte) : Int
|
||||
fun div(other : Char) : Int
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Long
|
||||
fun mod(other : Int) : Int
|
||||
fun mod(other : Short) : Int
|
||||
fun mod(other : Byte) : Int
|
||||
fun mod(other : Char) : Int
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Double>
|
||||
fun rangeTo(other : Long) : IntRange<Long>
|
||||
fun rangeTo(other : Int) : IntRange<Int>
|
||||
fun rangeTo(other : Short) : IntRange<Int>
|
||||
fun rangeTo(other : Byte) : IntRange<Int>
|
||||
fun rangeTo(other : Char) : IntRange<Int>
|
||||
|
||||
fun inc() : Int
|
||||
fun dec() : Int
|
||||
fun plus() : Int
|
||||
fun minus() : Int
|
||||
|
||||
fun shl(bits : Int) : Int
|
||||
fun shr(bits : Int) : Int
|
||||
fun ushr(bits : Int) : Int
|
||||
fun and(other : Int) : Int
|
||||
fun or(other : Int) : Int
|
||||
fun xor(other : Int) : Int
|
||||
fun inv() : Int
|
||||
}
|
||||
|
||||
class Char : Number, Comparable<Char> {
|
||||
fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
override fun compareTo(other : Char) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Long
|
||||
fun plus(other : Int) : Int
|
||||
fun plus(other : Short) : Int
|
||||
fun plus(other : Byte) : Int
|
||||
fun plus(other : Char) : Int
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Long
|
||||
fun minus(other : Int) : Int
|
||||
fun minus(other : Short) : Int
|
||||
fun minus(other : Byte) : Int
|
||||
fun minus(other : Char) : Int
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Long
|
||||
fun times(other : Int) : Int
|
||||
fun times(other : Short) : Int
|
||||
fun times(other : Byte) : Int
|
||||
fun times(other : Char) : Int
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Long
|
||||
fun div(other : Int) : Int
|
||||
fun div(other : Short) : Int
|
||||
fun div(other : Byte) : Int
|
||||
fun div(other : Char) : Int
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Long
|
||||
fun mod(other : Int) : Int
|
||||
fun mod(other : Short) : Int
|
||||
fun mod(other : Byte) : Int
|
||||
fun mod(other : Char) : Int
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Float>
|
||||
fun rangeTo(other : Long) : IntRange<Long>
|
||||
fun rangeTo(other : Int) : IntRange<Int>
|
||||
fun rangeTo(other : Short) : IntRange<Short>
|
||||
fun rangeTo(other : Byte) : IntRange<Byte>
|
||||
fun rangeTo(other : Char) : IntRange<Char>
|
||||
|
||||
fun inc() : Char
|
||||
fun dec() : Char
|
||||
fun plus() : Int
|
||||
fun minus() : Int
|
||||
}
|
||||
|
||||
class Short : Number, Comparable<Short> {
|
||||
fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
override fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Byte) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Long
|
||||
fun plus(other : Int) : Int
|
||||
fun plus(other : Short) : Int
|
||||
fun plus(other : Byte) : Int
|
||||
fun plus(other : Char) : Int
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Long
|
||||
fun minus(other : Int) : Int
|
||||
fun minus(other : Short) : Int
|
||||
fun minus(other : Byte) : Int
|
||||
fun minus(other : Char) : Int
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Long
|
||||
fun times(other : Int) : Int
|
||||
fun times(other : Short) : Int
|
||||
fun times(other : Byte) : Int
|
||||
fun times(other : Char) : Int
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Long
|
||||
fun div(other : Int) : Int
|
||||
fun div(other : Short) : Int
|
||||
fun div(other : Byte) : Int
|
||||
fun div(other : Char) : Int
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Long
|
||||
fun mod(other : Int) : Int
|
||||
fun mod(other : Short) : Int
|
||||
fun mod(other : Byte) : Int
|
||||
fun mod(other : Char) : Int
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Float>
|
||||
fun rangeTo(other : Long) : IntRange<Long>
|
||||
fun rangeTo(other : Int) : IntRange<Int>
|
||||
fun rangeTo(other : Short) : IntRange<Short>
|
||||
fun rangeTo(other : Byte) : IntRange<Short>
|
||||
fun rangeTo(other : Char) : IntRange<Int>
|
||||
|
||||
fun inc() : Short
|
||||
fun dec() : Short
|
||||
fun plus() : Int
|
||||
fun minus() : Int
|
||||
}
|
||||
|
||||
class Byte : Number, Comparable<Byte> {
|
||||
fun compareTo(other : Double) : Int
|
||||
fun compareTo(other : Float) : Int
|
||||
fun compareTo(other : Long) : Int
|
||||
fun compareTo(other : Int) : Int
|
||||
fun compareTo(other : Short) : Int
|
||||
fun compareTo(other : Char) : Int
|
||||
override fun compareTo(other : Byte) : Int
|
||||
|
||||
fun plus(other : Double) : Double
|
||||
fun plus(other : Float) : Float
|
||||
fun plus(other : Long) : Long
|
||||
fun plus(other : Int) : Int
|
||||
fun plus(other : Short) : Int
|
||||
fun plus(other : Byte) : Int
|
||||
fun plus(other : Char) : Int
|
||||
|
||||
fun minus(other : Double) : Double
|
||||
fun minus(other : Float) : Float
|
||||
fun minus(other : Long) : Long
|
||||
fun minus(other : Int) : Int
|
||||
fun minus(other : Short) : Int
|
||||
fun minus(other : Byte) : Int
|
||||
fun minus(other : Char) : Int
|
||||
|
||||
fun times(other : Double) : Double
|
||||
fun times(other : Float) : Float
|
||||
fun times(other : Long) : Long
|
||||
fun times(other : Int) : Int
|
||||
fun times(other : Short) : Int
|
||||
fun times(other : Byte) : Int
|
||||
fun times(other : Char) : Int
|
||||
|
||||
fun div(other : Double) : Double
|
||||
fun div(other : Float) : Float
|
||||
fun div(other : Long) : Long
|
||||
fun div(other : Int) : Int
|
||||
fun div(other : Short) : Int
|
||||
fun div(other : Byte) : Int
|
||||
fun div(other : Char) : Int
|
||||
|
||||
fun mod(other : Double) : Double
|
||||
fun mod(other : Float) : Float
|
||||
fun mod(other : Long) : Long
|
||||
fun mod(other : Int) : Int
|
||||
fun mod(other : Short) : Int
|
||||
fun mod(other : Byte) : Int
|
||||
fun mod(other : Char) : Int
|
||||
|
||||
fun rangeTo(other : Double) : Range<Double>
|
||||
fun rangeTo(other : Float) : Range<Float>
|
||||
fun rangeTo(other : Long) : IntRange<Long>
|
||||
fun rangeTo(other : Int) : IntRange<Int>
|
||||
fun rangeTo(other : Short) : IntRange<Short>
|
||||
fun rangeTo(other : Byte) : IntRange<Byte>
|
||||
fun rangeTo(other : Char) : IntRange<Int>
|
||||
|
||||
fun inc() : Byte
|
||||
fun dec() : Byte
|
||||
fun plus() : Int
|
||||
fun minus() : Int
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class JetNodeType extends IElementType {
|
||||
private Constructor<? extends JetElement> myPsiFactory;
|
||||
|
||||
public JetNodeType(@NotNull @NonNls String debugName) {
|
||||
this(debugName, null);
|
||||
}
|
||||
|
||||
public JetNodeType(@NotNull @NonNls String debugName, Class<? extends JetElement> psiClass) {
|
||||
super(debugName, JetLanguage.INSTANCE);
|
||||
try {
|
||||
myPsiFactory = psiClass != null ? psiClass.getConstructor(ASTNode.class) : null;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Must have a constructor with ASTNode");
|
||||
}
|
||||
}
|
||||
|
||||
public JetElement createPsi(ASTNode node) {
|
||||
assert node.getElementType() == this;
|
||||
|
||||
try {
|
||||
if (myPsiFactory == null) {
|
||||
return new JetElement(node);
|
||||
}
|
||||
return myPsiFactory.newInstance(node);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error creating psi element for node", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet;
|
||||
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
public interface JetNodeTypes {
|
||||
IFileElementType JET_FILE = new IFileElementType(JetLanguage.INSTANCE);
|
||||
|
||||
JetNodeType NAMESPACE = new JetNodeType("NAMESPACE", JetNamespace.class);
|
||||
JetNodeType CLASS = new JetNodeType("CLASS", JetClass.class);
|
||||
JetNodeType PROPERTY = new JetNodeType("PROPERTY", JetProperty.class);
|
||||
JetNodeType FUN = new JetNodeType("FUN", JetNamedFunction.class);
|
||||
JetNodeType TYPEDEF = new JetNodeType("TYPEDEF", JetTypedef.class);
|
||||
JetNodeType OBJECT_DECLARATION = new JetNodeType("OBJECT_DECLARATION", JetObjectDeclaration.class);
|
||||
JetNodeType OBJECT_DECLARATION_NAME = new JetNodeType("OBJECT_DECLARATION_NAME", JetObjectDeclarationName.class);
|
||||
|
||||
JetNodeType CLASS_OBJECT = new JetNodeType("CLASS_OBJECT", JetClassObject.class);
|
||||
JetNodeType CONSTRUCTOR = new JetNodeType("CONSTRUCTOR", JetConstructor.class);
|
||||
JetNodeType ENUM_ENTRY = new JetNodeType("ENUM_ENTRY", JetEnumEntry.class);
|
||||
JetNodeType ANONYMOUS_INITIALIZER = new JetNodeType("ANONYMOUS_INITIALIZER", JetClassInitializer.class);
|
||||
|
||||
JetNodeType TYPE_PARAMETER_LIST = new JetNodeType("TYPE_PARAMETER_LIST", JetTypeParameterList.class);
|
||||
JetNodeType TYPE_PARAMETER = new JetNodeType("TYPE_PARAMETER", JetTypeParameter.class);
|
||||
JetNodeType DELEGATION_SPECIFIER_LIST = new JetNodeType("DELEGATION_SPECIFIER_LIST", JetDelegationSpecifierList.class);
|
||||
JetNodeType DELEGATOR_BY = new JetNodeType("DELEGATOR_BY", JetDelegatorByExpressionSpecifier.class);
|
||||
JetNodeType DELEGATOR_SUPER_CALL = new JetNodeType("DELEGATOR_SUPER_CALL", JetDelegatorToSuperCall.class);
|
||||
JetNodeType DELEGATOR_SUPER_CLASS = new JetNodeType("DELEGATOR_SUPER_CLASS", JetDelegatorToSuperClass.class);
|
||||
JetNodeType CONSTRUCTOR_CALLEE = new JetNodeType("CONSTRUCTOR_CALLEE", JetConstructorCalleeExpression.class);
|
||||
JetNodeType VALUE_PARAMETER_LIST = new JetNodeType("VALUE_PARAMETER_LIST", JetParameterList.class);
|
||||
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER", JetParameter.class);
|
||||
|
||||
JetNodeType CLASS_BODY = new JetNodeType("CLASS_BODY", JetClassBody.class);
|
||||
JetNodeType IMPORT_DIRECTIVE = new JetNodeType("IMPORT_DIRECTIVE", JetImportDirective.class);
|
||||
JetNodeType NAMESPACE_BODY = new JetNodeType("NAMESPACE_BODY", JetNamespaceBody.class);
|
||||
JetNodeType MODIFIER_LIST = new JetNodeType("MODIFIER_LIST", JetModifierList.class);
|
||||
JetNodeType PRIMARY_CONSTRUCTOR_MODIFIER_LIST = new JetNodeType("PRIMARY_CONSTRUCTOR_MODIFIER_LIST", JetModifierList.class);
|
||||
JetNodeType ANNOTATION = new JetNodeType("ANNOTATION", JetAnnotation.class);
|
||||
JetNodeType ANNOTATION_ENTRY = new JetNodeType("ANNOTATION_ENTRY", JetAnnotationEntry.class);
|
||||
|
||||
JetNodeType TYPE_ARGUMENT_LIST = new JetNodeType("TYPE_ARGUMENT_LIST", JetTypeArgumentList.class);
|
||||
JetNodeType VALUE_ARGUMENT_LIST = new JetNodeType("VALUE_ARGUMENT_LIST", JetValueArgumentList.class);
|
||||
JetNodeType VALUE_ARGUMENT = new JetNodeType("VALUE_ARGUMENT", JetValueArgument.class);
|
||||
JetNodeType VALUE_ARGUMENT_NAME = new JetNodeType("VALUE_ARGUMENT_NAME", JetValueArgumentName.class);
|
||||
JetNodeType TYPE_REFERENCE = new JetNodeType("TYPE_REFERENCE", JetTypeReference.class);
|
||||
JetNodeType LABELED_TUPLE_ENTRY = new JetNodeType("LABELED_TUPLE_ENTRY");
|
||||
JetNodeType LABELED_TUPLE_TYPE_ENTRY = new JetNodeType("LABELED_TUPLE_TYPE_ENTRY");
|
||||
|
||||
JetNodeType USER_TYPE = new JetNodeType("USER_TYPE", JetUserType.class);
|
||||
JetNodeType TUPLE_TYPE = new JetNodeType("TUPLE_TYPE", JetTupleType.class);
|
||||
JetNodeType FUNCTION_TYPE = new JetNodeType("FUNCTION_TYPE", JetFunctionType.class);
|
||||
JetNodeType SELF_TYPE = new JetNodeType("SELF_TYPE", JetSelfType.class);
|
||||
JetNodeType NULLABLE_TYPE = new JetNodeType("NULLABLE_TYPE", JetNullableType.class);
|
||||
JetNodeType TYPE_PROJECTION = new JetNodeType("TYPE_PROJECTION", JetTypeProjection.class);
|
||||
|
||||
// TODO: review
|
||||
JetNodeType PROPERTY_ACCESSOR = new JetNodeType("PROPERTY_ACCESSOR", JetPropertyAccessor.class);
|
||||
JetNodeType INITIALIZER_LIST = new JetNodeType("INITIALIZER_LIST", JetInitializerList.class);
|
||||
JetNodeType THIS_CALL = new JetNodeType("THIS_CALL", JetDelegatorToThisCall.class);
|
||||
JetNodeType THIS_CONSTRUCTOR_REFERENCE = new JetNodeType("THIS_CONSTRUCTOR_REFERENCE", JetThisReferenceExpression.class);
|
||||
JetNodeType TYPE_CONSTRAINT_LIST = new JetNodeType("TYPE_CONSTRAINT_LIST", JetTypeConstraintList.class);
|
||||
JetNodeType TYPE_CONSTRAINT = new JetNodeType("TYPE_CONSTRAINT", JetTypeConstraint.class);
|
||||
|
||||
// TODO: Not sure if we need separate NT for each kind of constants
|
||||
JetNodeType NULL = new JetNodeType("NULL", JetConstantExpression.class);
|
||||
JetNodeType BOOLEAN_CONSTANT = new JetNodeType("BOOLEAN_CONSTANT", JetConstantExpression.class);
|
||||
JetNodeType FLOAT_CONSTANT = new JetNodeType("FLOAT_CONSTANT", JetConstantExpression.class);
|
||||
JetNodeType CHARACTER_CONSTANT = new JetNodeType("CHARACTER_CONSTANT", JetConstantExpression.class);
|
||||
JetNodeType RAW_STRING_CONSTANT = new JetNodeType("STRING_CONSTANT", JetConstantExpression.class);
|
||||
JetNodeType INTEGER_CONSTANT = new JetNodeType("INTEGER_CONSTANT", JetConstantExpression.class);
|
||||
|
||||
JetNodeType STRING_TEMPLATE = new JetNodeType("STRING_TEMPLATE", JetStringTemplateExpression.class);
|
||||
JetNodeType LONG_STRING_TEMPLATE_ENTRY = new JetNodeType("LONG_STRING_TEMPLATE_ENTRY", JetBlockStringTemplateEntry.class);
|
||||
JetNodeType SHORT_STRING_TEMPLATE_ENTRY = new JetNodeType("SHORT_STRING_TEMPLATE_ENTRY", JetSimpleNameStringTemplateEntry.class);
|
||||
JetNodeType LITERAL_STRING_TEMPLATE_ENTRY = new JetNodeType("LITERAL_STRING_TEMPLATE_ENTRY", JetLiteralStringTemplateEntry.class);
|
||||
JetNodeType ESCAPE_STRING_TEMPLATE_ENTRY = new JetNodeType("ESCAPE_STRING_TEMPLATE_ENTRY", JetEscapeStringTemplateEntry.class);
|
||||
|
||||
JetNodeType TUPLE = new JetNodeType("TUPLE", JetTupleExpression.class);
|
||||
JetNodeType PARENTHESIZED = new JetNodeType("PARENTHESIZED", JetParenthesizedExpression.class);
|
||||
JetNodeType RETURN = new JetNodeType("RETURN", JetReturnExpression.class);
|
||||
JetNodeType THROW = new JetNodeType("THROW", JetThrowExpression.class);
|
||||
JetNodeType CONTINUE = new JetNodeType("CONTINUE", JetContinueExpression.class);
|
||||
JetNodeType BREAK = new JetNodeType("BREAK", JetBreakExpression.class);
|
||||
JetNodeType IF = new JetNodeType("IF", JetIfExpression.class);
|
||||
JetNodeType CONDITION = new JetNodeType("CONDITION", JetContainerNode.class);
|
||||
JetNodeType THEN = new JetNodeType("THEN", JetContainerNode.class);
|
||||
JetNodeType ELSE = new JetNodeType("ELSE", JetContainerNode.class);
|
||||
JetNodeType TRY = new JetNodeType("TRY", JetTryExpression.class);
|
||||
JetNodeType CATCH = new JetNodeType("CATCH", JetCatchClause.class);
|
||||
JetNodeType FINALLY = new JetNodeType("FINALLY", JetFinallySection.class);
|
||||
JetNodeType FOR = new JetNodeType("FOR", JetForExpression.class);
|
||||
JetNodeType WHILE = new JetNodeType("WHILE", JetWhileExpression.class);
|
||||
JetNodeType DO_WHILE = new JetNodeType("DO_WHILE", JetDoWhileExpression.class);
|
||||
JetNodeType LOOP_PARAMETER = new JetNodeType("LOOP_PARAMETER", JetParameter.class); // TODO: Do we need separate type?
|
||||
JetNodeType LOOP_RANGE = new JetNodeType("LOOP_RANGE", JetContainerNode.class);
|
||||
JetNodeType BODY = new JetNodeType("BODY", JetContainerNode.class);
|
||||
JetNodeType BLOCK = new JetNodeType("BLOCK", JetBlockExpression.class);
|
||||
JetNodeType FUNCTION_LITERAL_EXPRESSION = new JetNodeType("FUNCTION_LITERAL_EXPRESSION", JetFunctionLiteralExpression.class);
|
||||
JetNodeType FUNCTION_LITERAL = new JetNodeType("FUNCTION_LITERAL", JetFunctionLiteral.class);
|
||||
JetNodeType ANNOTATED_EXPRESSION = new JetNodeType("ANNOTATED_EXPRESSION", JetAnnotatedExpression.class);
|
||||
|
||||
JetNodeType REFERENCE_EXPRESSION = new JetNodeType("REFERENCE_EXPRESSION", JetSimpleNameExpression.class);
|
||||
JetNodeType OPERATION_REFERENCE = new JetNodeType("OPERATION_REFERENCE", JetSimpleNameExpression.class);
|
||||
JetNodeType LABEL_REFERENCE = new JetNodeType("LABEL_REFERENCE", JetSimpleNameExpression.class);
|
||||
|
||||
JetNodeType LABEL_QUALIFIER = new JetNodeType("LABEL_QUALIFIER", JetContainerNode.class);
|
||||
|
||||
JetNodeType THIS_EXPRESSION = new JetNodeType("THIS_EXPRESSION", JetThisExpression.class);
|
||||
JetNodeType BINARY_EXPRESSION = new JetNodeType("BINARY_EXPRESSION", JetBinaryExpression.class);
|
||||
JetNodeType BINARY_WITH_TYPE = new JetNodeType("BINARY_WITH_TYPE", JetBinaryExpressionWithTypeRHS.class);
|
||||
JetNodeType BINARY_WITH_PATTERN = new JetNodeType("BINARY_WITH_PATTERN", JetIsExpression.class); // TODO:
|
||||
JetNodeType PREFIX_EXPRESSION = new JetNodeType("PREFIX_EXPRESSION", JetPrefixExpression.class);
|
||||
JetNodeType POSTFIX_EXPRESSION = new JetNodeType("POSTFIX_EXPRESSION", JetPostfixExpression.class);
|
||||
JetNodeType CALL_EXPRESSION = new JetNodeType("CALL_EXPRESSION", JetCallExpression.class);
|
||||
JetNodeType ARRAY_ACCESS_EXPRESSION = new JetNodeType("ARRAY_ACCESS_EXPRESSION", JetArrayAccessExpression.class);
|
||||
JetNodeType INDICES = new JetNodeType("INDICES", JetContainerNode.class);
|
||||
JetNodeType DOT_QUALIFIED_EXPRESSION = new JetNodeType("DOT_QUALIFIED_EXPRESSION", JetDotQualifiedExpression.class);
|
||||
JetNodeType HASH_QUALIFIED_EXPRESSION = new JetNodeType("HASH_QUALIFIED_EXPRESSION", JetHashQualifiedExpression.class);
|
||||
JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class);
|
||||
JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class);
|
||||
|
||||
JetNodeType OBJECT_LITERAL = new JetNodeType("OBJECT_LITERAL", JetObjectLiteralExpression.class);
|
||||
JetNodeType ROOT_NAMESPACE = new JetNodeType("ROOT_NAMESPACE", JetRootNamespaceExpression.class);
|
||||
|
||||
JetNodeType EXPRESSION_PATTERN = new JetNodeType("EXPRESSION_PATTERN", JetExpressionPattern.class);
|
||||
JetNodeType TYPE_PATTERN = new JetNodeType("TYPE_PATTERN", JetTypePattern.class);
|
||||
JetNodeType WILDCARD_PATTERN = new JetNodeType("WILDCARD_PATTERN", JetWildcardPattern.class);
|
||||
JetNodeType BINDING_PATTERN = new JetNodeType("BINDING_PATTERN", JetBindingPattern.class);
|
||||
JetNodeType TUPLE_PATTERN = new JetNodeType("TUPLE_PATTERN", JetTuplePattern.class);
|
||||
JetNodeType TUPLE_PATTERN_ENTRY = new JetNodeType("TUPLE_PATTERN_ENTRY", JetTuplePatternEntry.class);
|
||||
JetNodeType DECOMPOSER_PATTERN = new JetNodeType("DECOMPOSER_PATTERN", JetDecomposerPattern.class);
|
||||
JetNodeType DECOMPOSER_ARGUMENT_LIST = new JetNodeType("DECOMPOSER_ARGUMENT_LIST", JetTuplePattern.class);
|
||||
JetNodeType DECOMPOSER_ARGUMENT = TUPLE_PATTERN_ENTRY;
|
||||
|
||||
JetNodeType WHEN = new JetNodeType("WHEN", JetWhenExpression.class);
|
||||
JetNodeType WHEN_ENTRY = new JetNodeType("WHEN_ENTRY", JetWhenEntry.class);
|
||||
|
||||
JetNodeType WHEN_CONDITION_IN_RANGE = new JetNodeType("WHEN_CONDITION_IN_RANGE", JetWhenConditionInRange.class);
|
||||
JetNodeType WHEN_CONDITION_IS_PATTERN = new JetNodeType("WHEN_CONDITION_IS_PATTERN", JetWhenConditionIsPattern.class);
|
||||
JetNodeType WHEN_CONDITION_CALL = new JetNodeType("WHEN_CONDITION_CALL", JetWhenConditionCall.class);
|
||||
|
||||
JetNodeType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME", JetContainerNode.class);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class CollectingErrorHandler extends ErrorHandler {
|
||||
private final List<JetDiagnostic> diagnostics;
|
||||
|
||||
public CollectingErrorHandler() {
|
||||
this(Lists.<JetDiagnostic>newArrayList());
|
||||
}
|
||||
|
||||
public CollectingErrorHandler(List<JetDiagnostic> diagnostics) {
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
public List<JetDiagnostic> getDiagnostics() {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||
diagnostics.add(new JetDiagnostic.UnresolvedReferenceError(referenceExpression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
diagnostics.add(new JetDiagnostic.TypeMismatchError(expression, expectedType, actualType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
diagnostics.add(new JetDiagnostic.RedeclarationError(existingDescriptor, redeclaredDescriptor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||
diagnostics.add(new JetDiagnostic.GenericError(node, errorMessage));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||
diagnostics.add(new JetDiagnostic.GenericWarning(node, message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class CompositeErrorHandler extends ErrorHandler {
|
||||
private final ErrorHandler[] handlers;
|
||||
|
||||
public CompositeErrorHandler(ErrorHandler... handlers) {
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||
for (ErrorHandler handler : handlers) {
|
||||
handler.unresolvedReference(referenceExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
for (ErrorHandler handler : handlers) {
|
||||
handler.typeMismatch(expression, expectedType, actualType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
for (ErrorHandler handler : handlers) {
|
||||
handler.redeclaration(existingDescriptor, redeclaredDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||
for (ErrorHandler handler : handlers) {
|
||||
handler.genericError(node, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||
for (ErrorHandler handler : handlers) {
|
||||
handler.genericWarning(node, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ErrorHandler {
|
||||
public static final ErrorHandler DO_NOTHING = new ErrorHandler();
|
||||
public static final ErrorHandler THROW_EXCEPTION = new ErrorHandler() {
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||
throw new IllegalStateException("Unresolved reference: " + referenceExpression.getText() +
|
||||
atLocation(referenceExpression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||
throw new IllegalStateException(errorMessage + " at " + node.getText() + atLocation(node));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
throw new IllegalStateException("Type mismatch " + atLocation(expression) + ": inferred type is " + actualType + " but " + expectedType + " was expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
throw new IllegalStateException("Redeclaration: " + existingDescriptor.getName());
|
||||
}
|
||||
};
|
||||
|
||||
public static String atLocation(@NotNull PsiElement element) {
|
||||
return atLocation(element.getNode());
|
||||
}
|
||||
|
||||
public static String atLocation(@NotNull ASTNode node) {
|
||||
while (node.getPsi() == null) {
|
||||
node = node.getTreeParent();
|
||||
}
|
||||
PsiElement element = node.getPsi();
|
||||
Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(element.getContainingFile());
|
||||
int offset = element.getTextRange().getStartOffset();
|
||||
if (document != null) {
|
||||
int lineNumber = document.getLineNumber(offset);
|
||||
int lineStartOffset = document.getLineStartOffset(lineNumber);
|
||||
int column = offset - lineStartOffset;
|
||||
|
||||
return "' at line " + (lineNumber+1) + ":" + column;
|
||||
}
|
||||
else {
|
||||
return "' at offset " + offset + " (line unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) {
|
||||
Collection<JetDiagnostic> diagnostics = bindingContext.getDiagnostics();
|
||||
applyHandler(errorHandler, diagnostics);
|
||||
}
|
||||
|
||||
public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull Collection<JetDiagnostic> diagnostics) {
|
||||
for (JetDiagnostic jetDiagnostic : diagnostics) {
|
||||
jetDiagnostic.acceptHandler(errorHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||
}
|
||||
|
||||
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
}
|
||||
|
||||
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
}
|
||||
|
||||
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||
}
|
||||
|
||||
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ErrorHandlerAdapter extends ErrorHandler {
|
||||
protected ErrorHandler worker;
|
||||
|
||||
public ErrorHandlerAdapter(ErrorHandler worker) {
|
||||
this.worker = worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
|
||||
worker.unresolvedReference(referenceExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
worker.typeMismatch(expression, expectedType, actualType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
worker.redeclaration(existingDescriptor, redeclaredDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
|
||||
worker.genericError(node, errorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||
worker.genericWarning(node, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class JetDiagnostic {
|
||||
|
||||
public static class UnresolvedReferenceError extends JetDiagnostic {
|
||||
|
||||
private final JetReferenceExpression referenceExpression;
|
||||
|
||||
public UnresolvedReferenceError(@NotNull JetReferenceExpression referenceExpression) {
|
||||
this.referenceExpression = referenceExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptHandler(@NotNull ErrorHandler handler) {
|
||||
handler.unresolvedReference(referenceExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetReferenceExpression getReferenceExpression() {
|
||||
return referenceExpression;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericError extends JetDiagnostic {
|
||||
|
||||
private final ASTNode node;
|
||||
private final String message;
|
||||
|
||||
public GenericError(@NotNull ASTNode node, @NotNull String message) {
|
||||
this.node = node;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptHandler(@NotNull ErrorHandler handler) {
|
||||
handler.genericError(node, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeMismatchError extends JetDiagnostic {
|
||||
|
||||
private final JetExpression expression;
|
||||
private final JetType expectedType;
|
||||
private final JetType actualType;
|
||||
|
||||
public TypeMismatchError(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
|
||||
this.expression = expression;
|
||||
this.expectedType = expectedType;
|
||||
this.actualType = actualType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptHandler(@NotNull ErrorHandler handler) {
|
||||
handler.typeMismatch(expression, expectedType, actualType);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RedeclarationError extends JetDiagnostic {
|
||||
|
||||
private final DeclarationDescriptor existingDescriptor;
|
||||
private final DeclarationDescriptor redeclaredDescriptor;
|
||||
|
||||
public RedeclarationError(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
|
||||
this.existingDescriptor = existingDescriptor;
|
||||
this.redeclaredDescriptor = redeclaredDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptHandler(@NotNull ErrorHandler handler) {
|
||||
handler.redeclaration(existingDescriptor, redeclaredDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericWarning extends JetDiagnostic {
|
||||
|
||||
private final ASTNode node;
|
||||
private final String message;
|
||||
|
||||
public GenericWarning(@NotNull ASTNode node, @NotNull String message) {
|
||||
this.message = message;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptHandler(@NotNull ErrorHandler handler) {
|
||||
handler.genericWarning(node, message);
|
||||
}
|
||||
}
|
||||
|
||||
// private final StackTraceElement[] stackTrace;
|
||||
//
|
||||
// protected JetDiagnostic() {
|
||||
// stackTrace = Thread.currentThread().getStackTrace();
|
||||
// }
|
||||
//
|
||||
// public StackTraceElement[] getStackTrace() {
|
||||
// return stackTrace;
|
||||
// }
|
||||
|
||||
public abstract void acceptHandler(@NotNull ErrorHandler handler);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.jetbrains.jet.lang;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetSemanticServices {
|
||||
public static JetSemanticServices createSemanticServices(JetStandardLibrary standardLibrary) {
|
||||
return new JetSemanticServices(standardLibrary, JetControlFlowDataTraceFactory.EMPTY);
|
||||
}
|
||||
|
||||
public static JetSemanticServices createSemanticServices(Project project) {
|
||||
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY);
|
||||
}
|
||||
|
||||
public static JetSemanticServices createSemanticServices(Project project, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), flowDataTraceFactory);
|
||||
}
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final JetTypeChecker typeChecker;
|
||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||
|
||||
private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
this.standardLibrary = standardLibrary;
|
||||
this.typeChecker = new JetTypeChecker(standardLibrary);
|
||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetStandardLibrary getStandardLibrary() {
|
||||
return standardLibrary;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) {
|
||||
return new ClassDescriptorResolver(this, trace, flowDataTraceFactory);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider) {
|
||||
return new JetTypeInferrer(flowInformationProvider, this).getServices(trace);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetTypeChecker getTypeChecker() {
|
||||
return typeChecker;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class BlockInfo {}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class BreakableBlockInfo extends BlockInfo {
|
||||
private final JetElement element;
|
||||
private final Label entryPoint;
|
||||
private final Label exitPoint;
|
||||
|
||||
public BreakableBlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
|
||||
this.element = element;
|
||||
this.entryPoint = entryPoint;
|
||||
this.exitPoint = exitPoint;
|
||||
}
|
||||
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public Label getEntryPoint() {
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
public Label getExitPoint() {
|
||||
return exitPoint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface GenerationTrigger {
|
||||
void generate();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetControlFlowBuilder {
|
||||
void read(@NotNull JetExpression expression);
|
||||
void readUnit(@NotNull JetExpression expression);
|
||||
|
||||
// General label management
|
||||
@NotNull
|
||||
Label createUnboundLabel();
|
||||
|
||||
void bindLabel(@NotNull Label label);
|
||||
|
||||
// Jumps
|
||||
void jump(@NotNull Label label);
|
||||
void jumpOnFalse(@NotNull Label label);
|
||||
void jumpOnTrue(@NotNull Label label);
|
||||
void nondeterministicJump(Label label); // Maybe, jump to label
|
||||
void jumpToError(JetThrowExpression expression);
|
||||
|
||||
// Entry/exit points
|
||||
Label getEntryPoint(@NotNull JetElement labelElement);
|
||||
Label getExitPoint(@NotNull JetElement labelElement);
|
||||
|
||||
// Loops
|
||||
LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, @Nullable Label conditionEntryPoint);
|
||||
|
||||
void exitLoop(@NotNull JetExpression expression);
|
||||
@Nullable
|
||||
JetElement getCurrentLoop();
|
||||
|
||||
// Finally
|
||||
void enterTryFinally(@NotNull GenerationTrigger trigger);
|
||||
void exitTryFinally();
|
||||
|
||||
// Subroutines
|
||||
void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral);
|
||||
|
||||
void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral);
|
||||
|
||||
@Nullable
|
||||
JetElement getCurrentSubroutine();
|
||||
void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine);
|
||||
|
||||
void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine);
|
||||
|
||||
void write(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||
|
||||
// Other
|
||||
void unsupported(JetElement element);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
||||
protected JetControlFlowBuilder builder;
|
||||
|
||||
public JetControlFlowBuilderAdapter(JetControlFlowBuilder builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetExpression expression) {
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readUnit(@NotNull JetExpression expression) {
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Label createUnboundLabel() {
|
||||
return builder.createUnboundLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindLabel(@NotNull Label label) {
|
||||
builder.bindLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jump(@NotNull Label label) {
|
||||
builder.jump(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnFalse(@NotNull Label label) {
|
||||
builder.jumpOnFalse(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnTrue(@NotNull Label label) {
|
||||
builder.jumpOnTrue(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(Label label) {
|
||||
builder.nondeterministicJump(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpToError(JetThrowExpression expression) {
|
||||
builder.jumpToError(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getEntryPoint(@NotNull JetElement labelElement) {
|
||||
return builder.getEntryPoint(labelElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getExitPoint(@NotNull JetElement labelElement) {
|
||||
return builder.getExitPoint(labelElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) {
|
||||
return builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitLoop(@NotNull JetExpression expression) {
|
||||
builder.exitLoop(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetElement getCurrentLoop() {
|
||||
return builder.getCurrentLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterTryFinally(@NotNull GenerationTrigger trigger) {
|
||||
builder.enterTryFinally(trigger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitTryFinally() {
|
||||
builder.exitTryFinally();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
builder.enterSubroutine(subroutine, isFunctionLiteral);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
builder.exitSubroutine(subroutine, functionLiteral);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetElement getCurrentSubroutine() {
|
||||
return builder.getCurrentSubroutine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
|
||||
builder.returnValue(returnExpression, subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
|
||||
builder.returnNoValue(returnExpression, subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported(JetElement element) {
|
||||
builder.unsupported(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||
builder.write(assignment, lValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,778 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.types.JetTypeInferrer;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetControlFlowProcessor {
|
||||
|
||||
private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
|
||||
|
||||
private final JetControlFlowBuilder builder;
|
||||
private final BindingTrace trace;
|
||||
|
||||
public JetControlFlowProcessor(BindingTrace trace, JetControlFlowBuilder builder) {
|
||||
this.builder = builder;
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public void generate(@NotNull JetElement subroutineElement, @NotNull JetExpression body) {
|
||||
generateSubroutineControlFlow(subroutineElement, Collections.singletonList(body));
|
||||
}
|
||||
|
||||
public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List<? extends JetElement> body) {
|
||||
if (subroutineElement instanceof JetNamedDeclaration) {
|
||||
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement;
|
||||
enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration);
|
||||
}
|
||||
boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression;
|
||||
builder.enterSubroutine(subroutineElement, functionLiteral);
|
||||
for (JetElement statement : body) {
|
||||
statement.accept(new CFPVisitor(false));
|
||||
}
|
||||
builder.exitSubroutine(subroutineElement, functionLiteral);
|
||||
}
|
||||
|
||||
private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) {
|
||||
Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
if (stack == null) {
|
||||
stack = new Stack<JetElement>();
|
||||
labeledElements.put(labelName, stack);
|
||||
}
|
||||
stack.push(labeledElement);
|
||||
}
|
||||
|
||||
private void exitElement(JetElement element) {
|
||||
// TODO : really suboptimal
|
||||
for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
|
||||
Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
|
||||
Stack<JetElement> stack = entry.getValue();
|
||||
for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
|
||||
JetElement recorded = stackIter.next();
|
||||
if (recorded == element) {
|
||||
stackIter.remove();
|
||||
}
|
||||
}
|
||||
if (stack.isEmpty()) {
|
||||
mapIter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) {
|
||||
Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
if (reportUnresolved) {
|
||||
trace.getErrorHandler().unresolvedReference(labelExpression);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (stack.size() > 1) {
|
||||
trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope");
|
||||
}
|
||||
|
||||
JetElement result = stack.peek();
|
||||
trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private class CFPVisitor extends JetVisitorVoid {
|
||||
// private final boolean preferBlock;
|
||||
private final boolean inCondition;
|
||||
|
||||
private CFPVisitor(boolean inCondition) {
|
||||
// this.preferBlock = preferBlock;
|
||||
this.inCondition = inCondition;
|
||||
}
|
||||
|
||||
private void value(@Nullable JetElement element, boolean inCondition) {
|
||||
if (element == null) return;
|
||||
CFPVisitor visitor;
|
||||
if (this.inCondition == inCondition) {
|
||||
visitor = this;
|
||||
}
|
||||
else {
|
||||
visitor = new CFPVisitor(inCondition);
|
||||
}
|
||||
element.accept(visitor);
|
||||
exitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
|
||||
JetExpression innerExpression = expression.getExpression();
|
||||
if (innerExpression != null) {
|
||||
value(innerExpression, inCondition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitThisExpression(JetThisExpression expression) {
|
||||
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
if (targetLabel != null) {
|
||||
String labelName = expression.getLabelName();
|
||||
assert labelName != null;
|
||||
resolveLabel(labelName, targetLabel, false);
|
||||
}
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstantExpression(JetConstantExpression expression) {
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) {
|
||||
String labelName = expression.getLabelName();
|
||||
JetExpression labeledExpression = expression.getLabeledExpression();
|
||||
if (labelName != null && labeledExpression != null) {
|
||||
visitLabeledExpression(labelName, labeledExpression);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
|
||||
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
|
||||
if (deparenthesized != null) {
|
||||
enterLabeledElement(labelName, deparenthesized);
|
||||
value(labeledExpression, inCondition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryExpression(JetBinaryExpression expression) {
|
||||
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
||||
JetExpression right = expression.getRight();
|
||||
if (operationType == JetTokens.ANDAND) {
|
||||
value(expression.getLeft(), true);
|
||||
Label resultLabel = builder.createUnboundLabel();
|
||||
builder.jumpOnFalse(resultLabel);
|
||||
if (right != null) {
|
||||
value(right, true);
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
if (!inCondition) {
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
else if (operationType == JetTokens.OROR) {
|
||||
value(expression.getLeft(), true);
|
||||
Label resultLabel = builder.createUnboundLabel();
|
||||
builder.jumpOnTrue(resultLabel);
|
||||
if (right != null) {
|
||||
value(right, true);
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
if (!inCondition) {
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
else if (operationType == JetTokens.EQ) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (right != null) {
|
||||
value(right, false);
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression) {
|
||||
builder.write(expression, left);
|
||||
}
|
||||
else if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
visitAssignToArrayAccess(expression, arrayAccessExpression);
|
||||
} else if (left instanceof JetQualifiedExpression) {
|
||||
assert !(left instanceof JetPredicateExpression) : left; // TODO
|
||||
assert !(left instanceof JetHashQualifiedExpression) : left; // TODO
|
||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
|
||||
value(qualifiedExpression.getReceiverExpression(), false);
|
||||
value(expression.getOperationReference(), false);
|
||||
builder.write(expression, left);
|
||||
} else {
|
||||
builder.unsupported(expression); // TODO
|
||||
}
|
||||
}
|
||||
else if (JetTypeInferrer.assignmentOperationNames.containsKey(operationType)) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (left != null) {
|
||||
value(left, false);
|
||||
}
|
||||
if (right != null) {
|
||||
value(right, false);
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
|
||||
value(expression.getOperationReference(), false);
|
||||
builder.write(expression, left);
|
||||
}
|
||||
else if (left != null) {
|
||||
builder.unsupported(expression); // TODO
|
||||
}
|
||||
}
|
||||
else {
|
||||
value(expression.getLeft(), false);
|
||||
if (right != null) {
|
||||
value(right, false);
|
||||
}
|
||||
value(expression.getOperationReference(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
|
||||
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
|
||||
value(index, false);
|
||||
}
|
||||
value(arrayAccessExpression.getArrayExpression(), false);
|
||||
value(expression.getOperationReference(), false);
|
||||
builder.write(expression, arrayAccessExpression); // TODO : ???
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnaryExpression(JetUnaryExpression expression) {
|
||||
JetSimpleNameExpression operationSign = expression.getOperationSign();
|
||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||
JetExpression baseExpression = expression.getBaseExpression();
|
||||
if (JetTokens.LABELS.contains(operationType)) {
|
||||
String referencedName = operationSign.getReferencedName();
|
||||
referencedName = referencedName == null ? " <?>" : referencedName;
|
||||
visitLabeledExpression(referencedName.substring(1), baseExpression);
|
||||
}
|
||||
else {
|
||||
value(baseExpression, false);
|
||||
value(operationSign, false);
|
||||
|
||||
boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
|
||||
if (incrementOrDecrement) {
|
||||
builder.write(expression, baseExpression);
|
||||
}
|
||||
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isIncrementOrDecrement(IElementType operationType) {
|
||||
return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitIfExpression(JetIfExpression expression) {
|
||||
JetExpression condition = expression.getCondition();
|
||||
if (condition != null) {
|
||||
value(condition, true);
|
||||
}
|
||||
Label elseLabel = builder.createUnboundLabel();
|
||||
builder.jumpOnFalse(elseLabel);
|
||||
JetExpression thenBranch = expression.getThen();
|
||||
if (thenBranch != null) {
|
||||
value(thenBranch, inCondition);
|
||||
}
|
||||
else {
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
Label resultLabel = builder.createUnboundLabel();
|
||||
builder.jump(resultLabel);
|
||||
builder.bindLabel(elseLabel);
|
||||
JetExpression elseBranch = expression.getElse();
|
||||
if (elseBranch != null) {
|
||||
value(elseBranch, inCondition);
|
||||
}
|
||||
else {
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryExpression(JetTryExpression expression) {
|
||||
final JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||
if (finallyBlock != null) {
|
||||
builder.enterTryFinally(new GenerationTrigger() {
|
||||
private boolean working = false;
|
||||
|
||||
@Override
|
||||
public void generate() {
|
||||
// This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
|
||||
if (working) return;
|
||||
working = true;
|
||||
value(finallyBlock.getFinalExpression(), inCondition);
|
||||
working = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Label onException = builder.createUnboundLabel();
|
||||
builder.nondeterministicJump(onException);
|
||||
value(expression.getTryBlock(), inCondition);
|
||||
|
||||
List<JetCatchClause> catchClauses = expression.getCatchClauses();
|
||||
if (!catchClauses.isEmpty()) {
|
||||
Label afterCatches = builder.createUnboundLabel();
|
||||
builder.jump(afterCatches);
|
||||
|
||||
builder.bindLabel(onException);
|
||||
for (Iterator<JetCatchClause> iterator = catchClauses.iterator(); iterator.hasNext(); ) {
|
||||
JetCatchClause catchClause = iterator.next();
|
||||
JetExpression catchBody = catchClause.getCatchBody();
|
||||
if (catchBody != null) {
|
||||
value(catchBody, false);
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
builder.nondeterministicJump(afterCatches);
|
||||
}
|
||||
}
|
||||
|
||||
builder.bindLabel(afterCatches);
|
||||
} else {
|
||||
builder.bindLabel(onException);
|
||||
}
|
||||
|
||||
if (finallyBlock != null) {
|
||||
builder.exitTryFinally();
|
||||
value(finallyBlock.getFinalExpression(), inCondition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhileExpression(JetWhileExpression expression) {
|
||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||
|
||||
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||
JetExpression condition = expression.getCondition();
|
||||
if (condition != null) {
|
||||
value(condition, true);
|
||||
}
|
||||
builder.jumpOnFalse(loopInfo.getExitPoint());
|
||||
|
||||
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||
JetExpression body = expression.getBody();
|
||||
if (body != null) {
|
||||
value(body, false);
|
||||
}
|
||||
builder.jump(loopInfo.getEntryPoint());
|
||||
builder.exitLoop(expression);
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDoWhileExpression(JetDoWhileExpression expression) {
|
||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||
|
||||
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||
JetExpression body = expression.getBody();
|
||||
if (body != null) {
|
||||
value(body, false);
|
||||
}
|
||||
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||
JetExpression condition = expression.getCondition();
|
||||
if (condition != null) {
|
||||
value(condition, true);
|
||||
}
|
||||
builder.jumpOnTrue(loopInfo.getEntryPoint());
|
||||
builder.exitLoop(expression);
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForExpression(JetForExpression expression) {
|
||||
JetExpression loopRange = expression.getLoopRange();
|
||||
if (loopRange != null) {
|
||||
value(loopRange, false);
|
||||
}
|
||||
// TODO : primitive cases
|
||||
Label loopExitPoint = builder.createUnboundLabel();
|
||||
Label conditionEntryPoint = builder.createUnboundLabel();
|
||||
|
||||
builder.bindLabel(conditionEntryPoint);
|
||||
builder.nondeterministicJump(loopExitPoint);
|
||||
|
||||
LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
|
||||
|
||||
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||
JetExpression body = expression.getBody();
|
||||
if (body != null) {
|
||||
value(body, false);
|
||||
}
|
||||
|
||||
builder.nondeterministicJump(loopInfo.getEntryPoint());
|
||||
builder.exitLoop(expression);
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBreakExpression(JetBreakExpression expression) {
|
||||
JetElement loop = getCorrespondingLoop(expression);
|
||||
if (loop != null) {
|
||||
builder.jump(builder.getExitPoint(loop));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitContinueExpression(JetContinueExpression expression) {
|
||||
JetElement loop = getCorrespondingLoop(expression);
|
||||
if (loop != null) {
|
||||
builder.jump(builder.getEntryPoint(loop));
|
||||
}
|
||||
}
|
||||
|
||||
private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) {
|
||||
String labelName = expression.getLabelName();
|
||||
JetElement loop;
|
||||
if (labelName != null) {
|
||||
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
assert targetLabel != null;
|
||||
loop = resolveLabel(labelName, targetLabel, true);
|
||||
if (!isLoop(loop)) {
|
||||
trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop");
|
||||
loop = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
loop = builder.getCurrentLoop();
|
||||
if (loop == null) {
|
||||
trace.getErrorHandler().genericError(expression.getNode(), "'break' and 'continue' are only allowed inside a loop");
|
||||
}
|
||||
}
|
||||
return loop;
|
||||
}
|
||||
|
||||
private boolean isLoop(JetElement loop) {
|
||||
return loop instanceof JetWhileExpression ||
|
||||
loop instanceof JetDoWhileExpression ||
|
||||
loop instanceof JetForExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnExpression(JetReturnExpression expression) {
|
||||
JetExpression returnedExpression = expression.getReturnedExpression();
|
||||
if (returnedExpression != null) {
|
||||
value(returnedExpression, false);
|
||||
}
|
||||
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||
JetElement subroutine;
|
||||
if (labelElement != null) {
|
||||
String labelName = expression.getLabelName();
|
||||
assert labelName != null;
|
||||
subroutine = resolveLabel(labelName, labelElement, true);
|
||||
}
|
||||
else {
|
||||
subroutine = builder.getCurrentSubroutine();
|
||||
// TODO : a context check
|
||||
}
|
||||
if (subroutine != null) {
|
||||
if (returnedExpression == null) {
|
||||
builder.returnNoValue(expression, subroutine);
|
||||
}
|
||||
else {
|
||||
builder.returnValue(expression, subroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBlockExpression(JetBlockExpression expression) {
|
||||
List<JetElement> statements = expression.getStatements();
|
||||
for (JetElement statement : statements) {
|
||||
value(statement, false);
|
||||
}
|
||||
if (statements.isEmpty()) {
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNamedFunction(JetNamedFunction function) {
|
||||
JetExpression bodyExpression = function.getBodyExpression();
|
||||
if (bodyExpression != null) {
|
||||
generate(function, bodyExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
|
||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
|
||||
if (bodyExpression != null) {
|
||||
List<JetElement> statements = bodyExpression.getStatements();
|
||||
generateSubroutineControlFlow(expression, statements);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
||||
value(expression.getReceiverExpression(), false);
|
||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||
if (selectorExpression != null) {
|
||||
value(selectorExpression, false);
|
||||
}
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
private void visitCall(JetCallElement call) {
|
||||
for (ValueArgument argument : call.getValueArguments()) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
value(argumentExpression, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
|
||||
value(functionLiteral, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(JetCallExpression expression) {
|
||||
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
|
||||
value(typeArgument, false);
|
||||
}
|
||||
|
||||
visitCall(expression);
|
||||
|
||||
value(expression.getCalleeExpression(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void visitNewExpression(JetNewExpression expression) {
|
||||
// // TODO : Instantiated class is loaded
|
||||
// // TODO : type arguments?
|
||||
// visitCall(expression);
|
||||
// builder.read(expression);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void visitProperty(JetProperty property) {
|
||||
JetExpression initializer = property.getInitializer();
|
||||
if (initializer != null) {
|
||||
value(initializer, false);
|
||||
builder.write(property, property);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTupleExpression(JetTupleExpression expression) {
|
||||
for (JetExpression entry : expression.getEntries()) {
|
||||
value(entry, false);
|
||||
}
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
|
||||
IElementType operationType = expression.getOperationSign().getReferencedNameElementType();
|
||||
if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
|
||||
value(expression.getLeft(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
else {
|
||||
visitJetElement(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitThrowExpression(JetThrowExpression expression) {
|
||||
JetExpression thrownExpression = expression.getThrownExpression();
|
||||
if (thrownExpression != null) {
|
||||
value(thrownExpression, false);
|
||||
}
|
||||
builder.jumpToError(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
|
||||
for (JetExpression index : expression.getIndexExpressions()) {
|
||||
value(index, false);
|
||||
}
|
||||
value(expression.getArrayExpression(), false);
|
||||
// TODO : read 'get' or 'set' function
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIsExpression(JetIsExpression expression) {
|
||||
value(expression.getLeftHandSide(), inCondition);
|
||||
// TODO : builder.read(expression.getPattern());
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenExpression(JetWhenExpression expression) {
|
||||
// TODO : no more than one else
|
||||
// TODO : else must be the last
|
||||
JetExpression subjectExpression = expression.getSubjectExpression();
|
||||
if (subjectExpression != null) {
|
||||
value(subjectExpression, inCondition);
|
||||
}
|
||||
|
||||
Label doneLabel = builder.createUnboundLabel();
|
||||
|
||||
Label nextLabel = builder.createUnboundLabel();
|
||||
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
||||
JetWhenEntry whenEntry = iterator.next();
|
||||
|
||||
if (whenEntry.isElse()) {
|
||||
if (iterator.hasNext()) {
|
||||
trace.getErrorHandler().genericError(whenEntry.getNode(), "'else' entry must be the last one in a when-expression");
|
||||
}
|
||||
}
|
||||
|
||||
Label bodyLabel = builder.createUnboundLabel();
|
||||
|
||||
JetWhenCondition[] conditions = whenEntry.getConditions();
|
||||
for (int i = 0; i < conditions.length; i++) {
|
||||
JetWhenCondition condition = conditions[i];
|
||||
condition.accept(new JetVisitorVoid() {
|
||||
private final JetVisitorVoid conditionVisitor = this;
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
value(condition.getCallSuffixExpression(), inCondition); // TODO : inCondition?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
value(condition.getRangeExpression(), inCondition); // TODO : inCondition?
|
||||
value(condition.getOperationReference(), inCondition); // TODO : inCondition?
|
||||
// TODO : read the call to contains()...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
JetPattern pattern = condition.getPattern();
|
||||
if (pattern != null) {
|
||||
pattern.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitTypePattern(JetTypePattern typePattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWildcardPattern(JetWildcardPattern pattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExpressionPattern(JetExpressionPattern pattern) {
|
||||
value(pattern.getExpression(), inCondition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTuplePattern(JetTuplePattern pattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
|
||||
value(pattern.getDecomposerExpression(), inCondition);
|
||||
pattern.getArgumentList().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBindingPattern(JetBindingPattern pattern) {
|
||||
JetWhenCondition condition = pattern.getCondition();
|
||||
if (condition != null) {
|
||||
condition.accept(conditionVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
});
|
||||
if (i + 1 < conditions.length) {
|
||||
builder.nondeterministicJump(bodyLabel);
|
||||
}
|
||||
}
|
||||
|
||||
builder.nondeterministicJump(nextLabel);
|
||||
|
||||
builder.bindLabel(bodyLabel);
|
||||
value(whenEntry.getExpression(), inCondition);
|
||||
builder.jump(doneLabel);
|
||||
builder.bindLabel(nextLabel);
|
||||
nextLabel = builder.createUnboundLabel();
|
||||
}
|
||||
// TODO : if there's else, no error can happen
|
||||
builder.jumpToError(null);
|
||||
builder.bindLabel(doneLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
|
||||
// List<JetDelegationSpecifier> delegationSpecifiers = expression.getObjectDeclaration().getDelegationSpecifiers();
|
||||
// for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
|
||||
// if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
// JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
|
||||
// JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
// if (delegateExpression != null) {
|
||||
// value(delegateExpression, false, false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
value(expression.getObjectDeclaration(), inCondition);
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
|
||||
for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
|
||||
value(delegationSpecifier, inCondition);
|
||||
}
|
||||
for (JetDeclaration jetDeclaration : declaration.getDeclarations()) {
|
||||
FOR_LOCAL_CLASSES.value(jetDeclaration, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStringTemplateExpression(JetStringTemplateExpression expression) {
|
||||
for (JetStringTemplateEntry entry : expression.getEntries()) {
|
||||
if (entry instanceof JetStringTemplateEntryWithExpression) {
|
||||
JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry;
|
||||
value(entryWithExpression.getExpression(), false);
|
||||
}
|
||||
}
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeProjection(JetTypeProjection typeProjection) {
|
||||
// TODO : Support Type Arguments. Class object may be initialized at this point");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
builder.unsupported(element);
|
||||
}
|
||||
}
|
||||
|
||||
private final CFPVisitor FOR_LOCAL_CLASSES = new CFPVisitor(false) {
|
||||
@Override
|
||||
public void visitNamedFunction(JetNamedFunction function) {
|
||||
// Nothing
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetLoopExpression;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetFlowInformationProvider {
|
||||
JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
|
||||
@Override
|
||||
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBreakable(JetLoopExpression loop) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
||||
@Override
|
||||
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBreakable(JetLoopExpression loop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Collects expressions returned from the given subroutine and 'return;' expressions
|
||||
*/
|
||||
void collectReturnedInformation(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetExpression> returnedExpressions,
|
||||
@NotNull Collection<JetElement> elementsReturningUnit);
|
||||
|
||||
/**
|
||||
* Collects all 'return ...' expressions that return from the given subroutine and all the expressions that precede the exit point
|
||||
*/
|
||||
void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions);
|
||||
|
||||
void collectUnreachableExpressions(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetElement> unreachableElements);
|
||||
|
||||
void collectDominatedExpressions(
|
||||
@NotNull JetExpression dominator,
|
||||
@NotNull Collection<JetElement> dominated);
|
||||
|
||||
boolean isBreakable(JetLoopExpression loop);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface Label {
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class LoopInfo extends BreakableBlockInfo {
|
||||
private final Label bodyEntryPoint;
|
||||
private final Label conditionEntryPoint;
|
||||
|
||||
public LoopInfo(JetElement element, Label entryPoint, Label exitPoint, Label bodyEntryPoint, Label conditionEntryPoint) {
|
||||
super(element, entryPoint, exitPoint);
|
||||
this.bodyEntryPoint = bodyEntryPoint;
|
||||
this.conditionEntryPoint = conditionEntryPoint;
|
||||
}
|
||||
|
||||
public Label getBodyEntryPoint() {
|
||||
return bodyEntryPoint;
|
||||
}
|
||||
|
||||
public Label getConditionEntryPoint() {
|
||||
return conditionEntryPoint;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class AbstractJumpInstruction extends InstructionImpl {
|
||||
private final Label targetLabel;
|
||||
private Instruction resolvedTarget;
|
||||
|
||||
public AbstractJumpInstruction(Label targetLabel) {
|
||||
this.targetLabel = targetLabel;
|
||||
}
|
||||
|
||||
public Label getTargetLabel() {
|
||||
return targetLabel;
|
||||
}
|
||||
|
||||
public Instruction getResolvedTarget() {
|
||||
return resolvedTarget;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Collections.singleton(getResolvedTarget());
|
||||
}
|
||||
|
||||
public void setResolvedTarget(Instruction resolvedTarget) {
|
||||
this.resolvedTarget = outgoingEdgeTo(resolvedTarget);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ConditionalJumpInstruction extends AbstractJumpInstruction {
|
||||
private final boolean onTrue;
|
||||
private Instruction nextOnTrue;
|
||||
private Instruction nextOnFalse;
|
||||
|
||||
public ConditionalJumpInstruction(boolean onTrue, Label targetLabel) {
|
||||
super(targetLabel);
|
||||
this.onTrue = onTrue;
|
||||
}
|
||||
|
||||
public boolean onTrue() {
|
||||
return onTrue;
|
||||
}
|
||||
|
||||
public Instruction getNextOnTrue() {
|
||||
return nextOnTrue;
|
||||
}
|
||||
|
||||
public void setNextOnTrue(Instruction nextOnTrue) {
|
||||
this.nextOnTrue = outgoingEdgeTo(nextOnTrue);
|
||||
}
|
||||
|
||||
public Instruction getNextOnFalse() {
|
||||
return nextOnFalse;
|
||||
}
|
||||
|
||||
public void setNextOnFalse(Instruction nextOnFalse) {
|
||||
this.nextOnFalse = outgoingEdgeTo(nextOnFalse);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Arrays.asList(getNextOnFalse(), getNextOnTrue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitConditionalJump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String instr = onTrue ? "jt" : "jf";
|
||||
return instr + "(" + getTargetLabel().getName() + ")";
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class FunctionLiteralValueInstruction extends ReadValueInstruction {
|
||||
|
||||
private Pseudocode body;
|
||||
|
||||
public FunctionLiteralValueInstruction(@NotNull JetFunctionLiteralExpression expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
public Pseudocode getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Pseudocode body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitFunctionLiteralValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "rf(" + element.getText() + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface Instruction {
|
||||
@NotNull
|
||||
Pseudocode getOwner();
|
||||
|
||||
void setOwner(@NotNull Pseudocode owner);
|
||||
|
||||
Collection<Instruction> getPreviousInstructions();
|
||||
|
||||
@NotNull
|
||||
Collection<Instruction> getNextInstructions();
|
||||
|
||||
void accept(InstructionVisitor visitor);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class InstructionImpl implements Instruction {
|
||||
private Pseudocode owner;
|
||||
private final Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>();
|
||||
|
||||
protected InstructionImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Pseudocode getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(@NotNull Pseudocode owner) {
|
||||
assert this.owner == null || this.owner == owner;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Instruction> getPreviousInstructions() {
|
||||
return previousInstructions;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Instruction outgoingEdgeTo(@Nullable Instruction target) {
|
||||
if (target != null) {
|
||||
target.getPreviousInstructions().add(this);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class InstructionVisitor {
|
||||
public void visitReadValue(ReadValueInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
visitReadValue(instruction);
|
||||
}
|
||||
|
||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
visitInstruction(instruction);
|
||||
}
|
||||
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
visitInstruction(instruction);
|
||||
}
|
||||
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
visitInstruction(instruction);
|
||||
}
|
||||
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
}
|
||||
|
||||
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||
visitInstructionWithNext(writeValueInstruction);
|
||||
}
|
||||
|
||||
public void visitReadUnitValue(ReadUnitValueInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class InstructionWithNext extends JetElementInstructionImpl {
|
||||
private Instruction next;
|
||||
|
||||
protected InstructionWithNext(@NotNull JetElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
public Instruction getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Collections.singleton(next);
|
||||
}
|
||||
|
||||
public void setNext(Instruction next) {
|
||||
this.next = outgoingEdgeTo(next);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetControlFlowDataTraceFactory {
|
||||
JetControlFlowDataTraceFactory EMPTY = new JetControlFlowDataTraceFactory() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JetPseudocodeTrace createTrace(JetElement element) {
|
||||
return JetPseudocodeTrace.EMPTY;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
JetPseudocodeTrace createTrace(JetElement element);
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.*;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
|
||||
|
||||
private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>();
|
||||
private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>();
|
||||
private int labelCount = 0;
|
||||
|
||||
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
|
||||
|
||||
private final Stack<BlockInfo> allBlocks = new Stack<BlockInfo>();
|
||||
|
||||
private final JetPseudocodeTrace trace;
|
||||
|
||||
public JetControlFlowInstructionsGenerator(JetPseudocodeTrace trace) {
|
||||
super(null);
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
private void pushBuilder(JetElement scopingElement, JetElement subroutine) {
|
||||
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(scopingElement, subroutine);
|
||||
builders.push(worker);
|
||||
builder = worker;
|
||||
}
|
||||
|
||||
private JetControlFlowInstructionsGeneratorWorker popBuilder(@NotNull JetElement element) {
|
||||
JetControlFlowInstructionsGeneratorWorker worker = builders.pop();
|
||||
trace.recordControlFlowData(element, worker.getPseudocode());
|
||||
if (!builders.isEmpty()) {
|
||||
builder = builders.peek();
|
||||
}
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
if (isFunctionLiteral) {
|
||||
pushBuilder(subroutine, builder.getCurrentSubroutine());
|
||||
}
|
||||
else {
|
||||
pushBuilder(subroutine, subroutine);
|
||||
}
|
||||
builder.enterSubroutine(subroutine, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
super.exitSubroutine(subroutine, functionLiteral);
|
||||
JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine);
|
||||
if (functionLiteral) {
|
||||
JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
|
||||
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction((JetFunctionLiteralExpression) subroutine);
|
||||
instruction.setBody(worker.getPseudocode());
|
||||
builder.add(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder {
|
||||
|
||||
private final Pseudocode pseudocode;
|
||||
private final Label error;
|
||||
private final JetElement currentSubroutine;
|
||||
|
||||
private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement currentSubroutine) {
|
||||
this.pseudocode = new Pseudocode(scopingElement);
|
||||
this.error = pseudocode.createLabel("error");
|
||||
this.currentSubroutine = currentSubroutine;
|
||||
}
|
||||
|
||||
public Pseudocode getPseudocode() {
|
||||
return pseudocode;
|
||||
}
|
||||
|
||||
private void add(@NotNull Instruction instruction) {
|
||||
pseudocode.addInstruction(instruction);
|
||||
if (instruction instanceof JetElementInstruction) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final Label createUnboundLabel() {
|
||||
return pseudocode.createLabel("l" + labelCount++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) {
|
||||
Label label = createUnboundLabel();
|
||||
bindLabel(label);
|
||||
LoopInfo blockInfo = new LoopInfo(
|
||||
expression,
|
||||
label,
|
||||
loopExitPoint != null ? loopExitPoint : createUnboundLabel(),
|
||||
createUnboundLabel(),
|
||||
conditionEntryPoint != null ? conditionEntryPoint : createUnboundLabel());
|
||||
loopInfo.push(blockInfo);
|
||||
elementToBlockInfo.put(expression, blockInfo);
|
||||
allBlocks.push(blockInfo);
|
||||
trace.recordLoopInfo(expression, blockInfo);
|
||||
return blockInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void exitLoop(@NotNull JetExpression expression) {
|
||||
BreakableBlockInfo info = loopInfo.pop();
|
||||
elementToBlockInfo.remove(expression);
|
||||
allBlocks.pop();
|
||||
bindLabel(info.getExitPoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetElement getCurrentLoop() {
|
||||
return loopInfo.empty() ? null : loopInfo.peek().getElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
Label entryPoint = createUnboundLabel();
|
||||
BreakableBlockInfo blockInfo = new BreakableBlockInfo(subroutine, entryPoint, createUnboundLabel());
|
||||
// subroutineInfo.push(blockInfo);
|
||||
elementToBlockInfo.put(subroutine, blockInfo);
|
||||
allBlocks.push(blockInfo);
|
||||
bindLabel(entryPoint);
|
||||
add(new SubroutineEnterInstruction(subroutine));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetElement getCurrentSubroutine() {
|
||||
return currentSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getEntryPoint(@NotNull JetElement labelElement) {
|
||||
return elementToBlockInfo.get(labelElement).getEntryPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getExitPoint(@NotNull JetElement labelElement) {
|
||||
BreakableBlockInfo blockInfo = elementToBlockInfo.get(labelElement);
|
||||
assert blockInfo != null : labelElement.getText();
|
||||
return blockInfo.getExitPoint();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void handleJumpInsideTryFinally(Label jumpTarget) {
|
||||
List<TryFinallyBlockInfo> finallyBlocks = new ArrayList<TryFinallyBlockInfo>();
|
||||
|
||||
for (int i = allBlocks.size() - 1; i >= 0; i--) {
|
||||
BlockInfo blockInfo = allBlocks.get(i);
|
||||
if (blockInfo instanceof BreakableBlockInfo) {
|
||||
BreakableBlockInfo breakableBlockInfo = (BreakableBlockInfo) blockInfo;
|
||||
if (jumpTarget == breakableBlockInfo.getExitPoint() || jumpTarget == breakableBlockInfo.getEntryPoint()) {
|
||||
for (int j = finallyBlocks.size() - 1; j >= 0; j--) {
|
||||
finallyBlocks.get(j).generateFinallyBlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (blockInfo instanceof TryFinallyBlockInfo) {
|
||||
TryFinallyBlockInfo tryFinallyBlockInfo = (TryFinallyBlockInfo) blockInfo;
|
||||
finallyBlocks.add(tryFinallyBlockInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
bindLabel(getExitPoint(subroutine));
|
||||
pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, "<END>"));
|
||||
bindLabel(error);
|
||||
add(new SubroutineExitInstruction(subroutine, "<ERROR>"));
|
||||
elementToBlockInfo.remove(subroutine);
|
||||
allBlocks.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
|
||||
Label exitPoint = getExitPoint(subroutine);
|
||||
handleJumpInsideTryFinally(exitPoint);
|
||||
add(new ReturnValueInstruction(returnExpression, exitPoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
|
||||
Label exitPoint = getExitPoint(subroutine);
|
||||
handleJumpInsideTryFinally(exitPoint);
|
||||
add(new ReturnNoValueInstruction(returnExpression, exitPoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||
add(new WriteValueInstruction(assignment, lValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetExpression expression) {
|
||||
add(new ReadValueInstruction(expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readUnit(@NotNull JetExpression expression) {
|
||||
add(new ReadUnitValueInstruction(expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jump(@NotNull Label label) {
|
||||
handleJumpInsideTryFinally(label);
|
||||
add(new UnconditionalJumpInstruction(label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnFalse(@NotNull Label label) {
|
||||
handleJumpInsideTryFinally(label);
|
||||
add(new ConditionalJumpInstruction(false, label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnTrue(@NotNull Label label) {
|
||||
handleJumpInsideTryFinally(label);
|
||||
add(new ConditionalJumpInstruction(true, label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindLabel(@NotNull Label label) {
|
||||
pseudocode.bindLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(Label label) {
|
||||
handleJumpInsideTryFinally(label);
|
||||
add(new NondeterministicJumpInstruction(label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpToError(JetThrowExpression expression) {
|
||||
add(new UnconditionalJumpInstruction(error));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterTryFinally(@NotNull GenerationTrigger generationTrigger) {
|
||||
allBlocks.push(new TryFinallyBlockInfo(generationTrigger));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitTryFinally() {
|
||||
BlockInfo pop = allBlocks.pop();
|
||||
assert pop instanceof TryFinallyBlockInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported(JetElement element) {
|
||||
add(new UnsupportedElementInstruction(element));
|
||||
}
|
||||
}
|
||||
|
||||
public static class TryFinallyBlockInfo extends BlockInfo {
|
||||
private final GenerationTrigger finallyBlock;
|
||||
|
||||
private TryFinallyBlockInfo(GenerationTrigger finallyBlock) {
|
||||
this.finallyBlock = finallyBlock;
|
||||
}
|
||||
|
||||
public void generateFinallyBlock() {
|
||||
finallyBlock.generate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetElementInstruction extends Instruction {
|
||||
@NotNull
|
||||
JetElement getElement();
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class JetElementInstructionImpl extends InstructionImpl implements JetElementInstruction {
|
||||
protected final JetElement element;
|
||||
|
||||
public JetElementInstructionImpl(@NotNull JetElement element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.LoopInfo;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetPseudocodeTrace {
|
||||
|
||||
JetPseudocodeTrace EMPTY = new JetPseudocodeTrace() {
|
||||
@Override
|
||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
||||
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
|
||||
void close();
|
||||
|
||||
void recordLoopInfo(JetExpression expression, LoopInfo blockInfo);
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class NondeterministicJumpInstruction extends AbstractJumpInstruction {
|
||||
|
||||
private Instruction next;
|
||||
|
||||
public NondeterministicJumpInstruction(Label targetLabel) {
|
||||
super(targetLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitNondeterministicJump(this);
|
||||
}
|
||||
|
||||
public Instruction getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public void setNext(Instruction next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Arrays.asList(getResolvedTarget(), getNext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jmp?(" + getTargetLabel().getName() + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class Pseudocode {
|
||||
|
||||
public class PseudocodeLabel implements Label {
|
||||
private final String name;
|
||||
private Integer targetInstructionIndex;
|
||||
|
||||
|
||||
private PseudocodeLabel(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getTargetInstructionIndex() {
|
||||
return targetInstructionIndex;
|
||||
}
|
||||
|
||||
public void setTargetInstructionIndex(int targetInstructionIndex) {
|
||||
this.targetInstructionIndex = targetInstructionIndex;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<Instruction> resolve() {
|
||||
assert targetInstructionIndex != null;
|
||||
return instructions.subList(getTargetInstructionIndex(), instructions.size());
|
||||
}
|
||||
|
||||
public Instruction resolveToInstruction() {
|
||||
assert targetInstructionIndex != null;
|
||||
return instructions.get(targetInstructionIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||
|
||||
private final JetElement correspondingElement;
|
||||
private SubroutineExitInstruction exitInstruction;
|
||||
private boolean postPrecessed = false;
|
||||
|
||||
public Pseudocode(JetElement correspondingElement) {
|
||||
this.correspondingElement = correspondingElement;
|
||||
}
|
||||
|
||||
public JetElement getCorrespondingElement() {
|
||||
return correspondingElement;
|
||||
}
|
||||
|
||||
public PseudocodeLabel createLabel(String name) {
|
||||
PseudocodeLabel label = new PseudocodeLabel(name);
|
||||
labels.add(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<Instruction> getInstructions() {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
public void addExitInstruction(SubroutineExitInstruction exitInstruction) {
|
||||
addInstruction(exitInstruction);
|
||||
assert this.exitInstruction == null;
|
||||
this.exitInstruction = exitInstruction;
|
||||
}
|
||||
|
||||
public void addInstruction(Instruction instruction) {
|
||||
instructions.add(instruction);
|
||||
instruction.setOwner(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SubroutineExitInstruction getExitInstruction() {
|
||||
return exitInstruction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SubroutineEnterInstruction getEnterInstruction() {
|
||||
return (SubroutineEnterInstruction) instructions.get(0);
|
||||
}
|
||||
|
||||
public void bindLabel(Label label) {
|
||||
((PseudocodeLabel) label).setTargetInstructionIndex(instructions.size());
|
||||
}
|
||||
|
||||
public void postProcess() {
|
||||
if (postPrecessed) return;
|
||||
postPrecessed = true;
|
||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
final int currentPosition = i;
|
||||
instruction.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
Instruction nextInstruction = getNextPosition(currentPosition);
|
||||
Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel());
|
||||
if (instruction.onTrue()) {
|
||||
instruction.setNextOnFalse(nextInstruction);
|
||||
instruction.setNextOnTrue(jumpTarget);
|
||||
}
|
||||
else {
|
||||
instruction.setNextOnFalse(jumpTarget);
|
||||
instruction.setNextOnTrue(nextInstruction);
|
||||
}
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
instruction.getBody().postProcess();
|
||||
super.visitFunctionLiteralValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Instruction getJumpTarget(@NotNull Label targetLabel) {
|
||||
return getTargetInstruction(((PseudocodeLabel) targetLabel).resolve());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Instruction getTargetInstruction(@NotNull List<Instruction> instructions) {
|
||||
while (true) {
|
||||
assert instructions != null;
|
||||
Instruction targetInstruction = instructions.get(0);
|
||||
|
||||
if (false == targetInstruction instanceof UnconditionalJumpInstruction) {
|
||||
return targetInstruction;
|
||||
}
|
||||
|
||||
Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel();
|
||||
instructions = ((PseudocodeLabel)label).resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Instruction getNextPosition(int currentPosition) {
|
||||
int targetPosition = currentPosition + 1;
|
||||
assert targetPosition < instructions.size() : currentPosition;
|
||||
return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
|
||||
}
|
||||
|
||||
public void dfsDump(StringBuilder nodes, StringBuilder edges, Map<Instruction, String> nodeNames) {
|
||||
dfsDump(nodes, edges, instructions.get(0), nodeNames);
|
||||
}
|
||||
|
||||
private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map<Instruction, String> nodeNames) {
|
||||
if (nodeNames.containsKey(instruction)) return;
|
||||
String name = "n" + nodeNames.size();
|
||||
nodeNames.put(instruction, name);
|
||||
nodes.append(name).append(" := ").append(renderName(instruction));
|
||||
|
||||
}
|
||||
|
||||
private String renderName(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
public void dumpInstructions(@NotNull StringBuilder out) {
|
||||
List<Pseudocode> locals = new ArrayList<Pseudocode>();
|
||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
if (instruction instanceof FunctionLiteralValueInstruction) {
|
||||
FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction;
|
||||
locals.add(functionLiteralValueInstruction.getBody());
|
||||
}
|
||||
for (PseudocodeLabel label: labels) {
|
||||
if (label.getTargetInstructionIndex() == i) {
|
||||
out.append(label.getName()).append(":\n");
|
||||
}
|
||||
}
|
||||
out.append(" ").append(instruction).append("\n");
|
||||
}
|
||||
for (Pseudocode local : locals) {
|
||||
local.dumpInstructions(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpEdges(final PrintStream out, final int[] count, final Map<Instruction, String> nodeToName) {
|
||||
for (final Instruction fromInst : instructions) {
|
||||
fromInst.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
int index = count[0];
|
||||
// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getBody().instructions.get(0)), null);
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
super.visitReturnValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
super.visitReturnNoValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
String from = nodeToName.get(instruction);
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no");
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpNodes(PrintStream out, int[] count, Map<Instruction, String> nodeToName) {
|
||||
for (Instruction node : instructions) {
|
||||
if (node instanceof UnconditionalJumpInstruction) {
|
||||
continue;
|
||||
}
|
||||
String name = "n" + count[0]++;
|
||||
nodeToName.put(node, name);
|
||||
String text = node.toString();
|
||||
int newline = text.indexOf("\n");
|
||||
if (newline >= 0) {
|
||||
text = text.substring(0, newline);
|
||||
}
|
||||
String shape = "box";
|
||||
if (node instanceof ConditionalJumpInstruction) {
|
||||
shape = "diamond";
|
||||
}
|
||||
else if (node instanceof NondeterministicJumpInstruction) {
|
||||
shape = "Mdiamond";
|
||||
}
|
||||
else if (node instanceof UnsupportedElementInstruction) {
|
||||
shape = "box, fillcolor=red, style=filled";
|
||||
}
|
||||
else if (node instanceof FunctionLiteralValueInstruction) {
|
||||
shape = "Mcircle";
|
||||
}
|
||||
else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) {
|
||||
shape = "roundrect, style=rounded";
|
||||
}
|
||||
out.println(name + "[label=\"" + text + "\", shape=" + shape + "];");
|
||||
}
|
||||
}
|
||||
|
||||
private void printEdge(PrintStream out, String from, String to, String label) {
|
||||
if (label != null) {
|
||||
label = "[label=\"" + label + "\"]";
|
||||
}
|
||||
else {
|
||||
label = "";
|
||||
}
|
||||
out.println(from + " -> " + to + label + ";");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ReadUnitValueInstruction extends InstructionWithNext {
|
||||
|
||||
public ReadUnitValueInstruction(@NotNull JetExpression expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitReadUnitValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "read (Unit)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ReadValueInstruction extends InstructionWithNext {
|
||||
|
||||
public ReadValueInstruction(@NotNull JetExpression expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitReadValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "r(" + element.getText() + ")";
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ReturnNoValueInstruction extends AbstractJumpInstruction implements JetElementInstruction {
|
||||
|
||||
private final JetElement element;
|
||||
|
||||
public ReturnNoValueInstruction(@NotNull JetElement element, Label targetLabel) {
|
||||
super(targetLabel);
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitReturnNoValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ret " + getTargetLabel();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ReturnValueInstruction extends AbstractJumpInstruction implements JetElementInstruction {
|
||||
|
||||
private final JetElement element;
|
||||
|
||||
public ReturnValueInstruction(@NotNull JetExpression returnExpression, @NotNull Label targetLabel) {
|
||||
super(targetLabel);
|
||||
this.element = returnExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitReturnValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ret(*) " + getTargetLabel();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetElement getElement() {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class SubroutineEnterInstruction extends InstructionWithNext {
|
||||
private final JetElement subroutine;
|
||||
|
||||
public SubroutineEnterInstruction(@NotNull JetElement subroutine) {
|
||||
super(subroutine);
|
||||
this.subroutine = subroutine;
|
||||
}
|
||||
|
||||
public JetElement getSubroutine() {
|
||||
return subroutine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitSubroutineEnter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<START>";
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class SubroutineExitInstruction extends InstructionImpl {
|
||||
private final JetElement subroutine;
|
||||
private final String debugLabel;
|
||||
|
||||
public SubroutineExitInstruction(@NotNull JetElement subroutine, @NotNull String debugLabel) {
|
||||
this.subroutine = subroutine;
|
||||
this.debugLabel = debugLabel;
|
||||
}
|
||||
|
||||
public JetElement getSubroutine() {
|
||||
return subroutine;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitSubroutineExit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return debugLabel;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class UnconditionalJumpInstruction extends AbstractJumpInstruction {
|
||||
|
||||
|
||||
public UnconditionalJumpInstruction(Label targetLabel) {
|
||||
super(targetLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitUnconditionalJump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jmp(" + getTargetLabel().getName() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class UnsupportedElementInstruction extends InstructionWithNext {
|
||||
|
||||
protected UnsupportedElementInstruction(@NotNull JetElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitUnsupportedElementInstruction(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "unsupported(" + element + " : " + element.getText() + ")";
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class WriteValueInstruction extends InstructionWithNext {
|
||||
@NotNull
|
||||
private final JetElement lValue;
|
||||
|
||||
public WriteValueInstruction(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||
super(assignment);
|
||||
this.lValue = lValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitWriteValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (lValue instanceof JetNamedDeclaration) {
|
||||
JetNamedDeclaration value = (JetNamedDeclaration) lValue;
|
||||
return "w(" + value.getName() + ")";
|
||||
}
|
||||
return "w(" + lValue.getText() + ")";
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.types.NamespaceType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class AbstractNamespaceDescriptorImpl extends DeclarationDescriptorImpl implements NamespaceDescriptor {
|
||||
private NamespaceType namespaceType;
|
||||
|
||||
public AbstractNamespaceDescriptorImpl(DeclarationDescriptor containingDeclaration, List<AnnotationDescriptor> annotations, String name) {
|
||||
super(containingDeclaration, annotations, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public NamespaceType getNamespaceType() {
|
||||
if (namespaceType == null) {
|
||||
namespaceType = new NamespaceType(getName(), getMemberScope());
|
||||
}
|
||||
return namespaceType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public NamespaceDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
throw new UnsupportedOperationException("This operation does not make sense for a namespace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitNamespaceDescriptor(this, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface Annotation {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface CallableDescriptor extends DeclarationDescriptor {
|
||||
@Nullable
|
||||
JetType getReceiverType();
|
||||
|
||||
@NotNull
|
||||
List<TypeParameterDescriptor> getTypeParameters();
|
||||
|
||||
@NotNull
|
||||
JetType getReturnType();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
CallableDescriptor getOriginal();
|
||||
|
||||
@Override
|
||||
CallableDescriptor substitute(TypeSubstitutor substitutor);
|
||||
|
||||
@NotNull
|
||||
List<ValueParameterDescriptor> getValueParameters();
|
||||
|
||||
@NotNull
|
||||
Set<? extends CallableDescriptor> getOverriddenDescriptors();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface ClassDescriptor extends ClassifierDescriptor {
|
||||
|
||||
@NotNull
|
||||
JetScope getMemberScope(List<TypeProjection> typeArguments);
|
||||
|
||||
/**
|
||||
* @return the superclass for a class descriptor, and the required class fro a trait descriptor
|
||||
*/
|
||||
@NotNull
|
||||
JetType getSuperclassType();
|
||||
|
||||
@NotNull
|
||||
FunctionGroup getConstructors();
|
||||
|
||||
@Nullable
|
||||
ConstructorDescriptor getUnsubstitutedPrimaryConstructor();
|
||||
|
||||
boolean hasConstructors();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
DeclarationDescriptor getContainingDeclaration();
|
||||
|
||||
/**
|
||||
* @return type A<T> for the class A<T>
|
||||
*/
|
||||
@NotNull
|
||||
JetType getDefaultType();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
ClassDescriptor substitute(TypeSubstitutor substitutor);
|
||||
|
||||
@Nullable
|
||||
JetType getClassObjectType();
|
||||
|
||||
@NotNull
|
||||
ClassKind getKind();
|
||||
|
||||
@NotNull
|
||||
Modality getModality();
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements ClassDescriptor {
|
||||
private TypeConstructor typeConstructor;
|
||||
|
||||
private JetScope memberDeclarations;
|
||||
private FunctionGroup constructors;
|
||||
private ConstructorDescriptor primaryConstructor;
|
||||
private JetType superclassType;
|
||||
|
||||
public ClassDescriptorImpl(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull List<AnnotationDescriptor> annotations,
|
||||
@NotNull String name) {
|
||||
super(containingDeclaration, annotations, name);
|
||||
}
|
||||
|
||||
public final ClassDescriptorImpl initialize(boolean sealed,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull Collection<JetType> supertypes,
|
||||
@NotNull JetScope memberDeclarations,
|
||||
@NotNull FunctionGroup constructors,
|
||||
@Nullable ConstructorDescriptor primaryConstructor) {
|
||||
return initialize(sealed, typeParameters, supertypes, memberDeclarations, constructors, primaryConstructor, getClassType(supertypes));
|
||||
}
|
||||
|
||||
public final ClassDescriptorImpl initialize(boolean sealed,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull Collection<JetType> supertypes,
|
||||
@NotNull JetScope memberDeclarations,
|
||||
@NotNull FunctionGroup constructors,
|
||||
@Nullable ConstructorDescriptor primaryConstructor,
|
||||
@Nullable JetType superclassType) {
|
||||
this.typeConstructor = new TypeConstructorImpl(this, getAnnotations(), sealed, getName(), typeParameters, supertypes);
|
||||
this.memberDeclarations = memberDeclarations;
|
||||
this.constructors = constructors;
|
||||
this.primaryConstructor = primaryConstructor;
|
||||
this.superclassType = superclassType;
|
||||
// assert !constructors.isEmpty() || primaryConstructor == null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetType getClassType(@NotNull Collection<JetType> types) {
|
||||
for (JetType type : types) {
|
||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(type);
|
||||
if (classDescriptor != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return JetStandardClasses.getAnyType();
|
||||
}
|
||||
|
||||
public void setPrimaryConstructor(@NotNull ConstructorDescriptor primaryConstructor) {
|
||||
this.primaryConstructor = primaryConstructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TypeConstructor getTypeConstructor() {
|
||||
return typeConstructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
||||
assert typeArguments.size() == typeConstructor.getParameters().size() : typeArguments;
|
||||
if (typeConstructor.getParameters().isEmpty()) {
|
||||
return memberDeclarations;
|
||||
}
|
||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments);
|
||||
return new SubstitutingScope(memberDeclarations, TypeSubstitutor.create(substitutionContext));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getSuperclassType() {
|
||||
return superclassType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getDefaultType() {
|
||||
return TypeUtils.makeUnsubstitutedType(this, memberDeclarations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionGroup getConstructors() {
|
||||
// assert typeArguments.size() == getTypeConstructor().getParameters().size() : "Argument list length mismatch for " + getName();
|
||||
// if (typeArguments.size() == 0) {
|
||||
// return constructors;
|
||||
// }
|
||||
// Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
||||
return constructors;// LazySubstitutingFunctionGroup(TypeSubstitutor.create(substitutionContext), constructors);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType getClassObjectType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassKind getKind() {
|
||||
return ClassKind.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClassObjectAValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitClassDescriptor(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
|
||||
return primaryConstructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstructors() {
|
||||
return !constructors.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Modality getModality() {
|
||||
return Modality.FINAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public enum ClassKind {
|
||||
CLASS,
|
||||
TRAIT,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
OBJECT
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeConstructor;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface ClassifierDescriptor extends DeclarationDescriptor {
|
||||
@NotNull
|
||||
TypeConstructor getTypeConstructor();
|
||||
|
||||
@NotNull
|
||||
JetType getDefaultType();
|
||||
|
||||
@Nullable
|
||||
JetType getClassObjectType();
|
||||
|
||||
boolean isClassObjectAValue();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.jet.lang.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface ConstructorDescriptor extends FunctionDescriptor {
|
||||
/**
|
||||
* @throws UnsupportedOperationException -- no type parameters supported for constructors
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
List<TypeParameterDescriptor> getTypeParameters();
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException -- return type is not stored for constructors
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
JetType getReturnType();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
ClassDescriptor getContainingDeclaration();
|
||||
|
||||
/**
|
||||
* @return "<init>" -- name is not stored for constructors
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
String getName();
|
||||
|
||||
boolean isPrimary();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user