1ff0cb05514cc3c8e7c01d56587cee307c6bcd03
[cdsspec-compiler.git] / src / edu / uci / eecs / specExtraction / InterfaceConstruct.java
1 package edu.uci.eecs.specExtraction;
2
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8
9 import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
10 import edu.uci.eecs.specExtraction.SpecUtils.Primitive;
11 import edu.uci.eecs.utilParser.ParseException;
12 import edu.uci.eecs.utilParser.UtilParser;
13
14 /**
15  * <p>
16  * This class is a subclass of Construct. It represents a complete interface
17  * annotation.
18  * </p>
19  * 
20  * @author Peizhao Ou
21  * 
22  */
23 public class InterfaceConstruct extends Construct {
24         // The interface label of the current interface; If not specified, we use
25         // the actual interface name to represent this interface
26         private String name;
27         // Each interface interface will have an auto-generated struct that
28         // represents the return value and the arguments of that interface method
29         // call. We will mangle the interface label name to get this name in case we
30         // have other name conflict
31         private String structName;
32         public final Code preCondition;
33         public final Code transition;
34         public final Code postCondition;
35         public final Code print;
36
37         // The ending line number of the specification annotation construct
38         public final int endLineNum;
39
40         // The ending line number of the function definition
41         private int endLineNumFunction;
42         // The function header of the corresponding interface --- The list of
43         // variable declarations that represent the RETURN value and
44         // arguments of the interface
45         private FunctionHeader funcHeader;
46
47         public final boolean autoGenPrint;
48
49         public InterfaceConstruct(File file, int beginLineNum, int endLineNum,
50                         ArrayList<String> annotations) throws WrongAnnotationException {
51                 super(file, beginLineNum);
52                 this.endLineNum = endLineNum;
53                 this.name = null;
54                 this.structName = null;
55                 this.preCondition = new Code();
56                 this.transition = new Code();
57                 this.postCondition = new Code();
58                 this.print = new Code();
59
60                 processAnnotations(annotations);
61
62                 autoGenPrint = print.isEmpty();
63         }
64
65         public FunctionHeader getFunctionHeader() {
66                 return this.funcHeader;
67         }
68
69         public boolean equals(Object other) {
70                 if (!(other instanceof InterfaceConstruct)) {
71                         return false;
72                 }
73                 InterfaceConstruct o = (InterfaceConstruct) other;
74                 if (o.name.equals(this.name))
75                         return true;
76                 else
77                         return false;
78         }
79
80         public String getName() {
81                 return this.name;
82         }
83
84         /**
85          * <p>
86          * This function will automatically generate the printing statements for
87          * supported types if the user has not defined the "@Print" primitive
88          * </p>
89          * 
90          * @return The auto-generated state printing statements
91          * @throws WrongAnnotationException
92          */
93         private Code generateAutoPrintFunction() {
94                 Code code = new Code();
95                 // For RET
96                 code.addLines(SpecUtils.generatePrintStatement(funcHeader.returnType,
97                                 SpecNaming.RET));
98                 // For arguments
99                 for (VariableDeclaration decl : funcHeader.args) {
100                         String type = decl.type;
101                         String name = decl.name;
102                         code.addLines(SpecUtils.generatePrintStatement(type, name));
103                 }
104                 return code;
105         }
106
107         /**
108          * <p>
109          * Assert that the interface primitive is valid; if not, throws an exception
110          * </p>
111          * 
112          * @param file
113          *            Current file
114          * @param primitive
115          *            The primitive string that we have extracted earlier
116          * @throws WrongAnnotationException
117          */
118         private void assertValidPrimitive(File file, Primitive primitive)
119                         throws WrongAnnotationException {
120                 int lineNum = primitive.beginLineNum;
121                 String name = primitive.name;
122                 if (!name.equals(SpecNaming.Interface)
123                                 && !name.equals(SpecNaming.Transition)
124                                 && !name.equals(SpecNaming.PreCondition)
125                                 && !name.equals(SpecNaming.SideEffect)
126                                 && !name.equals(SpecNaming.PostCondition)
127                                 && !name.equals(SpecNaming.PrintValue)) {
128                         WrongAnnotationException.err(file, lineNum, name
129                                         + " is NOT a valid CDSSpec interface primitive.");
130                 }
131         }
132
133         /**
134          * <p>
135          * Assert that the "@Interface" primitive has correct syntax; if not, throws
136          * an exception. If so, it basically checks whether content of the primitive
137          * is a valid word and then return interface label name.
138          * </p>
139          * 
140          * @param file
141          *            Current file
142          * @param lineNum
143          *            Current line number
144          * @param primitive
145          *            The primitive string that we have extracted earlier
146          * @throws WrongAnnotationException
147          */
148         private String extractInterfaceName(File file, Primitive primitive)
149                         throws WrongAnnotationException {
150                 int lineNum = primitive.beginLineNum;
151                 String name = primitive.name;
152                 if (primitive.contents.size() != 1)
153                         WrongAnnotationException.err(file, lineNum,
154                                         "The @Interface primitive: " + name + " has wrong syntax.");
155                 String line = primitive.contents.get(0);
156                 SpecUtils.matcherWord.reset(line);
157                 if (!SpecUtils.matcherWord.find())
158                         WrongAnnotationException.err(file, lineNum, name
159                                         + " is NOT a valid CDSSpec @Interface primitive.");
160                 return line;
161         }
162
163         private void processAnnotations(ArrayList<String> annotations)
164                         throws WrongAnnotationException {
165                 IntObj curIdx = new IntObj(0);
166                 Primitive primitive = null;
167
168                 while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
169                                 annotations, curIdx)) != null) {
170                         String name = primitive.name;
171                         assertValidPrimitive(file, primitive);
172                         if (primitive.contents.size() == 0)
173                                 continue;
174                         if (name.equals(SpecNaming.Interface)) {
175                                 String interName = extractInterfaceName(file, primitive); 
176                                 setNames(interName);
177                         } else if (name.equals(SpecNaming.Transition)) {
178                                 this.transition.addLines(primitive.contents);
179                         } else if (name.equals(SpecNaming.PreCondition)) {
180                                 this.preCondition.addLines(primitive.contents);
181                         } else if (name.equals(SpecNaming.PostCondition)) {
182                                 this.postCondition.addLines(primitive.contents);
183                         } else if (name.equals(SpecNaming.PrintValue)) {
184                                 this.print.addLines(primitive.contents);
185                         }
186                 }
187         }
188
189         /**
190          * <p>
191          * This function is called to extract all the declarations that should go to
192          * the corresponding value struct --- a C++ struct to be generated for this
193          * interface that contains the information of the return value and the
194          * arguments.
195          * </p>
196          * 
197          * @param line
198          *            The line that represents the interface declaration line
199          * @throws ParseException
200          */
201         public void processFunctionDeclaration(String line) throws ParseException {
202                 // FIXME: Currently we only allow the declaration to be one-liner
203                 funcHeader = UtilParser.parseFuncHeader(line);
204                 // Record the original declaration line
205                 funcHeader.setHeaderLine(line);
206
207                 // If users have not defined @Interface, we should use the function name
208                 // as the interface label
209                 if (name == null) {
210                         setNames(funcHeader.funcName.bareName);
211                 }
212
213                 // Once we have the compelte function declaration, we can auto-gen the
214                 // print-out statements if it's not defined
215                 if (autoGenPrint) {
216                         print.addLines(generateAutoPrintFunction());
217                 }
218         }
219
220         public String toString() {
221                 StringBuilder sb = new StringBuilder();
222                 sb.append(super.toString() + "\n");
223                 sb.append("@Interface: " + name + "\n");
224                 if (!transition.isEmpty())
225                         sb.append("@Transition:\n" + transition);
226                 if (!preCondition.isEmpty())
227                         sb.append("@PreCondition:\n" + preCondition);
228                 if (!postCondition.isEmpty())
229                         sb.append("@PostCondition:\n" + postCondition);
230                 if (!print.isEmpty())
231                         sb.append("@Print:\n" + print + "\n");
232                 sb.append(funcHeader);
233
234                 return sb.toString();
235         }
236
237         public int getEndLineNumFunction() {
238                 return endLineNumFunction;
239         }
240
241         public void setEndLineNumFunction(int endLineNumFunction) {
242                 this.endLineNumFunction = endLineNumFunction;
243         }
244
245         public String getStructName() {
246                 return structName;
247         }
248
249         private void setNames(String name) {
250                 this.name = name;
251                 if (name == null)
252                         return;
253                 structName = createStructName(name);
254         }
255         
256         static public String createStructName(String labelName) {
257                 return "__struct_" + labelName + "__";
258         }
259 }