1 package org.ocltf.parser;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.LinkedList;
7 import java.util.List;
8 import java.util.Map;
9
10 import org.ocltf.parser.analysis.AnalysisAdapter;
11 import org.ocltf.parser.analysis.DepthFirstAdapter;
12 import org.ocltf.parser.lexer.Lexer;
13 import org.ocltf.parser.node.AActualParameterList;
14 import org.ocltf.parser.node.ABarFeatureCallParameterOption;
15 import org.ocltf.parser.node.AColonFeatureCallParameterOption;
16 import org.ocltf.parser.node.ACommaExpression;
17 import org.ocltf.parser.node.ACommaFeatureCallParameterOption;
18 import org.ocltf.parser.node.AConcreteFeatureCallParameters;
19 import org.ocltf.parser.node.AEqualExpression;
20 import org.ocltf.parser.node.AFeatureCallParameters;
21 import org.ocltf.parser.node.AIterateDeclarator;
22 import org.ocltf.parser.node.AIterateFeatureCallParameterOption;
23 import org.ocltf.parser.node.APathName;
24 import org.ocltf.parser.node.AStandardDeclarator;
25 import org.ocltf.parser.node.ATypeDeclaration;
26 import org.ocltf.parser.node.AVariableDeclaration;
27 import org.ocltf.parser.node.AVariableDeclarationList;
28 import org.ocltf.parser.node.AVariableDeclarationListTail;
29 import org.ocltf.parser.node.Node;
30 import org.ocltf.parser.node.PExpression;
31 import org.ocltf.parser.node.PFeatureCallParameterOption;
32 import org.ocltf.parser.node.TName;
33 import org.ocltf.parser.parser.Parser;
34
35 /***
36 * This class adapts the Parser class to handle expressions
37 * in which the SableCC parser can't handle.
38 */
39 public class OclParser extends Parser {
40
41 protected AstFix fix = new AstFix();
42 protected Node oclNode;
43
44 /***
45 * Constructs an instance of OclParser.
46 *
47 * @param lexer
48 */
49 public OclParser(Lexer lexer) {
50 super(lexer);
51 }
52
53 /***
54 * @see org.ocltf.parser.parser.Parser#filter()
55 */
56 protected void filter() {
57 oclNode = node;
58 oclNode.apply(fix);
59 node = oclNode;
60 }
61
62 private class AstFix extends AnalysisAdapter {
63
64 /***
65 * @see org.ocltf.parser.analysis.AnalysisAdapter#caseAConcreteFeatureCallParameters(org.ocltf.parser.node.AConcreteFeatureCallParameters)
66 */
67 public void caseAConcreteFeatureCallParameters(AConcreteFeatureCallParameters featureCallParameters) {
68 boolean isDeclarator = false;
69 boolean isIterateDeclarator = false;
70
71 List tail = featureCallParameters.getFeatureCallParameterOption();
72 PFeatureCallParameterOption[] parameterOption =
73 new PFeatureCallParameterOption[tail.size()];
74 Iterator iter = tail.iterator();
75
76 for (int ctr = 0; iter.hasNext(); ctr++) {
77 PFeatureCallParameterOption option = (PFeatureCallParameterOption) iter.next();
78 parameterOption[ctr] = option;
79 isIterateDeclarator = option instanceof AIterateFeatureCallParameterOption;
80 if (!isIterateDeclarator) {
81 isDeclarator = option instanceof ABarFeatureCallParameterOption;
82 }
83 }
84
85 if (isIterateDeclarator && !isDeclarator) {
86 throw new OclParserException(
87 "parser error: illegal feature call parameters format in \""
88 + featureCallParameters
89 + "\"; "
90 + "must contain \";\" only if it contains \"|\"");
91 }
92 AFeatureCallParameters parameters;
93 if (isIterateDeclarator) {
94 parameters =
95 getParametersWithIterateDeclarator(
96 featureCallParameters,
97 featureCallParameters.getExpression(),
98 parameterOption);
99 } else if (isDeclarator) {
100 parameters =
101 getParametersWithStandardDeclarator(
102 featureCallParameters,
103 parameterOption);
104 } else {
105 parameters =
106 getParametersWithoutDeclarator(
107 featureCallParameters,
108 featureCallParameters.getExpression(),
109 parameterOption);
110 }
111 oclNode = parameters;
112 }
113
114 /***
115 * Gets the AFeatureCallParameters with a iterate declarator.
116 *
117 * @param featureCallParameters
118 * @param expression
119 * @param parameterOption
120 * @return AFeatureCallParameters
121 */
122 protected AFeatureCallParameters getParametersWithIterateDeclarator(
123 AConcreteFeatureCallParameters featureCallParameters,
124 PExpression expression,
125 PFeatureCallParameterOption[] parameterOption) {
126 AIterateDeclarator iteratorDeclarator = new AIterateDeclarator();
127
128 AColonFeatureCallParameterOption featureCallParameterOption0 =
129 (AColonFeatureCallParameterOption) parameterOption[0];
130 AIterateFeatureCallParameterOption featureCallParameterOption1 =
131 (AIterateFeatureCallParameterOption) parameterOption[1];
132 ABarFeatureCallParameterOption featureCallParameterOption2 =
133 (ABarFeatureCallParameterOption) parameterOption[2];
134
135 AVariableDeclaration iterator =
136 new AVariableDeclaration(
137 getName(expression),
138 featureCallParameterOption0.getTypeDeclaration());
139 iteratorDeclarator.setIterator(iterator);
140 iteratorDeclarator.setSemicolon(featureCallParameterOption1.getSemicolon());
141
142 AVariableDeclaration accumulator =
143 new AVariableDeclaration(
144 featureCallParameterOption1.getName(),
145 featureCallParameterOption1.getTypeDeclaration());
146 iteratorDeclarator.setAccumulator(accumulator);
147
148 AEqualExpression equalExpression =
149 new AEqualExpression(
150 featureCallParameterOption1.getEqual(),
151 featureCallParameterOption1.getExpression());
152 iteratorDeclarator.setEqualExpression(equalExpression);
153 iteratorDeclarator.setBar(featureCallParameterOption2.getBar());
154 AActualParameterList params =
155 new AActualParameterList(
156 featureCallParameterOption2.getExpression(),
157 new ArrayList());
158 return
159 new AFeatureCallParameters(
160 featureCallParameters.getLParen(),
161 iteratorDeclarator,
162 params,
163 featureCallParameters.getRParen());
164 }
165
166 /***
167 * Gets AFeatureCallParameters from the standard declarator.
168 *
169 * @param featureCallParameters
170 * @param parameterOption
171 * @return AFeatureCallParameters
172 */
173 protected AFeatureCallParameters getParametersWithStandardDeclarator(
174 AConcreteFeatureCallParameters featureCallParameters,
175 PFeatureCallParameterOption[] parameterOptions) {
176
177 int parameterOptionNum = parameterOptions.length;
178
179 boolean valid = true;
180
181
182 if (parameterOptionNum < 1) {
183 valid = false;
184
185
186 } else if (!(parameterOptions[parameterOptionNum - 1] instanceof ABarFeatureCallParameterOption)) {
187 valid = false;
188 }
189
190
191
192
193
194 for (int ctr = 0; ctr < parameterOptionNum - 2; ctr++) {
195 if (!(parameterOptions[ctr] instanceof ACommaFeatureCallParameterOption ||
196 parameterOptions[ctr] instanceof AColonFeatureCallParameterOption)) {
197 throw new OclParserException(
198 "parser error: feature call parameters with standard declarator must have the format "
199 + "\"( name (: type)?, ... , name: type | expression )\"");
200 }
201 }
202
203 if (!valid) {
204
205 }
206
207 ABarFeatureCallParameterOption barParameterType =
208 (ABarFeatureCallParameterOption) parameterOptions[parameterOptionNum - 1];
209
210 AStandardDeclarator standardDeclarator =
211 new AStandardDeclarator(
212 this.getVariableDeclarationList(featureCallParameters),
213 barParameterType.getBar());
214 AActualParameterList params =
215 new AActualParameterList(
216 barParameterType.getExpression(),
217 new ArrayList());
218 return
219 new AFeatureCallParameters(
220 featureCallParameters.getLParen(),
221 standardDeclarator,
222 params,
223 featureCallParameters.getRParen());
224 }
225
226 /***
227 * Gets the AFeatureCallParameter instance without the declarator.
228 *
229 * @param featureCallParameters
230 * @param expr
231 * @param parameterOption
232 * @return AFeatureCallParameters
233 */
234 protected AFeatureCallParameters getParametersWithoutDeclarator(
235 AConcreteFeatureCallParameters featureCallParameters,
236 PExpression expr,
237 PFeatureCallParameterOption[] parameterOption) {
238
239 List paramList = new ArrayList();
240
241 for (int ctr = 0; ctr < parameterOption.length; ctr++) {
242 if (!(parameterOption[ctr] instanceof ACommaFeatureCallParameterOption)) {
243 throw new OclParserException(
244 "parser error: declarator-less feature call paramaters must have the format "
245 + "\"( expr, ..., expr )\"");
246 } else {
247 ACommaFeatureCallParameterOption commaOption =
248 (ACommaFeatureCallParameterOption) parameterOption[ctr];
249 ACommaExpression commaExpression =
250 new ACommaExpression(
251 commaOption.getComma(),
252 commaOption.getExpression());
253 paramList.add(commaExpression);
254 }
255 }
256
257 return
258 new AFeatureCallParameters(
259 featureCallParameters.getLParen(),
260 null,
261 new AActualParameterList(expr, paramList),
262 featureCallParameters.getRParen());
263 }
264
265 /***
266 * Gets the AVariableDeclarationList instance from the <code>params</code>
267 * by apply the VariableDeclarationListFinder to it.
268 * @param params the params node to parse.
269 * @return the found AVariableDeclarationList instance.
270 */
271 protected AVariableDeclarationList getVariableDeclarationList(AConcreteFeatureCallParameters params) {
272 VariableDeclarationListFinder finder = new VariableDeclarationListFinder();
273 params.apply(finder);
274 return finder.getList();
275 }
276
277 }
278
279 /***
280 * A tree traversal class that searchs for a name in a expression.
281 */
282 private class VariableDeclarationListFinder extends DepthFirstAdapter {
283
284 /***
285 * Stores the variable names in an ordered
286 * fashion so that we can retrieve them from the
287 * namesAndTypes map in the order they were stored.
288 */
289 private LinkedList orderedNames = new LinkedList();
290
291 /***
292 * Stores the variable names along with its
293 * variable type (if there is one).
294 */
295 private Map namesAndTypes = new HashMap();
296
297 /***
298 * @see org.ocltf.parser.analysis.Analysis#caseAPathName(org.ocltf.parser.node.APathName)
299 */
300 public void inAPathName(APathName name) {
301
302
303
304 if (this.namesAndTypes.isEmpty()) {
305 TName initialVariableName = name.getName();
306 this.orderedNames.add(initialVariableName);
307 this.namesAndTypes.put(this.orderedNames.getLast(), null);
308 }
309 }
310
311 /***
312 * @see org.ocltf.parser.analysis.Analysis#caseACommaFeatureCallParameterOption(org.ocltf.parser.node.ACommaFeatureCallParameterOption)
313 */
314 public void inACommaFeatureCallParameterOption(ACommaFeatureCallParameterOption commaName) {
315 this.orderedNames.add(commaName);
316 this.namesAndTypes.put(commaName, null);
317 }
318
319 /***
320 * @see org.ocltf.parser.analysis.Analysis#caseATypeDeclaration(org.ocltf.parser.node.ATypeDeclaration)
321 */
322 public void inATypeDeclaration(ATypeDeclaration type) {
323 if (this.namesAndTypes.containsKey(this.orderedNames.getLast())) {
324 this.namesAndTypes.put(this.orderedNames.getLast(), type);
325 }
326 }
327
328 /***
329 * Extracts and constructs AVariableDeclarationlist
330 * from a AConcreteFeatureCallParameters instance.
331 *
332 * @return AVariableDeclarationList
333 */
334 public AVariableDeclarationList getList() {
335
336 TName initialName = (TName)this.orderedNames.getFirst();
337
338 ATypeDeclaration typeDeclaration =
339 (ATypeDeclaration)namesAndTypes.get(initialName);
340
341 List variableDeclarationListTails = new ArrayList();
342 if (!this.orderedNames.isEmpty()) {
343 int orderedNameSize = orderedNames.size();
344 for (int ctr = 1; ctr < orderedNameSize; ctr++) {
345 ACommaFeatureCallParameterOption name =
346 (ACommaFeatureCallParameterOption)this.orderedNames.get(ctr);
347
348 ATypeDeclaration typeDecl =
349 (ATypeDeclaration)this.namesAndTypes.get(name);
350
351 AVariableDeclaration variableDeclaration =
352 new AVariableDeclaration(
353 getName(name.getExpression()),
354 typeDecl);
355
356 variableDeclarationListTails.add(
357 new AVariableDeclarationListTail(
358 name.getComma(),
359 variableDeclaration,
360 null));
361 }
362 }
363
364 AVariableDeclarationList list =
365 new AVariableDeclarationList(
366 new AVariableDeclaration(initialName, typeDeclaration),
367 null,
368 variableDeclarationListTails);
369 return list;
370 }
371
372 }
373
374 /***
375 * A tree traversal class that searchs for a name in a expression.
376 */
377 private class NameFinder extends DepthFirstAdapter {
378
379 private TName foundName;
380
381 /***
382 * @see org.ocltf.parser.analysis.DepthFirstAdapter#caseAPathName(org.ocltf.parser.node.APathName)
383 */
384 public void caseAPathName(APathName pathName) {
385 this.foundName = pathName.getName();
386 }
387
388 /***
389 * @return String the TName
390 */
391 public TName getName() {
392 return this.foundName;
393 }
394 }
395
396 /***
397 * Gets the TName from the <code>expression</code>.
398 * @param expression
399 * @return TName the name extracted from the <code>expression</code>.
400 */
401 protected TName getName(PExpression expression) {
402 NameFinder finder = new NameFinder();
403 expression.apply(finder);
404 return finder.getName();
405 }
406 }