View Javadoc
1   package de.fhdw.wtf.parser;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Iterator;
6   
7   import de.fhdw.wtf.common.ast.Operation;
8   import de.fhdw.wtf.common.ast.OperationModifier;
9   import de.fhdw.wtf.common.ast.OperationModifierAbstract;
10  import de.fhdw.wtf.common.ast.visitor.OperationModifierVisitor;
11  import de.fhdw.wtf.common.exception.parser.AbstractParserException;
12  import de.fhdw.wtf.common.exception.parser.NoSemicolonException;
13  import de.fhdw.wtf.common.exception.parser.OperationModifierAlreadyAddedException;
14  import de.fhdw.wtf.common.stream.TokenStream;
15  import de.fhdw.wtf.common.token.Token;
16  
17  /**
18   * Parser to parse the given TokenStream to {@link OperationModifier}s.
19   */
20  public final class OperationModifierParser {
21  	
22  	/**
23  	 * TokenStream.
24  	 */
25  	private final TokenStream stream;
26  	
27  	/**
28  	 * Collection of exceptions.
29  	 */
30  	private final Collection<AbstractParserException> exceptions;
31  	
32  	/**
33  	 * Constructor of {@link OperationModifierParser}.
34  	 * 
35  	 * @param stream
36  	 *            tokenStream
37  	 * @param exceptions
38  	 *            collection of exceptions
39  	 */
40  	private OperationModifierParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
41  		this.stream = stream;
42  		this.exceptions = exceptions;
43  	}
44  	
45  	/**
46  	 * FactoryMethod for {@link OperationModifierParser}.
47  	 * 
48  	 * @param stream
49  	 *            tokenStream
50  	 * @param exceptions
51  	 *            collection of exceptions
52  	 * @return The {@link OperationModifierParser}-Object.
53  	 */
54  	static OperationModifierParser create(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
55  		return new OperationModifierParser(stream, exceptions);
56  	}
57  	
58  	/**
59  	 * Parses the next series of Tokens of this.stream to {@link OperationModifier}s until a SemicolonToken occurs. If
60  	 * one of the Tokens between the first element of this.stream and the next SemicolonToken is not a subtype of
61  	 * {@link OperationModifier}, a {@link NoSemicolonException} will be thrown.
62  	 * 
63  	 * @param currentOperation
64  	 *            currentOperation
65  	 * @return all OperationModifier
66  	 * @throws AbstractParserException
67  	 *             AbstractParserException
68  	 */
69  	Collection<OperationModifier> parse(final Operation currentOperation) throws AbstractParserException {
70  		final Collection<OperationModifier> result = new ArrayList<>();
71  		while (this.stream.hasNext()) {
72  			if (this.stream.peek().isSemicolonToken()) {
73  				this.stream.next();
74  				currentOperation.setLastToken(this.stream.peek());
75  				break;
76  			} else {
77  				try {
78  					result.add(this.parseOperationModifier(result));
79  				} catch (final OperationModifierAlreadyAddedException e) {
80  					this.exceptions.add(e);
81  					ParserUtils.skipToSemicolonToken(this.stream);
82  					break;
83  				}
84  			}
85  		}
86  		return result;
87  	}
88  	
89  	/**
90  	 * Checks if the next Token of this.stream is a OperationModifierToken and returns it, if it is. Otherwise a
91  	 * NoOperationModifierException will be returned.
92  	 * 
93  	 * @param modifiers
94  	 *            already found modifiers
95  	 * @return OperationModifier
96  	 * @throws AbstractParserException
97  	 *             AbstractParserException
98  	 */
99  	private OperationModifier parseOperationModifier(final Collection<OperationModifier> modifiers)
100 			throws AbstractParserException {
101 		final Token nextToken = this.stream.peek();
102 		if (nextToken.isOperationModifierToken()) {
103 			if (this.containsOperationModifier(modifiers, nextToken)) {
104 				throw OperationModifierAlreadyAddedException.create(nextToken);
105 			}
106 			if (nextToken.isAbstractOperationToken()) {
107 				this.stream.removeFirst();
108 				return OperationModifierAbstract.create(nextToken, this.stream.peek());
109 			}
110 		}
111 		throw NoSemicolonException.create(nextToken);
112 	}
113 	
114 	/**
115 	 * Checks if <code>modifiers</code> contains a modifier of the type of <code>modifier</code>.
116 	 * 
117 	 * @param modifiers
118 	 *            : Modifiers of {@link OperationModifier}
119 	 * @param modifier
120 	 *            : modifier to search for
121 	 * @return Boolean
122 	 */
123 	private boolean containsOperationModifier(final Collection<OperationModifier> modifiers, final Token modifier) {
124 		final Iterator<OperationModifier> i = modifiers.iterator();
125 		while (i.hasNext()) {
126 			final OperationModifier current = i.next();
127 			if (current.accept(new OperationModifierVisitor() {
128 				
129 				@Override
130 				public boolean handle(final OperationModifier abstract1) {
131 					return modifier.isAbstractOperationToken();
132 				}
133 				
134 			})) {
135 				return true;
136 			}
137 		}
138 		return false;
139 	}
140 }