1   // Copyright 2011 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 an array initializer. Basically a list of
10   * initializing expressions.
11   */
12  
13  class JArrayInitializer
14      extends JExpression {
15  
16      /** The initializations. */
17      private ArrayList<JExpression> initials;
18  
19      /**
20       * Construct an AST node for an array initializer given the
21       * (expected) array type and initial values.
22       * 
23       * @param line
24       *                line in which this array initializer occurs
25       *                in the source file.
26       * @param expected
27       *                the type of the array we're initializing.
28       * @param initials
29       *                initializations.
30       */
31  
32      public JArrayInitializer(int line, Type expected,
33          ArrayList<JExpression> initials) {
34          super(line);
35          type = expected;
36          this.initials = initials;
37      }
38  
39      /**
40       * Analysis of array initializer involves making sure that
41       * that the type of the initials is the same as the component
42       * type.
43       * 
44       * @param context
45       *                context in which names are resolved.
46       * @return the analyzed (and possibly rewritten) AST subtree.
47       */
48  
49      public JExpression analyze(Context context) {
50          type = type.resolve(context);
51          if (!type.isArray()) {
52              JAST.compilationUnit.reportSemanticError(line,
53                  "Cannot initialize a " + type.toString()
54                      + " with an array sequence {...}");
55              return this; // un-analyzed
56          }
57          Type componentType = type.componentType();
58          for (int i = 0; i < initials.size(); i++) {
59              JExpression component = initials.get(i);
60              initials.set(i, component = component.analyze(context));
61              if (!(component instanceof JArrayInitializer)) {
62                  component.type().mustMatchExpected(line,
63                      componentType);
64              }
65          }
66          return this;
67      }
68  
69      /**
70       * Perform code generation necessary to construct the
71       * initializing array and leave it on top of the stack.
72       * 
73       * @param output
74       *                the code emitter (basically an abstraction
75       *                for producing the .class file).
76       */
77  
78      public void codegen(CLEmitter output) {
79          Type componentType = type.componentType();
80  
81          // Code to push array length.
82          new JLiteralInt(line, String.valueOf(initials.size()))
83              .codegen(output);
84  
85          // Code to create the (empty) array
86          output.addArrayInstruction(componentType.isReference()
87              ? ANEWARRAY
88              : NEWARRAY, componentType.jvmName());
89  
90          // Code to load initial values and store them as
91          // elements in the newly created array.
92          for (int i = 0; i < initials.size(); i++) {
93              JExpression initExpr = initials.get(i);
94  
95              // Duplicate the array for each element store
96              output.addNoArgInstruction(DUP);
97  
98              // Code to push index for store
99              new JLiteralInt(line, String.valueOf(i)).codegen(output);
100 
101             // Code to compute the initial value.
102             initExpr.codegen(output);
103 
104             // Code to store the initial value in the array
105         if (componentType == Type.INT) {
106         output.addNoArgInstruction(IASTORE);
107         } else if (componentType == Type.BOOLEAN) {
108         output.addNoArgInstruction(BASTORE);
109         } else if (componentType == Type.CHAR) {
110         output.addNoArgInstruction(CASTORE);
111         } else if (!componentType.isPrimitive()) {
112         output.addNoArgInstruction(AASTORE);
113         }
114         }
115     }
116 
117     /**
118      * @inheritDoc
119      */
120 
121     public void writeToStdOut(PrettyPrinter p) {
122         p.println("<JArrayInitializer>");
123         if (initials != null) {
124             for (JAST initial : initials) {
125                 p.indentRight();
126                 initial.writeToStdOut(p);
127                 p.indentLeft();
128             }
129         }
130         p.println("</JArrayInitializer>");
131     }
132 }
133