1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   
7   import static jminusminus.CLConstants.*;
8   
9   /**
10   * The AST node for a this(...) constructor.
11   */
12  class JThisConstruction extends JExpression {
13      // Arguments to the constructor.
14      private ArrayList<JExpression> arguments;
15  
16      // Constructor representation of the constructor.
17      private Constructor constructor;
18  
19      // Types of arguments.
20      private Type[] argTypes;
21  
22      // Whether this constructor is used properly, ie, as the first statement within a constructor.
23      private boolean properUseOfConstructor;
24  
25      /**
26       * Constructs the AST node for a this(...) constructor.
27       *
28       * @param line      line in which the constructor occurs in the source file.
29       * @param arguments the constructor's arguments.
30       */
31      protected JThisConstruction(int line, ArrayList<JExpression> arguments) {
32          super(line);
33          this.arguments = arguments;
34          properUseOfConstructor = false;
35      }
36  
37      /**
38       * Marks this(...) as being properly placed, ie, as the first statement in its body.
39       */
40      public void markProperUseOfConstructor() {
41          properUseOfConstructor = true;
42      }
43  
44      /**
45       * {@inheritDoc}
46       */
47      public JExpression analyze(Context context) {
48          type = Type.VOID;
49  
50          // Analyze the arguments, collecting their types (in Class form) as argTypes.
51          argTypes = new Type[arguments.size()];
52          for (int i = 0; i < arguments.size(); i++) {
53              arguments.set(i, (JExpression) arguments.get(i).analyze(context));
54              argTypes[i] = arguments.get(i).type();
55          }
56  
57          if (!properUseOfConstructor) {
58              JAST.compilationUnit.reportSemanticError(line(),
59                      "this" + Type.argTypesAsString(argTypes)
60                      + " must be first statement in the constructor's body");
61              return this;
62          }
63  
64          // Get the constructor this(...) refers to..
65          constructor =
66                  ((JTypeDecl) context.classContext.definition()).thisType().constructorFor(argTypes);
67  
68          if (constructor == null) {
69              JAST.compilationUnit.reportSemanticError(line(),
70                      "No such constructor: this" + Type.argTypesAsString(argTypes));
71  
72          }
73          return this;
74      }
75  
76      /**
77       * {@inheritDoc}
78       */
79      public void codegen(CLEmitter output) {
80          output.addNoArgInstruction(ALOAD_0); // this
81          for (JExpression argument : arguments) {
82              argument.codegen(output);
83          }
84          output.addMemberAccessInstruction(INVOKESPECIAL, constructor.declaringType().jvmName(),
85                  "<init>", constructor.toDescriptor());
86      }
87  
88      /**
89       * {@inheritDoc}
90       */
91      public void toJSON(JSONElement json) {
92          JSONElement e = new JSONElement();
93          json.addChild("JThisConstruction:" + line, e);
94          if (arguments != null) {
95              for (JExpression argument : arguments) {
96                  JSONElement e1 = new JSONElement();
97                  e.addChild("Argument", e1);
98                  argument.toJSON(e1);
99              }
100         }
101     }
102 }
103