1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   
7   /**
8    * JAST is the abstract superclass of all nodes in the abstract syntax tree (AST).
9    */
10  abstract class JAST {
11      /**
12       * Current compilation unit (set in JCompilationUnit()).
13       */
14      public static JCompilationUnit compilationUnit;
15  
16      /**
17       * Line in which the source for the AST was found.
18       */
19      protected int line;
20  
21      /**
22       * Constructs an AST node the given its line number in the source file.
23       *
24       * @param line line in which the source for the AST was found.
25       */
26      protected JAST(int line) {
27          this.line = line;
28      }
29  
30      /**
31       * Returns the line in which the source for the AST was found.
32       *
33       * @return the line in which the source for the AST was found.
34       */
35      public int line() {
36          return line;
37      }
38  
39      /**
40       * Performs semantic analysis on this AST and returns the (possibly modified) AST.
41       *
42       * @param context the environment (scope) in which code is analyzed.
43       * @return the (possibly modified) AST.
44       */
45      public abstract JAST analyze(Context context);
46  
47      /**
48       * Generates a partial class for a type, reflecting only the member information required to
49       * do analysis.
50       *
51       * @param context the parent (class) context.
52       * @param partial the code emitter.
53       */
54      public void partialCodegen(Context context, CLEmitter partial) {
55          // A dummy -- redefined where necessary.
56      }
57  
58      /**
59       * Performs code generation for this AST.
60       *
61       * @param output the code emitter.
62       */
63      public abstract void codegen(CLEmitter output);
64  
65      /**
66       * Stores information about this AST in JSON format.
67       *
68       * @param json the JSON emitter.
69       */
70      public void toJSON(JSONElement json) {
71          // Nothing here.
72      }
73  
74      /**
75       * Unescapes the escaped characters in the specified string and returns the unescaped string.
76       *
77       * @param s string to unescape.
78       * @return the unescaped string.
79       */
80      public static String unescape(String s) {
81          StringBuffer b = new StringBuffer();
82          for (int i = 0; i < s.length(); i++) {
83              char c = s.charAt(i);
84              if (c == '\\') {
85                  i++;
86                  if (i >= s.length()) {
87                      break;
88                  }
89                  c = s.charAt(i);
90                  switch (c) {
91                      case 'b':
92                          b.append('\b');
93                          break;
94                      case 't':
95                          b.append('\t');
96                          break;
97                      case 'n':
98                          b.append('\n');
99                          break;
100                     case 'f':
101                         b.append('\f');
102                         break;
103                     case 'r':
104                         b.append('\r');
105                         break;
106                     case '"':
107                         b.append('"');
108                         break;
109                     case '\'':
110                         b.append('\'');
111                         break;
112                     case '\\':
113                         b.append('\\');
114                         break;
115                 }
116             } else {
117                 b.append(c);
118             }
119         }
120         return b.toString();
121     }
122 }
123 
124 /**
125  * Representation of an element with a JSON document.
126  */
127 class JSONElement {
128     // List of attribute names.
129     private ArrayList<String> attrNames;
130 
131     // List of attribute values.
132     private ArrayList<String> attrValues;
133 
134     // List of children names.
135     private ArrayList<String> childrenNames;
136 
137     // List of children.
138     private ArrayList<JSONElement> children;
139 
140     // Indentation level.
141     private int indentation;
142 
143     /**
144      * Constructs an empty JSON element.
145      */
146     public JSONElement() {
147         this.attrNames = new ArrayList<String>();
148         this.attrValues = new ArrayList<String>();
149         this.childrenNames = new ArrayList<String>();
150         this.children = new ArrayList<JSONElement>();
151         indentation = 0;
152     }
153 
154     /**
155      * Adds an attribute to this JSON element with the given name and value.
156      *
157      * @param name  name of the attribute.
158      * @param value value of the attribute.
159      */
160     public void addAttribute(String name, String value) {
161         attrNames.add(name);
162         attrValues.add(value);
163     }
164 
165     /**
166      * Adds an attribute to this JSON element with the given name and value as a list of strings.
167      *
168      * @param name  name of the attribute.
169      * @param value value of the attribute as a list of strings.
170      */
171     public void addAttribute(String name, ArrayList<String> value) {
172         attrNames.add(name);
173         attrValues.add(value.toString());
174     }
175 
176     /**
177      * Adds a child to this JSON element with the given name.
178      *
179      * @param name  name of the child.
180      * @param child the child.
181      */
182     public void addChild(String name, JSONElement child) {
183         child.indentation = indentation + 4;
184         childrenNames.add(name);
185         children.add(child);
186     }
187 
188     /**
189      * Returns a string representation of this JSON element.
190      *
191      * @return a string representation of this JSON element.
192      */
193     public String toString() {
194         StringBuilder sb = new StringBuilder();
195         if (indentation > 0) {
196             sb.append(String.format("%" + indentation + "s", " "));
197         }
198         sb.append("{\n");
199         for (int i = 0; i < attrNames.size(); i++) {
200             String name = attrNames.get(i);
201             String value = attrValues.get(i);
202             sb.append(String.format("%" + (indentation + 4) + "s", " "));
203             if (value.startsWith("[") && value.endsWith("]")) {
204                 sb.append(String.format("\"%s\": %s", name, value));
205             } else {
206                 sb.append(String.format("\"%s\": \"%s\"", name, value));
207             }
208             if (i < attrNames.size() - 1 || childrenNames.size() > 0) {
209                 sb.append(",\n");
210             } else {
211                 sb.append("\n");
212             }
213         }
214         for (int i = 0; i < childrenNames.size(); i++) {
215             String name = childrenNames.get(i);
216             JSONElement child = children.get(i);
217             sb.append(String.format("%" + (indentation + 4) + "s", " "));
218             sb.append(String.format("\"%s\":\n", name));
219             sb.append(child.toString());
220             if (i < childrenNames.size() - 1) {
221                 sb.append(",\n");
222             } else {
223                 sb.append("\n");
224             }
225         }
226         if (indentation > 0) {
227             sb.append(String.format("%" + indentation + "s", " "));
228         }
229         sb.append("}");
230         return sb.toString();
231     }
232 }
233