Merge remote branch 'origin/master'

This commit is contained in:
Andrey Breslav
2011-05-20 22:24:36 +04:00
5 changed files with 244 additions and 84 deletions
@@ -229,7 +229,7 @@ public class ExpressionCodegen extends JetVisitor {
final JetType expressionType = bindingContext.getExpressionType(loopRange);
Type loopRangeType = typeMapper.mapType(expressionType);
if (loopRangeType.getSort() == Type.ARRAY) {
generateForInArray(expression, loopRangeType);
new ForInArrayLoopGenerator(expression, loopRangeType).invoke();
}
else {
final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
@@ -242,57 +242,14 @@ public class ExpressionCodegen extends JetVisitor {
return;
}
}
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
new ForInRangeLoopGenerator(expression, loopRangeType).invoke();
return;
}
throw new UnsupportedOperationException("for/in loop currently only supported for arrays and Iterable instances");
}
}
private void generateForInArray(JetForExpression expression, Type loopRangeType) {
final JetParameter loopParameter = expression.getLoopParameter();
final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter);
JetType paramType = parameterDescriptor.getOutType();
Type asmParamType = typeMapper.mapType(paramType);
int lengthVar = myMap.enterTemp();
gen(expression.getLoopRange(), loopRangeType);
v.arraylength();
v.store(lengthVar, Type.INT_TYPE);
int indexVar = myMap.enterTemp();
v.aconst(0);
v.store(indexVar, Type.INT_TYPE);
myMap.enter(parameterDescriptor, asmParamType.getSize());
Label condition = new Label();
Label increment = new Label();
Label end = new Label();
v.mark(condition);
myContinueTargets.push(increment);
myBreakTargets.push(end);
v.load(indexVar, Type.INT_TYPE);
v.load(lengthVar, Type.INT_TYPE);
v.ificmpge(end);
gen(expression.getLoopRange(), loopRangeType); // array
v.load(indexVar, Type.INT_TYPE);
v.aload(loopRangeType.getElementType());
StackValue.onStack(loopRangeType.getElementType()).put(asmParamType, v);
v.store(myMap.getIndex(parameterDescriptor), asmParamType);
gen(expression.getBody(), Type.VOID_TYPE);
v.mark(increment);
v.iinc(indexVar, 1);
v.goTo(condition);
v.mark(end);
final int paramIndex = myMap.leave(parameterDescriptor);
v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
myMap.leaveTemp();
myMap.leaveTemp();
myBreakTargets.pop();
myContinueTargets.pop();
}
private void generateForInIterable(JetForExpression expression, Type loopRangeType) {
final JetParameter loopParameter = expression.getLoopParameter();
final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter);
@@ -335,6 +292,140 @@ public class ExpressionCodegen extends JetVisitor {
myContinueTargets.pop();
}
private abstract class ForLoopGenerator {
protected JetForExpression expression;
protected Type loopRangeType;
protected VariableDescriptor parameterDescriptor;
public ForLoopGenerator(JetForExpression expression, Type loopRangeType) {
this.expression = expression;
this.loopRangeType = loopRangeType;
final JetParameter loopParameter = expression.getLoopParameter();
this.parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter);
}
public void invoke() {
JetType paramType = parameterDescriptor.getOutType();
Type asmParamType = typeMapper.mapType(paramType);
myMap.enter(parameterDescriptor, asmParamType.getSize());
generatePrologue();
Label condition = new Label();
Label increment = new Label();
Label end = new Label();
v.mark(condition);
myContinueTargets.push(increment);
myBreakTargets.push(end);
generateCondition(asmParamType, end);
gen(expression.getBody(), Type.VOID_TYPE);
v.mark(increment);
generateIncrement();
v.goTo(condition);
v.mark(end);
cleanupTemp();
final int paramIndex = myMap.leave(parameterDescriptor);
v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
myBreakTargets.pop();
myContinueTargets.pop();
}
protected void generatePrologue() {
}
protected abstract void generateCondition(Type asmParamType, Label end);
protected abstract void generateIncrement();
protected void cleanupTemp() {
}
}
private class ForInArrayLoopGenerator extends ForLoopGenerator {
private int myLengthVar;
private int myIndexVar;
public ForInArrayLoopGenerator(JetForExpression expression, Type loopRangeType) {
super(expression, loopRangeType);
}
@Override
protected void generatePrologue() {
myLengthVar = myMap.enterTemp();
gen(expression.getLoopRange(), loopRangeType);
v.arraylength();
v.store(myLengthVar, Type.INT_TYPE);
myIndexVar = myMap.enterTemp();
v.aconst(0);
v.store(myIndexVar, Type.INT_TYPE);
}
protected void generateCondition(Type asmParamType, Label end) {
v.load(myIndexVar, Type.INT_TYPE);
v.load(myLengthVar, Type.INT_TYPE);
v.ificmpge(end);
gen(expression.getLoopRange(), loopRangeType); // array
v.load(myIndexVar, Type.INT_TYPE);
v.aload(loopRangeType.getElementType());
StackValue.onStack(loopRangeType.getElementType()).put(asmParamType, v);
v.store(myMap.getIndex(parameterDescriptor), asmParamType);
}
protected void generateIncrement() {
v.iinc(myIndexVar, 1);
}
protected void cleanupTemp() {
myMap.leaveTemp(2);
}
}
private class ForInRangeLoopGenerator extends ForLoopGenerator {
private int myRangeVar;
private int myEndVar;
public ForInRangeLoopGenerator(JetForExpression expression, Type loopRangeType) {
super(expression, loopRangeType);
}
@Override
protected void generatePrologue() {
myRangeVar = myMap.enterTemp();
myEndVar = myMap.enterTemp();
gen(expression.getLoopRange(), loopRangeType);
v.dup();
v.dup();
v.store(myRangeVar, loopRangeType);
v.invokevirtual("jet/IntRange", "getStartValue", "()I");
v.store(myMap.getIndex(parameterDescriptor), Type.INT_TYPE);
v.invokevirtual("jet/IntRange", "getEndValue", "()I");
v.store(myEndVar, Type.INT_TYPE);
}
@Override
protected void generateCondition(Type asmParamType, Label end) {
v.load(myMap.getIndex(parameterDescriptor), Type.INT_TYPE);
v.load(myEndVar, Type.INT_TYPE);
v.ificmpgt(end);
}
@Override
protected void generateIncrement() {
v.iinc(myMap.getIndex(parameterDescriptor), 1); // TODO support decreasing order
}
@Override
protected void cleanupTemp() {
myMap.leaveTemp(2);
}
}
@Override
public void visitBreakExpression(JetBreakExpression expression) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
@@ -444,8 +535,8 @@ public class ExpressionCodegen extends JetVisitor {
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression);
final DeclarationDescriptor container = descriptor.getContainingDeclaration();
if (descriptor instanceof VariableDescriptor) {
final DeclarationDescriptor container = descriptor.getContainingDeclaration();
if (isClass(container, "Number")) {
Type castType = getCastType(expression.getReferencedName());
if (castType != null) {
@@ -492,13 +583,20 @@ public class ExpressionCodegen extends JetVisitor {
}
}
boolean isStatic = descriptor.getContainingDeclaration() instanceof NamespaceDescriptorImpl;
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
if (!isStatic) {
if (isClass(container, "Array") && propertyDescriptor.getName().equals("size")) {
ensureReceiverOnStack(expression);
v.arraylength();
myStack.push(StackValue.onStack(Type.INT_TYPE));
}
else {
boolean isStatic = container instanceof NamespaceDescriptorImpl;
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
if (!isStatic) {
ensureReceiverOnStack(expression);
}
myStack.push(iValue);
}
myStack.push(iValue);
}
else {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
@@ -1153,43 +1251,61 @@ public class ExpressionCodegen extends JetVisitor {
@Override
public void visitNewExpression(JetNewExpression expression) {
final JetUserType constructorType = (JetUserType) expression.getTypeReference().getTypeElement();
JetTypeReference typeReference = expression.getTypeReference();
final JetUserType constructorType = (JetUserType) typeReference.getTypeElement();
final JetSimpleNameExpression constructorReference = constructorType.getReferenceExpression();
DeclarationDescriptor constructorDescriptor = bindingContext.resolveReferenceExpression(constructorReference);
final PsiElement declaration = bindingContext.getDeclarationPsiElement(constructorDescriptor);
Type type;
if (declaration instanceof PsiMethod) {
final PsiMethod constructor = (PsiMethod) declaration;
PsiClass javaClass = constructor.getContainingClass();
Type type = JetTypeMapper.psiClassType(javaClass);
v.anew(type);
v.dup();
final Method jvmConstructor = getMethodDescriptor(constructor);
pushMethodArguments(expression, jvmConstructor);
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", jvmConstructor.getDescriptor());
myStack.push(StackValue.onStack(type));
return;
type = generateJavaConstructorCall(expression, (PsiMethod) declaration);
}
else if (constructorDescriptor instanceof ConstructorDescriptor) {
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
Type type = JetTypeMapper.jetImplementationType(classDecl);
v.anew(type);
v.dup();
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
pushMethodArguments(expression, method);
for (JetTypeReference typeArgumentReference : constructorType.getTypeArgumentsAsTypes()) {
JetType typeArgument = bindingContext.resolveTypeReference(typeArgumentReference);
// TODO is the makeNullable() call correct here?
ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
type = typeMapper.mapType(bindingContext.resolveTypeReference(typeReference), OwnerKind.IMPLEMENTATION);
if (type.getSort() == Type.ARRAY) {
generateNewArray(expression, type);
}
else {
v.anew(type);
v.dup();
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
myStack.push(StackValue.onStack(type));
return;
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
pushMethodArguments(expression, method);
for (JetTypeReference typeArgumentReference : constructorType.getTypeArgumentsAsTypes()) {
JetType typeArgument = bindingContext.resolveTypeReference(typeArgumentReference);
// TODO is the makeNullable() call correct here?
ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
}
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
}
}
else {
throw new UnsupportedOperationException("don't know how to generate this new expression");
}
myStack.push(StackValue.onStack(type));
}
throw new UnsupportedOperationException("don't know how to generate this new expression");
private Type generateJavaConstructorCall(JetNewExpression expression, PsiMethod constructor) {
PsiClass javaClass = constructor.getContainingClass();
Type type = JetTypeMapper.psiClassType(javaClass);
v.anew(type);
v.dup();
final Method jvmConstructor = getMethodDescriptor(constructor);
pushMethodArguments(expression, jvmConstructor);
v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", jvmConstructor.getDescriptor());
return type;
}
private void generateNewArray(JetNewExpression expression, Type type) {
List<JetArgument> args = expression.getValueArguments();
if (args.size() != 1) {
throw new CompilationException("array constructor requires one value argument");
}
gen(args.get(0).getArgumentExpression(), Type.INT_TYPE);
v.newarray(type.getElementType());
}
@Override
@@ -1308,7 +1424,7 @@ public class ExpressionCodegen extends JetVisitor {
if (!(descriptor instanceof ClassDescriptor)) {
throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?");
}
Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE);
Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
gen(expression.getLeft(), OBJECT_TYPE);
if (opToken == JetTokens.AS_SAFE) {
generateInstanceOf(new Runnable() {
@@ -1380,7 +1496,7 @@ public class ExpressionCodegen extends JetVisitor {
if (leaveExpressionOnStack) {
v.dup();
}
Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE);
Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
v.instanceOf(type);
}
}
@@ -1487,5 +1603,11 @@ public class ExpressionCodegen extends JetVisitor {
}
private static class CompilationException extends RuntimeException {
private CompilationException() {
}
private CompilationException(String message) {
super(message);
}
}
}
@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import jet.typeinfo.TypeInfo;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -118,6 +119,10 @@ public class JetTypeMapper {
}
public Type mapType(final JetType jetType) {
return mapType(jetType, OwnerKind.INTERFACE);
}
public Type mapType(final JetType jetType, OwnerKind kind) {
if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) {
return Type.VOID_TYPE;
}
@@ -191,7 +196,7 @@ public class JetTypeMapper {
if (declaration instanceof PsiClass) {
return psiClassType((PsiClass) declaration);
}
return Type.getObjectType(jvmNameForInterface((ClassDescriptor) descriptor));
return Type.getObjectType(jetJvmName((ClassDescriptor) descriptor, kind));
}
throw new UnsupportedOperationException("Unknown type " + jetType);
@@ -92,6 +92,14 @@ public class ControlStructuresTest extends CodegenTestCase {
assertEquals("IntelliJ IDEA", main.invoke(null, new Object[] { args }));
}
public void testForInRange() throws Exception {
loadText("fun foo(sb: StringBuilder) { for(x in 1..4) sb.append(x) }");
final Method main = generateFunction();
StringBuilder stringBuilder = new StringBuilder();
main.invoke(null, stringBuilder);
assertEquals("1234", stringBuilder.toString());
}
public void testThrowCheckedException() throws Exception {
loadText("fun foo() { throw new Exception(); }");
final Method main = generateFunction();
@@ -360,6 +360,23 @@ public class NamespaceGenTest extends CodegenTestCase {
assertEquals(10, data[0]);
}
public void testArrayNew() throws Exception {
loadText("fun foo() = new Array<Int>(4)");
final Method main = generateFunction();
int[] result = (int[]) main.invoke(null);
assertEquals(4, result.length);
}
public void testArraySize() throws Exception {
loadText("fun foo(a: Array<Int>) = a.size");
System.out.println(generateToText());
final Method main = generateFunction();
Object[] args = new Object[] { new int[4] };
int result = (Integer) main.invoke(null, args);
assertEquals(4, result);
}
public void testIntRange() throws Exception {
loadText("fun foo() = 1..10");
final Method main = generateFunction();
+8
View File
@@ -17,4 +17,12 @@ public class IntRange implements Range<Integer> {
}
return item <= startValue && item >= endValue;
}
public int getStartValue() {
return startValue;
}
public int getEndValue() {
return endValue;
}
}