1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import static jminusminus.CLConstants.*;
6   
7   /**
8    * The AST node for a string concatenation operation. Nodes of this type are not produced by the
9    * parser, but by analysis of a + operation where the arguments are strings. Such operations are
10   * rewritten to be string concatenation operations.
11   */
12  class JStringConcatenationOp extends JBinaryExpression {
13      /**
14       * Constructs an AST node for a string concatenation expression.
15       *
16       * @param line line in which the expression occurs in the source file.
17       * @param lhs  lhs operand.
18       * @param rhs  rhs operand.
19       */
20      public JStringConcatenationOp(int line, JExpression lhs, JExpression rhs) {
21          super(line, "+", lhs, rhs);
22      }
23  
24      /**
25       * {@inheritDoc}
26       */
27      public JExpression analyze(Context context) {
28          type = Type.STRING;
29          return this;
30      }
31  
32      /**
33       * {@inheritDoc}
34       */
35      public void codegen(CLEmitter output) {
36          // Firstly, create a StringBuilder.
37          output.addReferenceInstruction(NEW, "java/lang/StringBuilder");
38          output.addNoArgInstruction(DUP);
39          output.addMemberAccessInstruction(INVOKESPECIAL, "java/lang/StringBuilder", "<init>",
40                  "()V");
41  
42          // Lhs and Rhs.
43          nestedCodegen(output);
44  
45          // Finally, make into a String.
46          output.addMemberAccessInstruction(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString",
47                  "()Ljava/lang/String;");
48      }
49  
50      // Like codegen() method, but we needn't (and shouldn't) create a StringBuilder nor convert
51      // the result to a String, as that will be done in a parent.
52      private void nestedCodegen(CLEmitter output) {
53          // Lhs.
54          if (lhs instanceof JStringConcatenationOp) {
55              // This appends lhs
56              ((JStringConcatenationOp) lhs).nestedCodegen(output);
57          } else {
58              lhs.codegen(output);
59              output.addMemberAccessInstruction(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
60                      "(" + lhs.type().argumentTypeForAppend() + ")Ljava/lang/StringBuilder;");
61          }
62  
63          // Rhs.
64          if (rhs instanceof JStringConcatenationOp) {
65              // This appends rhs.
66              ((JStringConcatenationOp) rhs).nestedCodegen(output);
67          } else {
68              rhs.codegen(output);
69              output.addMemberAccessInstruction(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
70                      "(" + rhs.type().argumentTypeForAppend() + ")Ljava/lang/StringBuilder;");
71          }
72      }
73  }
74