edits
[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         public final boolean autoGenCopy;
29
30         public GlobalConstruct(File file, int beginLineNum,
31                         ArrayList<String> annotations) throws WrongAnnotationException {
32                 super(file, beginLineNum);
33                 declState = new ArrayList<VariableDeclaration>();
34                 initState = new Code();
35                 copyState = new Code();
36                 finalState = new Code();
37                 printState = new Code();
38                 commutativityRules = new ArrayList<CommutativityRule>();
39
40                 processAnnotations(annotations);
41
42                 if (copyState.isEmpty()) {
43                         Code code = generateAutoCopyFunction();
44                         copyState.addLines(code);
45                         autoGenCopy = true;
46                 } else {
47                         autoGenCopy = false;
48                 }
49         }
50
51         /**
52          * <p>
53          * This function will automatically generate the copy statements for
54          * supported types if the user has not defined the "@Copy" primitive
55          * </p>
56          * 
57          * @return The auto-generated copy statements
58          * @throws WrongAnnotationException
59          */
60         private Code generateAutoCopyFunction() throws WrongAnnotationException {
61                 Code code = new Code();
62                 for (VariableDeclaration decl : declState) {
63                         String type = decl.type;
64                         String name = decl.name;
65                         // Primitive types
66                         if (type.equals("int") || type.equals("unsigned")
67                                         || type.equals("unsigned int")
68                                         || type.equals("int unsigned") || type.equals("double")
69                                         || type.equals("double") || type.equals("bool")) {
70                                 // NEW->x = OLD->x;
71                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
72                                                 + SpecNaming.OldStateInst + "->" + name + ";");
73                         } else if (type.equals("IntList") || type.equals("IntSet")
74                                         || type.equals("IntMap")) {
75                                 // Supported types
76                                 // New->q = IntList(OLD->q);
77                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
78                                                 + type + "(" + SpecNaming.OldStateInst + "->" + name
79                                                 + ");");
80                         } else if (type.equals("IntList *") || type.equals("IntSet *")
81                                         || type.equals("IntMap *")) {
82                                 // Supported pointer types
83                                 // New->q = new IntList(*OLD->q);
84                                 String originalType = SpecUtils.trimSpace(type
85                                                 .replace('*', ' '));
86                                 code.addLine(SpecNaming.NewStateInst + "->" + name + " = new "
87                                                 + originalType + "(*" + SpecNaming.OldStateInst + "->"
88                                                 + name + ");");
89                         } else {
90                                 WrongAnnotationException
91                                                 .err(file,
92                                                                 beginLineNum,
93                                                                 "You have types in the state declaration that we do not support auto-gen copy function.");
94                         }
95                 }
96
97                 return code;
98         }
99
100         /**
101          * <p>
102          * Assert that the global state primitive is valid; if not, throws an
103          * exception.
104          * </p>
105          * 
106          * @param file
107          *            Current file
108          * @param primitive
109          *            The primitive that we have extracted earlier
110          * @throws WrongAnnotationException
111          */
112         private void assertValidPrimitive(File file, Primitive primitive)
113                         throws WrongAnnotationException {
114                 int lineNum = primitive.beginLineNum;
115                 String name = primitive.name;
116                 if (!name.equals(SpecNaming.DeclareState)
117                                 && !name.equals(SpecNaming.InitalState)
118                                 && !name.equals(SpecNaming.CopyState)
119                                 && !name.equals(SpecNaming.FinalState)
120                                 && !name.equals(SpecNaming.Commutativity)
121                                 && !name.equals(SpecNaming.PrintState)) {
122                         WrongAnnotationException.err(file, lineNum, name
123                                         + " is NOT a valid CDSSpec global state primitive.");
124                 }
125         }
126
127         /**
128          * <p>
129          * Given a "@DeclareState" primitive that has a list of strings of
130          * declarations, we initialize our local "declState" members.
131          * 
132          * @param primitive
133          * @throws WrongAnnotationException
134          */
135         private void processDeclState(Primitive primitive)
136                         throws WrongAnnotationException {
137                 for (int i = 0; i < primitive.contents.size(); i++) {
138                         int lineNum = i + primitive.beginLineNum;
139                         String declLine = primitive.contents.get(i);
140                         VariableDeclaration tmp = new VariableDeclaration(file, lineNum,
141                                         declLine);
142                         declState.add(tmp);
143                 }
144         }
145
146         /**
147          * <p>
148          * Given a "@DeclareState" primitive that has a list of strings of
149          * declarations, we initialize our local "declState" members.
150          * 
151          * @param primitive
152          * @throws WrongAnnotationException
153          */
154         private void processCommutativity(Primitive primitive)
155                         throws WrongAnnotationException {
156                 // Mathch commutativity rule
157                 Pattern regexpCommute = Pattern
158                                 .compile("\\s*(\\w+)\\s*<->\\s*(\\w+)\\s*\\((.*)\\)\\s*$");
159                 Matcher matcherCommute = regexpCommute.matcher("");
160
161                 for (int i = 0; i < primitive.contents.size(); i++) {
162                         // FIXME: Currently we only allow a one-line commutativity rule
163                         int curLineNum = primitive.beginLineNum + i;
164                         String line = primitive.contents.get(i);
165                         matcherCommute.reset(line);
166                         if (matcherCommute.find()) {
167                                 String method1 = matcherCommute.group(1);
168                                 String method2 = matcherCommute.group(2);
169                                 String code = matcherCommute.group(3);
170                                 String rule = SpecUtils.trimSpace(SpecUtils
171                                                 .trimTrailingCommentSymbol(code));
172                                 commutativityRules.add(new CommutativityRule(method1, method2,
173                                                 rule));
174                         } else {
175                                 WrongAnnotationException
176                                                 .err(file,
177                                                                 curLineNum,
178                                                                 "The @Commutativity annotation should be: @Commutativity: Method1 <-> Method2 (condition)\n\t"
179                                                                                 + "Problematic line: \"" + line + "\"");
180                         }
181                         // Done with processing the current commutativity
182                 }
183         }
184
185         private void processAnnotations(ArrayList<String> annotations)
186                         throws WrongAnnotationException {
187                 IntObj curIdx = new IntObj(0);
188                 Primitive primitive = null;
189
190                 while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
191                                 annotations, curIdx)) != null) {
192                         String name = primitive.name;
193                         assertValidPrimitive(file, primitive);
194                         if (primitive.contents.size() == 0)
195                                 continue;
196                         if (name.equals(SpecNaming.DeclareState)) {
197                                 processDeclState(primitive);
198                         } else if (name.equals(SpecNaming.InitalState)) {
199                                 initState.addLines(primitive.contents);
200                         } else if (name.equals(SpecNaming.CopyState)) {
201                                 copyState.addLines(primitive.contents);
202                         } else if (name.equals(SpecNaming.FinalState)) {
203                                 finalState.addLines(primitive.contents);
204                         } else if (name.equals(SpecNaming.PrintState)) {
205                                 printState.addLines(primitive.contents);
206                         } else if (name.equals(SpecNaming.Commutativity)) {
207                                 processCommutativity(primitive);
208                         }
209                 }
210         }
211
212         public String toString() {
213                 StringBuilder sb = new StringBuilder("");
214                 sb.append(super.toString() + "\n");
215                 sb.append("@DeclareState:\n");
216                 sb.append(declState);
217                 sb.append("\n");
218                 sb.append("@InitState:\n");
219                 sb.append(initState);
220                 if (!printState.isEmpty()) {
221                         sb.append("@Print:\n");
222                         sb.append(printState);
223                 }
224
225                 for (int i = 0; i < commutativityRules.size(); i++) {
226                         sb.append("@Commutativity: " + commutativityRules + "\n");
227                 }
228                 return sb.toString();
229         }
230 }