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