d8f6dd42491bfaaa62b17b9e3c06efd8840a4e6e
[cdsspec-compiler.git] / src / edu / uci / eecs / specExtraction / GlobalConstruct.java
1 package edu.uci.eecs.specExtraction;
2
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.regex.Matcher;
6 import java.util.regex.Pattern;
7
8 import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
9 import edu.uci.eecs.specExtraction.SpecUtils.Primitive;
10
11 /**
12  * <p>
13  * This class is a subclass of Construct. It represents a complete global state
14  * annotation.
15  * </p>
16  * 
17  * @author Peizhao Ou
18  * 
19  */
20 public class GlobalConstruct extends Construct {
21         public final ArrayList<VariableDeclaration> declState;
22         public final Code initState;
23         public final Code copyState;
24         public final Code clearState;
25         public final Code finalState;
26         public final Code printState;
27         public final ArrayList<CommutativityRule> commutativityRules;
28
29         // Whether the state declaration is empty
30         public final boolean emptyState;
31         // Whether we have auto-gen the state initialization code
32         public final boolean autoGenInitial;
33         // Whether we have auto-gen the state copying code
34         public final boolean autoGenCopy;
35         // Whether we have auto-gen the state clearing code
36         public final boolean autoGenClear;
37         // Whether we have auto-gen the state printing code
38         public final boolean autoGenPrint;
39
40         public GlobalConstruct(File file, int beginLineNum,
41                         ArrayList<String> annotations) throws WrongAnnotationException {
42                 super(file, beginLineNum);
43                 declState = new ArrayList<VariableDeclaration>();
44                 initState = new Code();
45                 copyState = new Code();
46                 clearState = new Code();
47                 finalState = new Code();
48                 printState = new Code();
49                 commutativityRules = new ArrayList<CommutativityRule>();
50
51                 processAnnotations(annotations);
52
53                 emptyState = declState.isEmpty();
54                 if (emptyState) {
55                         WrongAnnotationException.warning(file, beginLineNum,
56                                         "The state is empty. Make sure that's what you want!");
57                 }
58
59                 autoGenInitial = initState.isEmpty();
60                 if (autoGenInitial) {
61                         Code code = generateAutoInitalFunction();
62                         initState.addLines(code);
63                 }
64
65                 autoGenCopy = copyState.isEmpty();
66                 if (autoGenCopy) {
67                         Code code = generateAutoCopyFunction();
68                         copyState.addLines(code);
69                 }
70
71                 autoGenClear = clearState.isEmpty();
72                 if (autoGenClear) {
73                         Code code = generateAutoClearFunction();
74                         clearState.addLines(code);
75                 }
76
77                 autoGenPrint = printState.isEmpty();
78                 if (autoGenPrint) {
79                         Code code = generateAutoPrintFunction();
80                         printState.addLines(code);
81                 }
82         }
83
84         /**
85          * <p>
86          * This function will automatically generate the initial statements for
87          * supported types if the user has not defined the "@Initial" primitive
88          * </p>
89          * 
90          * @return The auto-generated state intialization statements
91          * @throws WrongAnnotationException
92          */
93         private Code generateAutoInitalFunction() throws WrongAnnotationException {
94                 Code code = new Code();
95                 if (emptyState) // Empty state should have empty initial function
96                         return code;
97                 for (VariableDeclaration decl : declState) {
98                         String type = decl.type;
99                         String name = decl.name;
100                         // Primitive types
101                         if (type.equals("int") || type.equals("unsigned")
102                                         || type.equals("unsigned int")
103                                         || type.equals("int unsigned") || type.equals("double")
104                                         || type.equals("double") || type.equals("bool")) {
105                                 // x = 0;
106                                 code.addLine(name + " = 0;");
107                         } else if (type.equals("IntList") || type.equals("IntSet")
108                                         || type.equals("IntMap")) {
109                                 // Supported types
110                                 // q = IntList();
111                                 code.addLine(name + " = " + type + "();");
112                         } else if (type.equals("IntList *") || type.equals("IntSet *")
113                                         || type.equals("IntMap *")) {
114                                 // Supported pointer types
115                                 // q = new IntList;
116                                 String originalType = SpecUtils.trimSpace(type
117                                                 .replace('*', ' '));
118                                 code.addLine(name + " = new " + originalType + "();");
119                         } else {
120                                 WrongAnnotationException
121                                                 .err(file,
122                                                                 beginLineNum,
123                                                                 "You have types in the state declaration that we do not support auto-gen initial function.");
124                         }
125                 }
126
127                 return code;
128         }
129
130         /**
131          * <p>
132          * This function will automatically generate the copy statements for
133          * supported types if the user has not defined the "@Copy" primitive
134          * </p>
135          * 
136          * @return The auto-generated state copy statements
137          * @throws WrongAnnotationException
138          */
139         private Code generateAutoCopyFunction() throws WrongAnnotationException {
140                 Code code = new Code();
141                 if (emptyState) // Empty state should have empty copy function
142                         return code;
143                 for (VariableDeclaration decl : declState) {
144                         String type = decl.type;
145                         String name = decl.name;
146                         // Primitive types
147                         if (type.equals("int") || type.equals("unsigned")
148                                         || type.equals("unsigned int")
149                                         || type.equals("int unsigned") || type.equals("double")
150                                         || type.equals("double") || type.equals("bool")) {
151                                 // NEW->x = OLD->x;
152                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
153                                                 + SpecNaming.OldStateInst + "->" + name + ";");
154                         } else if (type.equals("IntList") || type.equals("IntSet")
155                                         || type.equals("IntMap")) {
156                                 // Supported types
157                                 // New->q = IntList(OLD->q);
158                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
159                                                 + type + "(" + SpecNaming.OldStateInst + "->" + name
160                                                 + ");");
161                         } else if (type.equals("IntList *") || type.equals("IntSet *")
162                                         || type.equals("IntMap *")) {
163                                 // Supported pointer types
164                                 // New->q = new IntList(*OLD->q);
165                                 String originalType = SpecUtils.trimSpace(type
166                                                 .replace('*', ' '));
167                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = new "
168                                                 + originalType + "(*" + SpecNaming.OldStateInst + "->"
169                                                 + name + ");");
170                         } else {
171                                 WrongAnnotationException
172                                                 .err(file,
173                                                                 beginLineNum,
174                                                                 "You have types in the state declaration that we do not support auto-gen copy function.");
175                         }
176                 }
177
178                 return code;
179         }
180         
181         /**
182          * <p>
183          * This function will automatically generate the clear statements for
184          * supported types if the user has not defined the "@Clear" primitive
185          * </p>
186          * 
187          * @return The auto-generated state copy statements
188          * @throws WrongAnnotationException
189          */
190         private Code generateAutoClearFunction() throws WrongAnnotationException {
191                 Code code = new Code();
192                 if (emptyState) // Empty state should have empty copy function
193                         return code;
194                 
195                 // FIXME: Just try our best to generate recycling statements
196                 for (VariableDeclaration decl : declState) {
197                         String type = decl.type;
198                         String name = decl.name;
199                         if (type.equals("IntList *") || type.equals("IntSet *")
200                                         || type.equals("IntMap *")) {
201                                 // Supported pointer types
202                                 // if (stack) delete stack;
203                                 code.addLine("if (" + name + ") delete " + name + ";");
204                         }
205                 }
206
207                 return code;
208         }
209
210         /**
211          * <p>
212          * This function will automatically generate the printing statements for
213          * supported types if the user has not defined the "@Print" primitive
214          * </p>
215          * 
216          * @return The auto-generated state printing statements
217          * @throws WrongAnnotationException
218          */
219         private Code generateAutoPrintFunction() throws WrongAnnotationException {
220                 Code code = new Code();
221                 if (emptyState) // Empty state should have empty printing function
222                         return code;
223                 for (VariableDeclaration decl : declState) {
224                         String type = decl.type;
225                         String name = decl.name;
226                         code.addLines(SpecUtils.generatePrintStatement(type, name));
227                 }
228
229                 return code;
230         }
231
232         /**
233          * <p>
234          * Assert that the global state primitive is valid; if not, throws an
235          * exception.
236          * </p>
237          * 
238          * @param file
239          *            Current file
240          * @param primitive
241          *            The primitive that we have extracted earlier
242          * @throws WrongAnnotationException
243          */
244         private void assertValidPrimitive(File file, Primitive primitive)
245                         throws WrongAnnotationException {
246                 int lineNum = primitive.beginLineNum;
247                 String name = primitive.name;
248                 if (!name.equals(SpecNaming.DeclareState)
249                                 && !name.equals(SpecNaming.InitalState)
250                                 && !name.equals(SpecNaming.CopyState)
251                                 && !name.equals(SpecNaming.ClearState)
252                                 && !name.equals(SpecNaming.FinalState)
253                                 && !name.equals(SpecNaming.Commutativity)
254                                 && !name.equals(SpecNaming.PrintState)) {
255                         WrongAnnotationException.err(file, lineNum, name
256                                         + " is NOT a valid CDSSpec global state primitive.");
257                 }
258         }
259
260         /**
261          * <p>
262          * Given a "@DeclareState" primitive that has a list of strings of
263          * declarations, we initialize our local "declState" members.
264          * 
265          * @param primitive
266          * @throws WrongAnnotationException
267          */
268         private void processDeclState(Primitive primitive)
269                         throws WrongAnnotationException {
270                 for (int i = 0; i < primitive.contents.size(); i++) {
271                         int lineNum = i + primitive.beginLineNum;
272                         String declLine = primitive.contents.get(i);
273                         VariableDeclaration tmp = new VariableDeclaration(file, lineNum,
274                                         declLine);
275                         declState.add(tmp);
276                 }
277         }
278
279         /**
280          * <p>
281          * Given a "@DeclareState" primitive that has a list of strings of
282          * declarations, we initialize our local "declState" members.
283          * 
284          * @param primitive
285          * @throws WrongAnnotationException
286          */
287         private void processCommutativity(Primitive primitive)
288                         throws WrongAnnotationException {
289                 // Mathch commutativity rule
290                 Pattern regexpCommute = Pattern
291                                 .compile("\\s*(\\w+)\\s*<->\\s*(\\w+)\\s*\\((.*)\\)\\s*$");
292                 Matcher matcherCommute = regexpCommute.matcher("");
293
294                 for (int i = 0; i < primitive.contents.size(); i++) {
295                         // FIXME: Currently we only allow a one-line commutativity rule
296                         int curLineNum = primitive.beginLineNum + i;
297                         String line = primitive.contents.get(i);
298                         matcherCommute.reset(line);
299                         if (matcherCommute.find()) {
300                                 String method1 = matcherCommute.group(1);
301                                 String method2 = matcherCommute.group(2);
302                                 String code = matcherCommute.group(3);
303                                 String rule = SpecUtils.trimSpace(SpecUtils
304                                                 .trimTrailingCommentSymbol(code));
305                                 commutativityRules.add(new CommutativityRule(method1, method2,
306                                                 rule));
307                         } else {
308                                 WrongAnnotationException
309                                                 .err(file,
310                                                                 curLineNum,
311                                                                 "The @Commutativity annotation should be: @Commutativity: Method1 <-> Method2 (condition)\n\t"
312                                                                                 + "Problematic line: \"" + line + "\"");
313                         }
314                         // Done with processing the current commutativity
315                 }
316         }
317
318         private void processAnnotations(ArrayList<String> annotations)
319                         throws WrongAnnotationException {
320                 IntObj curIdx = new IntObj(0);
321                 Primitive primitive = null;
322
323                 while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
324                                 annotations, curIdx)) != null) {
325                         String name = primitive.name;
326                         assertValidPrimitive(file, primitive);
327                         if (primitive.contents.size() == 0)
328                                 continue;
329                         if (name.equals(SpecNaming.DeclareState)) {
330                                 processDeclState(primitive);
331                         } else if (name.equals(SpecNaming.InitalState)) {
332                                 initState.addLines(primitive.contents);
333                         } else if (name.equals(SpecNaming.CopyState)) {
334                                 copyState.addLines(primitive.contents);
335                         } else if (name.equals(SpecNaming.ClearState)) {
336                                 clearState.addLines(primitive.contents);
337                         } else if (name.equals(SpecNaming.FinalState)) {
338                                 finalState.addLines(primitive.contents);
339                         } else if (name.equals(SpecNaming.PrintState)) {
340                                 printState.addLines(primitive.contents);
341                         } else if (name.equals(SpecNaming.Commutativity)) {
342                                 processCommutativity(primitive);
343                         }
344                 }
345         }
346
347         public String toString() {
348                 StringBuilder sb = new StringBuilder("");
349                 sb.append(super.toString() + "\n");
350                 sb.append("@DeclareState:\n");
351                 sb.append(declState);
352                 sb.append("\n");
353                 sb.append("@InitState:\n");
354                 sb.append(initState);
355                 if (!printState.isEmpty()) {
356                         sb.append("@Print:\n");
357                         sb.append(printState);
358                 }
359
360                 for (int i = 0; i < commutativityRules.size(); i++) {
361                         sb.append("@Commutativity: " + commutativityRules + "\n");
362                 }
363                 return sb.toString();
364         }
365 }