View Javadoc

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 			// if there is less than one parameter in the parameterOption array
182 			if (parameterOptionNum < 1) {
183 				valid = false;	
184 			//check and make sure the last parameterOption is an instance of ABarFeatureCallParameterOption
185 			//and set to false if not.
186 			} else if (!(parameterOptions[parameterOptionNum - 1] instanceof ABarFeatureCallParameterOption)) {
187 				valid = false;
188 			}
189 			
190 			//check if the parameterOptions (after the first two) are instances of either 
191 			//ACommaFeatureCallParameter (so we can retrieve something like ', name') or
192 			//AColonFeatureCallParameterOption (so we can retrieve something like ': type') 
193 			//and valid to false if this isn't the case.
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         	//we only want to add the first name (since the other
302         	//names will all be comma seperated and stored within 
303         	//the inACommaFeatureCallParameterOption() method)
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 }