+= for strings is intrinsic
This commit is contained in:
@@ -78,6 +78,8 @@ class String() : Comparable<String> {
|
|||||||
val length : Int
|
val length : Int
|
||||||
|
|
||||||
fun plus(other : Any?) : String
|
fun plus(other : Any?) : String
|
||||||
|
fun plusAssign(other: Any?): String
|
||||||
|
|
||||||
fun equals(other : Any?) : Boolean
|
fun equals(other : Any?) : Boolean
|
||||||
fun equalsIgnoreCase(other: String?) : Boolean
|
fun equalsIgnoreCase(other: String?) : Boolean
|
||||||
|
|
||||||
|
|||||||
@@ -799,19 +799,19 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue invokeFunction(JetCallExpression expression, FunctionDescriptor fd, boolean haveReceiver) {
|
private StackValue invokeFunction(JetCallExpression expression, DeclarationDescriptor fd, boolean haveReceiver) {
|
||||||
Callable callableMethod = resolveToCallable(fd);
|
Callable callableMethod = resolveToCallable(fd);
|
||||||
return invokeCallable(fd, callableMethod, expression, haveReceiver);
|
return invokeCallable(fd, callableMethod, expression, haveReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private StackValue invokeCallable(FunctionDescriptor fd, Callable callable, JetCallExpression expression, boolean haveReceiver) {
|
private StackValue invokeCallable(DeclarationDescriptor fd, Callable callable, JetCallExpression expression, boolean haveReceiver) {
|
||||||
if (callable instanceof CallableMethod) {
|
if (callable instanceof CallableMethod) {
|
||||||
final CallableMethod callableMethod = (CallableMethod) callable;
|
final CallableMethod callableMethod = (CallableMethod) callable;
|
||||||
invokeMethodWithArguments(callableMethod, expression, haveReceiver);
|
invokeMethodWithArguments(callableMethod, expression, haveReceiver);
|
||||||
|
|
||||||
final Type callReturnType = callableMethod.getSignature().getReturnType();
|
final Type callReturnType = callableMethod.getSignature().getReturnType();
|
||||||
return returnValueAsStackValue(fd, callReturnType);
|
return returnValueAsStackValue((FunctionDescriptor) fd, callReturnType);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||||
@@ -832,7 +832,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Callable resolveToCallable(FunctionDescriptor fd) {
|
private Callable resolveToCallable(DeclarationDescriptor fd) {
|
||||||
final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(fd);
|
final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(fd);
|
||||||
if (intrinsic != null) {
|
if (intrinsic != null) {
|
||||||
return intrinsic;
|
return intrinsic;
|
||||||
@@ -843,8 +843,11 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) {
|
if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) {
|
||||||
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement);
|
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement);
|
||||||
}
|
}
|
||||||
|
else if (fd instanceof FunctionDescriptor) {
|
||||||
|
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
callableMethod = ClosureCodegen.asCallableMethod(fd);
|
throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd);
|
||||||
}
|
}
|
||||||
return callableMethod;
|
return callableMethod;
|
||||||
}
|
}
|
||||||
@@ -1090,22 +1093,20 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
|
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
|
||||||
if (op instanceof FunctionDescriptor) {
|
final Callable callable = resolveToCallable(op);
|
||||||
final Callable callable = resolveToCallable((FunctionDescriptor) op);
|
if (callable instanceof IntrinsicMethod) {
|
||||||
if (callable instanceof IntrinsicMethod) {
|
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||||
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
myStack.push(intrinsic.generate(this, v, expressionType(expression), expression,
|
||||||
myStack.push(intrinsic.generate(this, v, expressionType(expression), expression,
|
Arrays.asList(expression.getLeft(), expression.getRight()), false));
|
||||||
Arrays.asList(expression.getLeft(), expression.getRight()), false));
|
}
|
||||||
}
|
else {
|
||||||
else {
|
CallableMethod callableMethod = (CallableMethod) callable;
|
||||||
CallableMethod callableMethod = (CallableMethod) callable;
|
genToJVMStack(expression.getLeft());
|
||||||
genToJVMStack(expression.getLeft());
|
genToJVMStack(expression.getRight());
|
||||||
genToJVMStack(expression.getRight());
|
callableMethod.invoke(v);
|
||||||
callableMethod.invoke(v);
|
final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType());
|
||||||
final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType());
|
if (value != null) {
|
||||||
if (value != null) {
|
myStack.push(value);
|
||||||
myStack.push(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1265,28 +1266,31 @@ 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 Callable callable = resolveToCallable(op);
|
||||||
final JetExpression lhs = expression.getLeft();
|
final JetExpression lhs = expression.getLeft();
|
||||||
Type lhsType = expressionType(lhs);
|
Type lhsType = expressionType(lhs);
|
||||||
if (isNumberPrimitive(lhsType)) {
|
if (bindingContext.isVariableReassignment(expression)) {
|
||||||
StackValue value = generateIntermediateValue(lhs); // receiver
|
if (isNumberPrimitive(lhsType)) {
|
||||||
value.dupReceiver(v, 0); // receiver receiver
|
StackValue value = generateIntermediateValue(lhs); // receiver
|
||||||
value.put(lhsType, v); // receiver lhs
|
value.dupReceiver(v, 0); // receiver receiver
|
||||||
genToJVMStack(expression.getRight()); // receiver lhs rhs
|
value.put(lhsType, v); // receiver lhs
|
||||||
v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result
|
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
|
else {
|
||||||
StackValue value = generateIntermediateValue(lhs); // StringBuilder receiver
|
throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented");
|
||||||
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 {
|
else {
|
||||||
throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented");
|
if (callable instanceof IntrinsicMethod) {
|
||||||
|
final IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||||
|
intrinsic.generate(this, v, Type.VOID_TYPE, expression, Arrays.asList(lhs, expression.getRight()), false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1312,7 +1316,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
invokeAppendMethod(exprType);
|
invokeAppendMethod(exprType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeAppendMethod(Type exprType) {
|
public 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());
|
||||||
@@ -1359,7 +1363,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Callable callable = resolveToCallable((FunctionDescriptor) op);
|
final Callable callable = resolveToCallable(op);
|
||||||
if (callable instanceof IntrinsicMethod) {
|
if (callable instanceof IntrinsicMethod) {
|
||||||
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||||
myStack.push(intrinsic.generate(this, v, expressionType(unaryExpression), unaryExpression,
|
myStack.push(intrinsic.generate(this, v, expressionType(unaryExpression), unaryExpression,
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public class IntrinsicMethods {
|
|||||||
declareIntrinsicFunction("Boolean", "not", 0, new Not());
|
declareIntrinsicFunction("Boolean", "not", 0, new Not());
|
||||||
|
|
||||||
declareIntrinsicFunction("String", "plus", 1, new Concat());
|
declareIntrinsicFunction("String", "plus", 1, new Concat());
|
||||||
|
declareIntrinsicFunction("String", "plusAssign", 1, new PlusConcat());
|
||||||
|
|
||||||
declareIntrinsicStringMethods();
|
declareIntrinsicStringMethods();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
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 PlusConcat implements IntrinsicMethod {
|
||||||
|
@Override
|
||||||
|
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
|
||||||
|
final JetExpression lhs = arguments.get(0);
|
||||||
|
final Type lhsType = codegen.expressionType(lhs);
|
||||||
|
codegen.generateStringBuilderConstructor(); // StringBuilder
|
||||||
|
StackValue value = codegen.generateIntermediateValue(lhs); // StringBuilder receiver
|
||||||
|
value.dupReceiver(v, 1); // receiver StringBuilder receiver
|
||||||
|
value.put(lhsType, v); // receiver StringBuilder value
|
||||||
|
codegen.invokeAppendMethod(lhsType); // receiver StringBuilder
|
||||||
|
codegen.invokeAppend(arguments.get(1)); // receiver StringBuilder
|
||||||
|
v.invokevirtual(ExpressionCodegen.CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
|
||||||
|
value.store(v);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user