001: package org.andromda.translation.ocl.parser;
002:
003: import org.andromda.translation.ocl.analysis.AnalysisAdapter;
004: import org.andromda.translation.ocl.analysis.DepthFirstAdapter;
005: import org.andromda.translation.ocl.lexer.Lexer;
006: import org.andromda.translation.ocl.node.AActualParameterList;
007: import org.andromda.translation.ocl.node.ABarFeatureCallParameterOption;
008: import org.andromda.translation.ocl.node.AColonFeatureCallParameterOption;
009: import org.andromda.translation.ocl.node.ACommaExpression;
010: import org.andromda.translation.ocl.node.ACommaFeatureCallParameterOption;
011: import org.andromda.translation.ocl.node.AConcreteFeatureCallParameters;
012: import org.andromda.translation.ocl.node.AEqualExpression;
013: import org.andromda.translation.ocl.node.AFeatureCallParameters;
014: import org.andromda.translation.ocl.node.AIterateDeclarator;
015: import org.andromda.translation.ocl.node.AIterateFeatureCallParameterOption;
016: import org.andromda.translation.ocl.node.APathName;
017: import org.andromda.translation.ocl.node.AStandardDeclarator;
018: import org.andromda.translation.ocl.node.ATypeDeclaration;
019: import org.andromda.translation.ocl.node.AVariableDeclaration;
020: import org.andromda.translation.ocl.node.AVariableDeclarationList;
021: import org.andromda.translation.ocl.node.AVariableDeclarationListTail;
022: import org.andromda.translation.ocl.node.Node;
023: import org.andromda.translation.ocl.node.PExpression;
024: import org.andromda.translation.ocl.node.PFeatureCallParameterOption;
025: import org.andromda.translation.ocl.node.TName;
026:
027: import java.util.ArrayList;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.LinkedList;
031: import java.util.List;
032: import java.util.Map;
033:
034: /**
035: * This class adapts the Parser class to handle expressions in which the SableCC parser can't handle.
036: */
037: public class OclParser extends Parser {
038: protected Node oclNode;
039:
040: /**
041: * Constructs an instance of OclParser.
042: *
043: * @param lexer
044: */
045: public OclParser(Lexer lexer) {
046: super (lexer);
047: }
048:
049: /**
050: * @see org.andromda.core.translation.parser.Parser#filter()
051: */
052: protected void filter() {
053: oclNode = node;
054: oclNode.apply(handler);
055: node = oclNode;
056: }
057:
058: protected SyntaxHandler handler = new SyntaxHandler();
059:
060: /**
061: * A private inner class for handling syntax which SableCC can't handle on its own.
062: */
063: private class SyntaxHandler extends AnalysisAdapter {
064:
065: /**
066: * @see org.andromda.core.translation.parser.analysis.Analysis#caseAConcreteFeatureCallParameters(org.andromda.core.translation.parser.node.AConcreteFeatureCallParameters)
067: */
068: public void caseAConcreteFeatureCallParameters(
069: AConcreteFeatureCallParameters featureCallParameters) {
070: boolean isDeclarator = false;
071: boolean isIterateDeclarator = false;
072:
073: List tail = featureCallParameters
074: .getFeatureCallParameterOption();
075: PFeatureCallParameterOption[] parameterOption = new PFeatureCallParameterOption[tail
076: .size()];
077: Iterator iter = tail.iterator();
078:
079: for (int ctr = 0; iter.hasNext(); ctr++) {
080: PFeatureCallParameterOption option = (PFeatureCallParameterOption) iter
081: .next();
082: parameterOption[ctr] = option;
083: isIterateDeclarator = option instanceof AIterateFeatureCallParameterOption;
084: if (!isIterateDeclarator) {
085: isDeclarator = option instanceof ABarFeatureCallParameterOption;
086: }
087: }
088:
089: if (isIterateDeclarator && !isDeclarator) {
090: throw new OclParserException(
091: "Parser Error: Illegal feature call parameters format in \""
092: + featureCallParameters
093: + "\"; "
094: + "must contain \";\" only if it contains \"|\"");
095: }
096: AFeatureCallParameters parameters;
097: if (isIterateDeclarator) {
098: parameters = getParametersWithIterateDeclarator(
099: featureCallParameters, featureCallParameters
100: .getExpression(), parameterOption);
101: } else if (isDeclarator) {
102: parameters = getParametersWithStandardDeclarator(
103: featureCallParameters, parameterOption);
104: } else {
105: parameters = getParametersWithoutDeclarator(
106: featureCallParameters, featureCallParameters
107: .getExpression(), parameterOption);
108: }
109: oclNode = parameters;
110: }
111:
112: /**
113: * Gets the AFeatureCallParameters with a iterate declarator.
114: *
115: * @param featureCallParameters
116: * @param expression
117: * @param parameterOption
118: * @return AFeatureCallParameters
119: */
120: protected AFeatureCallParameters getParametersWithIterateDeclarator(
121: AConcreteFeatureCallParameters featureCallParameters,
122: PExpression expression,
123: PFeatureCallParameterOption[] parameterOption) {
124: AIterateDeclarator iteratorDeclarator = new AIterateDeclarator();
125:
126: AColonFeatureCallParameterOption featureCallParameterOption0 = (AColonFeatureCallParameterOption) parameterOption[0];
127: AIterateFeatureCallParameterOption featureCallParameterOption1 = (AIterateFeatureCallParameterOption) parameterOption[1];
128: ABarFeatureCallParameterOption featureCallParameterOption2 = (ABarFeatureCallParameterOption) parameterOption[2];
129:
130: AVariableDeclaration iterator = new AVariableDeclaration(
131: getName(expression), featureCallParameterOption0
132: .getTypeDeclaration());
133: iteratorDeclarator.setIterator(iterator);
134: iteratorDeclarator.setSemicolon(featureCallParameterOption1
135: .getSemicolon());
136:
137: AVariableDeclaration accumulator = new AVariableDeclaration(
138: featureCallParameterOption1.getName(),
139: featureCallParameterOption1.getTypeDeclaration());
140: iteratorDeclarator.setAccumulator(accumulator);
141:
142: AEqualExpression equalExpression = new AEqualExpression(
143: featureCallParameterOption1.getEqual(),
144: featureCallParameterOption1.getExpression());
145: iteratorDeclarator.setEqualExpression(equalExpression);
146: iteratorDeclarator.setBar(featureCallParameterOption2
147: .getBar());
148: AActualParameterList params = new AActualParameterList(
149: featureCallParameterOption2.getExpression(),
150: new ArrayList());
151: return new AFeatureCallParameters(featureCallParameters
152: .getLParen(), iteratorDeclarator, params,
153: featureCallParameters.getRParen());
154: }
155:
156: /**
157: * Gets AFeatureCallParameters from the standard declarator.
158: *
159: * @param featureCallParameters
160: * @param parameterOption
161: * @return AFeatureCallParameters
162: */
163: protected AFeatureCallParameters getParametersWithStandardDeclarator(
164: AConcreteFeatureCallParameters featureCallParameters,
165: PFeatureCallParameterOption[] parameterOptions) {
166:
167: int parameterOptionNum = parameterOptions.length;
168:
169: // check if the parameterOptions (after the first two)
170: // are instances of either ACommaFeatureCallParameter
171: // (so we can retrieve something like ', name') or
172: // ColonFeatureCallParameterOption (so we can retrieve
173: // something like ': type') and valid to false if this
174: // isn't the case.
175: for (int ctr = 0; ctr < parameterOptionNum - 2; ctr++) {
176: if (!(parameterOptions[ctr] instanceof ACommaFeatureCallParameterOption || parameterOptions[ctr] instanceof AColonFeatureCallParameterOption)) {
177: throw new OclParserException(
178: "OCL Parser Error: Feature call parameters with "
179: + "a standard declarator must have the format "
180: + "\"( name (: type)?, ... , name (: type)? | expression )\"");
181: }
182: }
183:
184: ABarFeatureCallParameterOption barParameterType = (ABarFeatureCallParameterOption) parameterOptions[parameterOptionNum - 1];
185:
186: AStandardDeclarator standardDeclarator = new AStandardDeclarator(
187: this
188: .getVariableDeclarationList(featureCallParameters),
189: barParameterType.getBar());
190: AActualParameterList params = new AActualParameterList(
191: barParameterType.getExpression(), new ArrayList());
192: return new AFeatureCallParameters(featureCallParameters
193: .getLParen(), standardDeclarator, params,
194: featureCallParameters.getRParen());
195: }
196:
197: /**
198: * Gets the AFeatureCallParameter instance without the declarator.
199: *
200: * @param featureCallParameters
201: * @param expr
202: * @param parameterOption
203: * @return AFeatureCallParameters
204: */
205: protected AFeatureCallParameters getParametersWithoutDeclarator(
206: AConcreteFeatureCallParameters featureCallParameters,
207: PExpression expr,
208: PFeatureCallParameterOption[] parameterOption) {
209:
210: List paramList = new ArrayList();
211:
212: for (int ctr = 0; ctr < parameterOption.length; ctr++) {
213: if (!(parameterOption[ctr] instanceof ACommaFeatureCallParameterOption)) {
214: throw new OclParserException(
215: "parser error: declarator-less feature call paramaters must have the format "
216: + "\"( expr, ..., expr )\"");
217: }
218: ACommaFeatureCallParameterOption commaOption = (ACommaFeatureCallParameterOption) parameterOption[ctr];
219: ACommaExpression commaExpression = new ACommaExpression(
220: commaOption.getComma(), commaOption
221: .getExpression());
222: paramList.add(commaExpression);
223: }
224:
225: return new AFeatureCallParameters(featureCallParameters
226: .getLParen(), null, new AActualParameterList(expr,
227: paramList), featureCallParameters.getRParen());
228: }
229:
230: /**
231: * Gets the AVariableDeclarationList instance from the <code>params</code> by apply the
232: * VariableDeclarationListFinder to it.
233: *
234: * @param params the params node to parse.
235: * @return the found AVariableDeclarationList instance.
236: */
237: protected AVariableDeclarationList getVariableDeclarationList(
238: AConcreteFeatureCallParameters params) {
239: VariableDeclarationListFinder finder = new VariableDeclarationListFinder();
240: params.apply(finder);
241: return finder.getList();
242: }
243:
244: }
245:
246: /**
247: * A tree traversal class that searchs for a name in a expression.
248: */
249: private class VariableDeclarationListFinder extends
250: DepthFirstAdapter {
251: /**
252: * Stores the variable names in an ordered fashion so that we can retrieve them from the namesAndTypes map in
253: * the order they were stored.
254: */
255: private LinkedList orderedNames = new LinkedList();
256:
257: /**
258: * Stores the variable names along with its variable type (if there is one).
259: */
260: private Map namesAndTypes = new HashMap();
261:
262: /**
263: * @see org.andromda.core.translation.parser.analysis.DepthFirstAdapter#inAPathName(org.andromda.core.translation.parser.node.APathName)
264: */
265: public void inAPathName(APathName name) {
266: // we only want to add the first name (since the other
267: // names will all be comma seperated and stored within
268: // the inACommaFeatureCallParameterOption() method)
269: if (this .namesAndTypes.isEmpty()) {
270: TName initialVariableName = name.getName();
271: this .orderedNames.add(initialVariableName);
272: this .namesAndTypes.put(this .orderedNames.getLast(),
273: null);
274: }
275: }
276:
277: /**
278: * @see org.andromda.core.translation.parser.analysis.DepthFirstAdapter#inACommaFeatureCallParameterOption(org.andromda.core.translation.parser.node.ACommaFeatureCallParameterOption)
279: */
280: public void inACommaFeatureCallParameterOption(
281: ACommaFeatureCallParameterOption commaName) {
282: this .orderedNames.add(commaName);
283: this .namesAndTypes.put(commaName, null);
284: }
285:
286: /**
287: * @see org.andromda.core.translation.parser.analysis.DepthFirstAdapter#inATypeDeclaration(org.andromda.core.translation.parser.node.ATypeDeclaration)
288: */
289: public void inATypeDeclaration(ATypeDeclaration type) {
290: if (this .namesAndTypes.containsKey(this .orderedNames
291: .getLast())) {
292: this .namesAndTypes.put(this .orderedNames.getLast(),
293: type);
294: }
295: }
296:
297: /**
298: * Extracts and constructs AVariableDeclarationlist from a AConcreteFeatureCallParameters instance.
299: *
300: * @return AVariableDeclarationList
301: */
302: public AVariableDeclarationList getList() {
303:
304: TName initialName = (TName) this .orderedNames.getFirst();
305:
306: ATypeDeclaration typeDeclaration = (ATypeDeclaration) namesAndTypes
307: .get(initialName);
308:
309: List variableDeclarationListTails = new ArrayList();
310: if (!this .orderedNames.isEmpty()) {
311: int orderedNameSize = orderedNames.size();
312: for (int ctr = 1; ctr < orderedNameSize; ctr++) {
313: ACommaFeatureCallParameterOption name = (ACommaFeatureCallParameterOption) this .orderedNames
314: .get(ctr);
315:
316: ATypeDeclaration typeDecl = (ATypeDeclaration) this .namesAndTypes
317: .get(name);
318:
319: AVariableDeclaration variableDeclaration = new AVariableDeclaration(
320: getName(name.getExpression()), typeDecl);
321:
322: variableDeclarationListTails
323: .add(new AVariableDeclarationListTail(name
324: .getComma(), variableDeclaration,
325: null));
326: }
327: }
328:
329: AVariableDeclarationList list = new AVariableDeclarationList(
330: new AVariableDeclaration(initialName,
331: typeDeclaration), null,
332: variableDeclarationListTails);
333: return list;
334: }
335: }
336:
337: /**
338: * A tree traversal class that searches for a name in a expression.
339: */
340: private class NameFinder extends DepthFirstAdapter {
341: private TName foundName;
342:
343: /**
344: * @see org.andromda.core.translation.parser.analysis.Analysis#caseAPathName(org.andromda.core.translation.parser.node.APathName)
345: */
346: public void caseAPathName(APathName pathName) {
347: this .foundName = pathName.getName();
348: }
349:
350: /**
351: * @return String the TName
352: */
353: public TName getName() {
354: return this .foundName;
355: }
356: }
357:
358: /**
359: * Gets the TName from the <code>expression</code>.
360: *
361: * @param expression
362: * @return TName the name extracted from the <code>expression</code>.
363: */
364: protected TName getName(PExpression expression) {
365: NameFinder finder = new NameFinder();
366: expression.apply(finder);
367: return finder.getName();
368: }
369: }
|