X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fconstants%2FStringInterpolation.java;h=9b3bbca92a342dfa6a0fa774f9d10c82d60d57d7;hp=55bba560472aaced6f5b74925dd953d436c8cb29;hb=3448b94a8e90047c88eb62a0542c1596acb701b8;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/StringInterpolation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/StringInterpolation.java index 55bba5604..9b3bbca92 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/StringInterpolation.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/StringInterpolation.java @@ -1,8 +1,16 @@ package org.simantics.scl.compiler.constants; +import java.util.Arrays; + import org.cojen.classfile.TypeDesc; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.internal.codegen.continuations.Cont; +import org.simantics.scl.compiler.internal.codegen.references.IVal; import org.simantics.scl.compiler.internal.codegen.references.Val; import org.simantics.scl.compiler.internal.codegen.utils.Constants; +import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; @@ -22,6 +30,22 @@ public class StringInterpolation extends FunctionValue { public StringInterpolation(String[] textParts) { this(stringTypeArray(textParts.length-1), textParts); } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append('"'); + boolean first = true; + for(String textPart : textParts) { + if(first) + first = false; + else + b.append("\\(.)"); + b.append(textPart); + } + b.append('"'); + return b.toString(); + } private static Type[] stringTypeArray(int length) { Type[] result = new Type[length]; @@ -32,6 +56,37 @@ public class StringInterpolation extends FunctionValue { @Override public Type applyExact(MethodBuilder mb, Val[] parameters) { + if(textParts.length==1) { + mb.loadConstant(textParts[0]); + } + else if(textParts.length==2) { + if(parameters[0].getType() == Types.STRING) { + // Optimized special cases "asd" + x, x + "asd" + if(textParts[0].isEmpty()) { + mb.push(parameters[0], Types.STRING); + if(!textParts[1].isEmpty()) { + mb.loadConstant(textParts[1]); + mb.invokeVirtual("java/lang/String", "concat", TypeDesc.STRING, new TypeDesc[] {TypeDesc.STRING}); + } + return Types.STRING; + } + else if(textParts[1].isEmpty()) { + mb.loadConstant(textParts[0]); + mb.push(parameters[0], Types.STRING); + mb.invokeVirtual("java/lang/String", "concat", TypeDesc.STRING, new TypeDesc[] {TypeDesc.STRING}); + return Types.STRING; + } + } + } + else if(textParts.length==3) { + if(parameters[0].getType() == Types.STRING && parameters[1].getType() == Types.STRING + && textParts[0].isEmpty() && textParts[1].isEmpty() && textParts[2].isEmpty()) { + mb.push(parameters[0], Types.STRING); + mb.push(parameters[1], Types.STRING); + mb.invokeVirtual("java/lang/String", "concat", TypeDesc.STRING, new TypeDesc[] {TypeDesc.STRING}); + return Types.STRING; + } + } mb.newObject(STRING_BUILDER); mb.dup(); mb.invokeConstructor(STRING_BUILDER, Constants.EMPTY_TYPEDESC_ARRAY); @@ -60,5 +115,55 @@ public class StringInterpolation extends FunctionValue { return Types.STRING; } + + @Override + public int hashCode() { + return Arrays.hashCode(textParts) ^ Arrays.hashCode(parameterTypes); + } + @Override + public boolean equals(Object obj) { + if(this == obj) + return true; + if(obj == null || obj.getClass() != getClass()) + return false; + StringInterpolation other = (StringInterpolation)obj; + return Arrays.equals(textParts, other.textParts) && Arrays.equals(parameterTypes, other.parameterTypes); + } + + @Override + public int constructorTag() { + return textParts.length == 2 && parameterTypes[0] == Types.STRING ? 0 : -1; + } + + @Override + public void deconstruct(MethodBuilder mb, IVal parameter, Cont success, Label failure) { + if(textParts.length != 2) + throw new InternalCompilerError("String interpolation with more than one open string parts cannot be used as a pattern."); + mb.push(parameter, Types.STRING); + LocalVariable temp = mb.createLocalVariable(null, TypeDesc.STRING); + mb.storeLocal(temp); + if(!textParts[0].isEmpty()) { + mb.loadLocal(temp); + mb.loadConstant(textParts[0]); + mb.invokeVirtual("java/lang/String", "startsWith", TypeDesc.BOOLEAN, new TypeDesc[] {TypeDesc.STRING}); + mb.ifZeroComparisonBranch(failure, "=="); + } + if(!textParts[1].isEmpty()) { + mb.loadLocal(temp); + mb.loadConstant(textParts[1]); + mb.invokeVirtual("java/lang/String", "endsWith", TypeDesc.BOOLEAN, new TypeDesc[] {TypeDesc.STRING}); + mb.ifZeroComparisonBranch(failure, "=="); + } + mb.loadLocal(temp); + mb.loadConstant(textParts[0].length()); + mb.loadLocal(temp); + mb.invokeVirtual("java/lang/String", "length", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY); + mb.loadConstant(textParts[1].length()); + mb.math(Opcodes.ISUB); + mb.invokeVirtual("java/lang/String", "substring", TypeDesc.STRING, new TypeDesc[] {TypeDesc.INT, TypeDesc.INT}); + mb.storeLocal(temp); + mb.jump(success, new LocalVariableConstant(Types.STRING, temp)); + } + }