| JAST.java |
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