List<Exprent> (List<PooledConstant> bootstrapArguments, InvocationExprent expr) { List<Exprent> parameters = expr.getParameters(); if (bootstrapArguments != null) { PooledConstant constant = bootstrapArguments.get(0); if (constant.type == CodeConstants.CONSTANT_String) { String recipe = ((PrimitiveConstant)constant).getString(); List<Exprent> res = new ArrayList<>(); StringBuilder acc = new StringBuilder(); int parameterId = 0; int bootstrapArgumentId = 1; for (int i = 0; i < recipe.length(); i++) { char c = recipe.charAt(i); if (c == TAG_CONST || c == TAG_ARG) { // Detected a special tag, flush all accumulated characters // as a constant first: if (acc.length() > 0) { res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode)); acc.setLength(0); } if (c == TAG_CONST) { PooledConstant pooledConstant = bootstrapArguments.get(bootstrapArgumentId++); if (pooledConstant.type == CodeConstants.CONSTANT_String) { res.add(new ConstExprent(VarType.VARTYPE_STRING, ((PrimitiveConstant) pooledConstant).getString(), expr.bytecode)); } } if (c == TAG_ARG) { Exprent exprent = parameters.get(parameterId++); if ((exprent instanceof VarExprent varExprent) && res.isEmpty()) { if (!VarType.VARTYPE_STRING.equals(varExprent.getVarType())) { // First item of concatenation is a variable and variable's type is not a String. // Prepend it with empty string literal to force resulting expression type to be String. res.add(new ConstExprent(VarType.VARTYPE_STRING, "", expr.bytecode)); } } res.add(exprent); } } else { // Not a special characters, this is a constant embedded into // the recipe itself. acc.append(c); } } // Flush the remaining characters as constant: if (acc.length() > 0) { res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode)); } if (res.size() == 1) { // // Only one element in result list. // The most probable cause is an empty prefix/suffix. // Something like this: // // return "" + value; // // NOTE: Empty suffix is indistinguishable from empty prefix. We always assume latter. // res.add(0, new ConstExprent(VarType.VARTYPE_STRING, "", expr.bytecode)); } return res; } } return new ArrayList<>(parameters); }