+= for strings

This commit is contained in:
Dmitry Jemerov
2011-04-28 16:27:13 +02:00
parent bca39bf21f
commit da6b4a9595
5 changed files with 75 additions and 17 deletions
@@ -828,25 +828,44 @@ public class ExpressionCodegen extends JetVisitor {
private void generateAugmentedAssignment(JetBinaryExpression expression) { private void generateAugmentedAssignment(JetBinaryExpression expression) {
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
final JetExpression lhs = expression.getLeft(); final JetExpression lhs = expression.getLeft();
Type asmType = expressionType(lhs); Type lhsType = expressionType(lhs);
StackValue value = generateIntermediateValue(lhs); if (isNumberPrimitive(lhsType)) {
value.dupReceiver(v); StackValue value = generateIntermediateValue(lhs); // receiver
value.put(asmType, v); value.dupReceiver(v, 0); // receiver receiver
genToJVMStack(expression.getRight()); value.put(lhsType, v); // receiver lhs
v.visitInsn(asmType.getOpcode(opcodeForMethod(op.getName()))); genToJVMStack(expression.getRight()); // receiver lhs rhs
value.store(v); v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result
value.store(v);
}
else if ("java.lang.String".equals(lhsType.getClassName()) && op.getName().equals("plus")) {
generateStringBuilderConstructor(); // StringBuilder
StackValue value = generateIntermediateValue(lhs); // StringBuilder receiver
value.dupReceiver(v, 1); // receiver StringBuilder receiver
value.put(lhsType, v); // receiver StringBuilder value
invokeAppendMethod(lhsType); // receiver StringBuilder
invokeAppend(expression.getRight()); // receiver StringBuilder
v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
value.store(v);
}
else {
throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented");
}
} }
private void generateConcatenation(JetBinaryExpression expression) { private void generateConcatenation(JetBinaryExpression expression) {
generateStringBuilderConstructor();
invokeAppend(expression.getLeft());
invokeAppend(expression.getRight());
v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
myStack.push(StackValue.onStack(Type.getObjectType(CLASS_STRING)));
}
private void generateStringBuilderConstructor() {
Type type = Type.getObjectType(CLASS_STRING_BUILDER); Type type = Type.getObjectType(CLASS_STRING_BUILDER);
v.anew(type); v.anew(type);
v.dup(); v.dup();
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]); Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
v.invokespecial(CLASS_STRING_BUILDER, method.getName(), method.getDescriptor()); v.invokespecial(CLASS_STRING_BUILDER, method.getName(), method.getDescriptor());
invokeAppend(expression.getLeft());
invokeAppend(expression.getRight());
v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
myStack.push(StackValue.onStack(Type.getObjectType(CLASS_STRING)));
} }
private void invokeAppend(final JetExpression expr) { private void invokeAppend(final JetExpression expr) {
@@ -860,6 +879,10 @@ public class ExpressionCodegen extends JetVisitor {
} }
Type exprType = expressionType(expr); Type exprType = expressionType(expr);
gen(expr, exprType); gen(expr, exprType);
invokeAppendMethod(exprType);
}
private void invokeAppendMethod(Type exprType) {
Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER), Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType}); new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor()); v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
@@ -934,7 +957,7 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
StackValue value = generateIntermediateValue(operand); StackValue value = generateIntermediateValue(operand);
value.dupReceiver(v); value.dupReceiver(v, 0);
value.put(asmType, v); value.put(asmType, v);
if (asmType == Type.LONG_TYPE) { if (asmType == Type.LONG_TYPE) {
v.aconst(Long.valueOf(increment)); v.aconst(Long.valueOf(increment));
@@ -24,7 +24,7 @@ public abstract class StackValue {
throw new UnsupportedOperationException("cannot store to value " + this); throw new UnsupportedOperationException("cannot store to value " + this);
} }
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v, int below) {
} }
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
@@ -341,8 +341,13 @@ public abstract class StackValue {
} }
@Override @Override
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v, int below) {
v.dup2(); // array and index if (below == 1) {
v.dup2X1();
}
else {
v.dup2(); // array and index
}
} }
} }
@@ -364,8 +369,15 @@ public abstract class StackValue {
} }
@Override @Override
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v, int below) {
if (!isStatic) v.dup(); if (!isStatic) {
if (below == 1) {
v.dupX1();
}
else {
v.dup();
}
}
} }
@Override @Override
@@ -0,0 +1,7 @@
var collector: String = ""
set(it) { $collector += it }
fun append(s: String): String {
collector = s;
return collector;
}
@@ -259,6 +259,13 @@ public class NamespaceGenTest extends CodegenTestCase {
assertEquals("jet Lang", main.invoke(null, "jet", " ", "Lang")); assertEquals("jet Lang", main.invoke(null, "jet", " ", "Lang"));
} }
public void testStringPlusEq() throws Exception {
loadText("fun foo(s: String) { val result = s; result += s; return result; } ");
System.out.println(generateToText());
final Method main = generateFunction();
assertEquals("JarJar", main.invoke(null, "Jar"));
}
public void testStringCompare() throws Exception { public void testStringCompare() throws Exception {
loadText("fun foo(s1: String, s2: String) = s1 < s2"); loadText("fun foo(s1: String, s2: String) = s1 < s2");
System.out.println(generateToText()); System.out.println(generateToText());
@@ -81,6 +81,15 @@ public class PropertyGenTest extends CodegenTestCase {
assertEquals(value, "IntelliJ IDEA"); assertEquals(value, "IntelliJ IDEA");
} }
public void testFieldSetterPlusEq() throws Exception {
loadFile("fieldSetterPlusEq.jet");
System.out.println(generateToText());
final Method method = generateFunction("append");
method.invoke(null, "IntelliJ ");
String value = (String) method.invoke(null, "IDEA");
assertEquals(value, "IntelliJ IDEA");
}
public void testAccessorsWithoutBody() throws Exception { public void testAccessorsWithoutBody() throws Exception {
loadText("class AccessorsWithoutBody() { public var foo: Int = 349\n get\n private set\n fun setter() { foo = 610; } } "); loadText("class AccessorsWithoutBody() { public var foo: Int = 349\n get\n private set\n fun setter() { foo = 610; } } ");
final Class aClass = loadImplementationClass(generateClassesInFile(), "AccessorsWithoutBody"); final Class aClass = loadImplementationClass(generateClassesInFile(), "AccessorsWithoutBody");