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