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