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
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
\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
\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