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