232acaf2b34bc5529db9d64bb10af8547059f1ca
[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         private String name;
25         public final Code transition;
26         public final Code preCondition;
27         public final Code postCondition;
28         public final Code print;
29
30         // The ending line number of the specification annotation construct
31         public final int endLineNum;
32
33         // The ending line number of the function definition
34         private int endLineNumFunction;
35         // The function header of the corresponding interface --- The list of
36         // variable declarations that represent the RETURN value and
37         // arguments of the interface
38         private FunctionHeader funcHeader;
39
40         public final boolean autoGenPrint;
41
42         public InterfaceConstruct(File file, int beginLineNum, int endLineNum,
43                         ArrayList<String> annotations) throws WrongAnnotationException {
44                 super(file, beginLineNum);
45                 this.endLineNum = endLineNum;
46                 this.name = null;
47                 this.transition = new Code();
48                 this.preCondition = new Code();
49                 this.postCondition = new Code();
50                 this.print = new Code();
51
52                 processAnnotations(annotations);
53
54                 autoGenPrint = print.isEmpty();
55         }
56
57         public FunctionHeader getFunctionHeader() {
58                 return this.funcHeader;
59         }
60
61         public boolean equals(Object other) {
62                 if (!(other instanceof InterfaceConstruct)) {
63                         return false;
64                 }
65                 InterfaceConstruct o = (InterfaceConstruct) other;
66                 if (o.name.equals(this.name))
67                         return true;
68                 else
69                         return false;
70         }
71
72         public String getName() {
73                 return this.name;
74         }
75
76         /**
77          * <p>
78          * This function will automatically generate the printing statements for
79          * supported types if the user has not defined the "@Print" primitive
80          * </p>
81          * 
82          * @return The auto-generated state printing statements
83          * @throws WrongAnnotationException
84          */
85         private Code generateAutoPrintFunction() {
86                 Code code = new Code();
87                 // For RET
88                 code.addLines(SpecUtils.generatePrintStatement(funcHeader.returnType,
89                                 SpecNaming.RET));
90                 // For arguments
91                 for (VariableDeclaration decl : funcHeader.args) {
92                         String type = decl.type;
93                         String name = decl.name;
94                         code.addLines(SpecUtils.generatePrintStatement(type, name));
95                 }
96                 return code;
97         }
98
99         /**
100          * <p>
101          * Assert that the interface primitive is valid; if not, throws an exception
102          * </p>
103          * 
104          * @param file
105          *            Current file
106          * @param primitive
107          *            The primitive string that we have extracted earlier
108          * @throws WrongAnnotationException
109          */
110         private void assertValidPrimitive(File file, Primitive primitive)
111                         throws WrongAnnotationException {
112                 int lineNum = primitive.beginLineNum;
113                 String name = primitive.name;
114                 if (!name.equals(SpecNaming.Interface)
115                                 && !name.equals(SpecNaming.Transition)
116                                 && !name.equals(SpecNaming.PreCondition)
117                                 && !name.equals(SpecNaming.SideEffect)
118                                 && !name.equals(SpecNaming.PostCondition)
119                                 && !name.equals(SpecNaming.PrintValue)) {
120                         WrongAnnotationException.err(file, lineNum, name
121                                         + " is NOT a valid CDSSpec interface primitive.");
122                 }
123         }
124
125         /**
126          * <p>
127          * Assert that the "@Interface" primitive has correct syntax; if not, throws
128          * an exception. If so, it basically checks whether content of the primitive
129          * is a valid word and then return interface label name.
130          * </p>
131          * 
132          * @param file
133          *            Current file
134          * @param lineNum
135          *            Current line number
136          * @param primitive
137          *            The primitive string that we have extracted earlier
138          * @throws WrongAnnotationException
139          */
140         private String extractInterfaceName(File file, Primitive primitive)
141                         throws WrongAnnotationException {
142                 int lineNum = primitive.beginLineNum;
143                 String name = primitive.name;
144                 if (primitive.contents.size() != 1)
145                         WrongAnnotationException.err(file, lineNum,
146                                         "The @Interface primitive: " + name + " has wrong syntax.");
147                 String line = primitive.contents.get(0);
148                 SpecUtils.matcherWord.reset(line);
149                 if (!SpecUtils.matcherWord.find())
150                         WrongAnnotationException.err(file, lineNum, name
151                                         + " is NOT a valid CDSSpec @Interface primitive.");
152                 return line;
153         }
154
155         private void processAnnotations(ArrayList<String> annotations)
156                         throws WrongAnnotationException {
157                 IntObj curIdx = new IntObj(0);
158                 Primitive primitive = null;
159
160                 while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
161                                 annotations, curIdx)) != null) {
162                         String name = primitive.name;
163                         assertValidPrimitive(file, primitive);
164                         if (primitive.contents.size() == 0)
165                                 continue;
166                         if (name.equals(SpecNaming.Interface)) {
167                                 this.name = extractInterfaceName(file, primitive);
168                         } else if (name.equals(SpecNaming.Transition)) {
169                                 this.transition.addLines(primitive.contents);
170                         } else if (name.equals(SpecNaming.PreCondition)) {
171                                 this.preCondition.addLines(primitive.contents);
172                         } else if (name.equals(SpecNaming.PostCondition)) {
173                                 this.postCondition.addLines(primitive.contents);
174                         } else if (name.equals(SpecNaming.PrintValue)) {
175                                 this.print.addLines(primitive.contents);
176                         }
177                 }
178         }
179
180         /**
181          * <p>
182          * This function is called to extract all the declarations that should go to
183          * the corresponding value struct --- a C++ struct to be generated for this
184          * interface that contains the information of the return value and the
185          * arguments.
186          * </p>
187          * 
188          * @param line
189          *            The line that represents the interface declaration line
190          * @throws ParseException
191          */
192         public void processFunctionDeclaration(String line) throws ParseException {
193                 // FIXME: Currently we only allow the declaration to be one-liner
194                 funcHeader = UtilParser.parseFuncHeader(line);
195                 // Record the original declaration line
196                 funcHeader.setHeaderLine(line);
197
198                 // Once we have the compelte function declaration, we can auto-gen the
199                 // print-out statements if it's not defined
200                 if (autoGenPrint) {
201                         print.addLines(generateAutoPrintFunction());
202                 }
203         }
204
205         public String toString() {
206                 StringBuilder sb = new StringBuilder();
207                 sb.append(super.toString() + "\n");
208                 sb.append("@Interface: " + name + "\n");
209                 if (!transition.isEmpty())
210                         sb.append("@Transition:\n" + transition);
211                 if (!preCondition.isEmpty())
212                         sb.append("@PreCondition:\n" + preCondition);
213                 if (!postCondition.isEmpty())
214                         sb.append("@PostCondition:\n" + postCondition);
215                 if (!print.isEmpty())
216                         sb.append("@Print:\n" + print + "\n");
217                 sb.append(funcHeader);
218
219                 return sb.toString();
220         }
221
222         public int getEndLineNumFunction() {
223                 return endLineNumFunction;
224         }
225
226         public void setEndLineNumFunction(int endLineNumFunction) {
227                 this.endLineNumFunction = endLineNumFunction;
228         }
229 }