JStringConcatenationOp.java |
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