1   // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   import static jminusminus.CLConstants.*;
7   
8   /**
9    * The AST node for a super(...) constructor.
10   */
11  
12  class JSuperConstruction extends JExpression {
13  
14      /** Arguments to the constructor. */
15      private ArrayList<JExpression> arguments;
16  
17      /** Constructor representation of the constructor. */
18      private Constructor constructor;
19  
20      /** Types of arguments. */
21      private Type[] argTypes;
22  
23      /**
24       * Whether this constructor is used properly, ie, as the first statement
25       * within a constructor.
26       */
27      private boolean properUseOfConstructor = false;
28  
29      /**
30       * Construct an AST node for a super(...) constructor given its line number
31       * and arguments.
32       * 
33       * @param line
34       *            line in which the constructor occurs in the source file.
35       * @param arguments
36       *            the constructor's arguments.
37       */
38  
39      protected JSuperConstruction(int line, ArrayList<JExpression> arguments) {
40          super(line);
41          this.arguments = arguments;
42      }
43  
44      /**
45       * Used in JConstructorDeclaration to mark super(...) as being properly
46       * placed, ie, as the first statement in its body.
47       */
48  
49      public void markProperUseOfConstructor() {
50          properUseOfConstructor = true;
51      }
52  
53      /**
54       * Analyzing a super constructor statement involves (1) setting the type,
55       * (2) analyzing the actual arguments, and (3) checking that this
56       * construction statement is properly invoked (as the first statement in
57       * another constructor).
58       * 
59       * @param context
60       *            context in which names are resolved.
61       * @return the analyzed (and possibly rewritten) AST subtree.
62       */
63  
64      public JExpression analyze(Context context) {
65          type = Type.VOID;
66  
67          // Analyze the arguments, collecting
68          // their types (in Class form) as argTypes.
69          argTypes = new Type[arguments.size()];
70          for (int i = 0; i < arguments.size(); i++) {
71              arguments.set(i, (JExpression) arguments.get(i).analyze(context));
72              argTypes[i] = arguments.get(i).type();
73          }
74  
75          if (!properUseOfConstructor) {
76              JAST.compilationUnit.reportSemanticError(line(), "super"
77                      + Type.argTypesAsString(argTypes)
78                      + " must be first statement in the constructor's body.");
79              return this;
80          }
81  
82          // Get the Constructor super(...) refers to
83          Type superClass = ((JTypeDecl) context.classContext.definition())
84                  .thisType().superClass();
85          if (superClass == null) {
86              JAST.compilationUnit.reportSemanticError(line,
87                      ((JTypeDecl) context.classContext.definition()).thisType()
88                              + " has no super class.");
89          }
90          constructor = superClass.constructorFor(argTypes);
91  
92          if (constructor == null) {
93              JAST.compilationUnit.reportSemanticError(line(),
94                      "No such constructor: super"
95                              + Type.argTypesAsString(argTypes));
96  
97          }
98          return this;
99      }
100 
101     /**
102      * Code generation involves generating code to load the actual arguments
103      * onto the stack, and then the code for invoking the constructor.
104      * 
105      * @param output
106      *            the code emitter (basically an abstraction for producing the
107      *            .class file).
108      */
109 
110     public void codegen(CLEmitter output) {
111         output.addNoArgInstruction(ALOAD_0); // this
112         for (JExpression argument : arguments) {
113             argument.codegen(output);
114         }
115         output.addMemberAccessInstruction(INVOKESPECIAL, constructor
116                 .declaringType().jvmName(), "<init>", constructor
117                 .toDescriptor());
118     }
119 
120     /**
121      * @inheritDoc
122      */
123 
124     public void writeToStdOut(PrettyPrinter p) {
125         p.printf("<JSuperConstruction line=\"%d\"/>\n", line());
126         p.indentRight();
127         if (arguments != null) {
128             p.println("<Arguments>");
129             for (JExpression argument : arguments) {
130                 p.indentRight();
131                 p.println("<Argument>");
132                 p.indentRight();
133                 argument.writeToStdOut(p);
134                 p.indentLeft();
135                 p.println("</Argument>");
136                 p.indentLeft();
137             }
138             p.println("</Arguments>");
139         }
140         p.indentLeft();
141         p.println("</JSuperConstruction>");
142     }
143 
144 }
145