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 super(...) constructor.
11   */
12  class JSuperConstruction 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 an AST node for a super(...) 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 JSuperConstruction(int line, ArrayList<JExpression> arguments) {
32          super(line);
33          this.arguments = arguments;
34          properUseOfConstructor = false;
35      }
36  
37      /**
38       * Marks super(...) 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                      "super" + Type.argTypesAsString(argTypes)
60                      + " must be first statement in the constructor's body");
61              return this;
62          }
63  
64          // Get the Constructor super(...) refers to.
65          Type superClass = ((JTypeDecl) context.classContext.definition()).thisType().superClass();
66          if (superClass == null) {
67              JAST.compilationUnit.reportSemanticError(line,
68                      ((JTypeDecl) context.classContext.definition()).thisType() +
69                              " has no super class");
70          }
71          constructor = superClass.constructorFor(argTypes);
72          if (constructor == null) {
73              JAST.compilationUnit.reportSemanticError(line(),
74                      "No such constructor: super" + Type.argTypesAsString(argTypes));
75          }
76  
77          return this;
78      }
79  
80      /**
81       * {@inheritDoc}
82       */
83      public void codegen(CLEmitter output) {
84          output.addNoArgInstruction(ALOAD_0); // this
85          for (JExpression argument : arguments) {
86              argument.codegen(output);
87          }
88          output.addMemberAccessInstruction(INVOKESPECIAL, constructor.declaringType().jvmName(),
89                  "<init>", constructor.toDescriptor());
90      }
91  
92      /**
93       * {@inheritDoc}
94       */
95      public void toJSON(JSONElement json) {
96          JSONElement e = new JSONElement();
97          json.addChild("JSuperConstruction:" + line, e);
98          if (arguments != null) {
99              for (JExpression argument : arguments) {
100                 JSONElement e1 = new JSONElement();
101                 e.addChild("Argument", e1);
102                 argument.toJSON(e1);
103             }
104         }
105     }
106 }
107