1   // Copyright 2013 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
9    * produced by the parser but by analysis of a + operation where the arguments
10   * are strings. Such operations are rewritten to be string concatenation
11   * operations.
12   */
13  
14  class JStringConcatenationOp extends JBinaryExpression {
15  
16      /**
17       * Construct an AST node for a string concatenation expression given its
18       * line number, and the lhs and rhs operands. An expression of this sort is
19       * created during the analysis of a (overloaded) + operation (and not by the
20       * Parser).
21       * 
22       * @param line
23       *            line in which the expression occurs in the source file.
24       * @param lhs
25       *            lhs operand.
26       * @param rhs
27       *            rhs operand.
28       */
29  
30      public JStringConcatenationOp(int line, JExpression lhs, JExpression rhs) {
31          super(line, "+", lhs, rhs);
32      }
33  
34      /**
35       * Analysis is simple here. The operands have already been analyzed (in
36       * JPlusOp) so we simply set the result type.
37       * 
38       * @param context
39       *            context in which names are resolved.
40       * @return the analyzed (and possibly rewritten) AST subtree.
41       */
42  
43      public JExpression analyze(Context context) {
44          type = Type.STRING;
45          return this;
46      }
47  
48      /**
49       * Code generation generates code for creating a StringBuilder atop the
50       * runtime stack, appending the operands (which might contain nested
51       * concatenations; these are handled by cascadingCodegen()), and then for
52       * converting the StringBuilder to a String.
53       * 
54       * @param output
55       *            the code emitter (basically an abstraction for producing the
56       *            .class file).
57       */
58  
59      public void codegen(CLEmitter output) {
60          // Firstly, create a StringBuilder
61          output.addReferenceInstruction(NEW, "java/lang/StringBuilder");
62          output.addNoArgInstruction(DUP);
63          output.addMemberAccessInstruction(INVOKESPECIAL,
64                  "java/lang/StringBuilder", "<init>", "()V");
65  
66          // Lhs and Rhs
67          nestedCodegen(output);
68  
69          // Finally, make into a String
70          output.addMemberAccessInstruction(INVOKEVIRTUAL,
71                  "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
72      }
73  
74      /**
75       * Like a codegen() but we needn't (and shouldn't) create a StringBuilder
76       * nor convert the result to a String, as that will be done in a parent.
77       * 
78       * @param output
79       *            the code emitter (basically an abstraction for producing the
80       *            .class file).
81       */
82  
83      void nestedCodegen(CLEmitter output) {
84          // Lhs
85          if (lhs instanceof JStringConcatenationOp) {
86              // This appends lhs
87              ((JStringConcatenationOp) lhs).nestedCodegen(output);
88          } else {
89              lhs.codegen(output);
90              output.addMemberAccessInstruction(INVOKEVIRTUAL,
91                      "java/lang/StringBuilder", "append", "("
92                              + lhs.type().argumentTypeForAppend()
93                              + ")Ljava/lang/StringBuilder;");
94          }
95  
96          // Rhs
97          if (rhs instanceof JStringConcatenationOp) {
98              // This appends rhs
99              ((JStringConcatenationOp) rhs).nestedCodegen(output);
100         } else {
101             rhs.codegen(output);
102             output.addMemberAccessInstruction(INVOKEVIRTUAL,
103                     "java/lang/StringBuilder", "append", "("
104                             + rhs.type().argumentTypeForAppend()
105                             + ")Ljava/lang/StringBuilder;");
106         }
107     }
108 
109 }
110