Logo Search packages:      
Sourcecode: janino version File versions  Download package

IClass org::codehaus::janino::UnitCompiler::compileStringConcatenation ( final Locatable  l,
IClass  type,
Java.Rvalue  operand,
Iterator  operands 
) throws CompileException [inline, private]

Parameters:
type If non-null, the first operand with that type is already on the stack
operand The next operand
operands All following operands (Iterator over Java.Rvalues)

Definition at line 4653 of file UnitCompiler.java.

                              {
        boolean operandOnStack;
        if (type != null) {
            this.stringConversion(l, type);
            operandOnStack = true;
        } else
        {
            operandOnStack = false;
        }

        // Compute list of operands and merge consecutive constant operands.
        List tmp = new ArrayList(); // Compilable
        do {
            Object cv = this.getConstantValue(operand);
            if (cv == null) {
                // Non-constant operand.
                final Java.Rvalue final_operand = operand;
                tmp.add(new Compilable() {
                    public void compile() throws CompileException {
                        UnitCompiler.this.stringConversion(l, UnitCompiler.this.compileGetValue(final_operand));
                    }
                });

                operand = operands.hasNext() ? (Java.Rvalue) operands.next() : null;
            } else
            {
                // Constant operand. Check to see whether the next operand is also constant.
                if (operands.hasNext()) {
                    operand = (Java.Rvalue) operands.next();
                    Object cv2 = this.getConstantValue(operand);
                    if (cv2 != null) {
                        StringBuffer sb = new StringBuffer(cv.toString()).append(cv2);
                        for (;;) {
                            if (!operands.hasNext()) {
                                operand = null;
                                break;
                            }
                            operand = (Java.Rvalue) operands.next();
                            Object cv3 = this.getConstantValue(operand);
                            if (cv3 == null) break;
                            sb.append(cv3);
                        }
                        cv = sb.toString();
                    }
                } else
                {
                    operand = null;
                }
                // Break long string constants up into UTF8-able chunks.
                final String[] ss = UnitCompiler.makeUTF8Able(cv.toString());
                for (int i = 0; i < ss.length; ++i) {
                    final String s = ss[i];
                    tmp.add(new Compilable() {
                        public void compile() throws CompileException {
                            UnitCompiler.this.pushConstant(l, s);
                        }
                    });
                }
            }
        } while (operand != null);

        // At this point "tmp" contains an optimized sequence of Strings (representing constant
        // portions) and Rvalues (non-constant portions).

        if (tmp.size() <= (operandOnStack ? STRING_CONCAT_LIMIT - 1: STRING_CONCAT_LIMIT)) {

            // String concatenation through "a.concat(b).concat(c)".
            for (Iterator it = tmp.iterator(); it.hasNext();) {
                Compilable c = (Compilable) it.next();
                c.compile();
                
                // Concatenate.
                if (operandOnStack) {
                    this.writeOpcode(l, Opcode.INVOKEVIRTUAL);
                    this.writeConstantMethodrefInfo(
                        Descriptor.STRING,
                        "concat",                                // classFD
                        "(" + Descriptor.STRING + ")" + Descriptor.STRING // methodMD
                    );
                } else
                {
                    operandOnStack = true;
                }
            }
            return this.iClassLoader.STRING;
        }

        // String concatenation through "new StringBuffer(a).append(b).append(c).append(d).toString()".
        Iterator it = tmp.iterator();

        String stringBuilferFD = this.isStringBuilderAvailable ? Descriptor.STRING_BUILDER : Descriptor.STRING_BUFFER;
        // "new StringBuffer(a)":
        if (operandOnStack) {
            this.writeOpcode(l, Opcode.NEW);
            this.writeConstantClassInfo(stringBuilferFD);
            this.writeOpcode(l, Opcode.DUP_X1);
            this.writeOpcode(l, Opcode.SWAP);
        } else
        {
            this.writeOpcode(l, Opcode.NEW);
            this.writeConstantClassInfo(stringBuilferFD);
            this.writeOpcode(l, Opcode.DUP);
            ((Compilable) it.next()).compile();
        }
        this.writeOpcode(l, Opcode.INVOKESPECIAL);
        this.writeConstantMethodrefInfo(
            stringBuilferFD,
            "<init>",                                // classFD
            "(" + Descriptor.STRING + ")" + Descriptor.VOID_ // methodMD
        );
        while (it.hasNext()) {
            ((Compilable) it.next()).compile();
            
            // "StringBuffer.append(b)":
            this.writeOpcode(l, Opcode.INVOKEVIRTUAL);
            this.writeConstantMethodrefInfo(
                stringBuilferFD,
                "append",                                // classFD
                "(" + Descriptor.STRING + ")" + stringBuilferFD // methodMD
            );
        }

        // "StringBuffer.toString()":
        this.writeOpcode(l, Opcode.INVOKEVIRTUAL);
        this.writeConstantMethodrefInfo(
            stringBuilferFD,
            "toString",           // classFD
            "()" + Descriptor.STRING   // methodMD
        );
        return this.iClassLoader.STRING;
    }


Generated by  Doxygen 1.6.0   Back to index