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   import java.util.List;
7   
8   import de.fhdw.wtf.common.ast.AttributeModifier;
9   import de.fhdw.wtf.common.ast.AttributeModifierFindable;
10  import de.fhdw.wtf.common.ast.AttributeModifierMutable;
11  import de.fhdw.wtf.common.ast.AttributeModifierPrior;
12  import de.fhdw.wtf.common.ast.AttributeModifierSymmetric;
13  import de.fhdw.wtf.common.ast.AttributeModifierTransient;
14  import de.fhdw.wtf.common.ast.visitor.AttributModifierVisitor;
15  import de.fhdw.wtf.common.exception.parser.AbstractParserException;
16  import de.fhdw.wtf.common.exception.parser.AttributeModifierAlreadyAddedException;
17  import de.fhdw.wtf.common.exception.parser.NoSemicolonException;
18  import de.fhdw.wtf.common.stream.TokenStream;
19  import de.fhdw.wtf.common.token.IdentifierToken;
20  import de.fhdw.wtf.common.token.Token;
21  
22  /**
23   * Parser to parse the given TokenStream to {@link AttributeModifier}s.
24   */
25  public final class AttributeModifierParser {
26  	
27  	/**
28  	 * Tokenstream.
29  	 */
30  	private final TokenStream stream;
31  	
32  	/**
33  	 * Collection for exceptions.
34  	 */
35  	private final Collection<AbstractParserException> exceptions;
36  	
37  	/**
38  	 * Constrcutor of {@link AttributeModifierParser}.
39  	 * 
40  	 * @param stream
41  	 *            tokenstream
42  	 * @param exceptions
43  	 *            collection for exceptions
44  	 */
45  	private AttributeModifierParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
46  		this.stream = stream;
47  		this.exceptions = exceptions;
48  	}
49  	
50  	/**
51  	 * Creates a {@link AttributeModifierParser}-Object.
52  	 * 
53  	 * @param stream
54  	 *            tokenstream
55  	 * @param exceptions
56  	 *            collection for exceptions
57  	 * @return the {@link AttributeModifierParser}-Object.
58  	 */
59  	static AttributeModifierParser create(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
60  		return new AttributeModifierParser(stream, exceptions);
61  	}
62  	
63  	/**
64  	 * Parses the next series of Tokens of this.stream to AttributeModifiers until a SemicolonToken occurs. If one of
65  	 * the Tokens between the first element of this.stream and the next SemicolonToken is not a AttributeModifierToken,
66  	 * a NoAttributeModifierException will be thrown.
67  	 * 
68  	 * @return found attribute modifiers
69  	 * @throws AbstractParserException
70  	 *             possible Exceptions
71  	 */
72  	List<AttributeModifier> parse() throws AbstractParserException {
73  		final List<AttributeModifier> modifiers = new ArrayList<>();
74  		while (this.stream.hasNext()) {
75  			if (this.stream.peek().isSemicolonToken()) {
76  				break;
77  			} else {
78  				try {
79  					final AttributeModifier modifier = this.parseAttributeModifier(modifiers);
80  					modifiers.add(modifier);
81  				} catch (final AttributeModifierAlreadyAddedException e) {
82  					this.stream.removeFirst();
83  					this.exceptions.add(e);
84  				}
85  			}
86  		}
87  		return modifiers;
88  	}
89  	
90  	/**
91  	 * Checks if the next Token of this.stream is a AttributeModifierToken and returns it, if it is. Otherwise a
92  	 * {@link NoSemicolonException} will be returned.
93  	 * 
94  	 * @param modifiers
95  	 *            already found modfiers
96  	 * @return attribute Modifier
97  	 * @throws AbstractParserException
98  	 *             possible Exception
99  	 */
100 	private AttributeModifier parseAttributeModifier(final Collection<AttributeModifier> modifiers)
101 			throws AbstractParserException {
102 		
103 		final Token nextToken = this.stream.peek();
104 		if (nextToken.isAttributeModifierToken()) {
105 			if (containsAttributeModifier(modifiers, nextToken)) {
106 				throw AttributeModifierAlreadyAddedException.create(nextToken);
107 			}
108 			if (nextToken.isPriorModifierToken()) {
109 				this.stream.removeFirst();
110 				return AttributeModifierPrior.create(nextToken, this.stream.peek());
111 			}
112 			if (nextToken.isTransientToken()) {
113 				this.stream.removeFirst();
114 				return AttributeModifierTransient.create(nextToken, this.stream.peek());
115 			}
116 			if (nextToken.isFindableToken()) {
117 				this.stream.removeFirst();
118 				return AttributeModifierFindable.create(nextToken, this.stream.peek());
119 			}
120 			if (nextToken.isMutableToken()) {
121 				this.stream.removeFirst();
122 				return AttributeModifierMutable.create(nextToken, this.stream.peek());
123 			}
124 			if (nextToken.isSymmetricToken()) {
125 				this.stream.removeFirst();
126 				ParserUtils.requireAndRemoveBracketOpenToken(this.stream);
127 				final IdentifierToken symmetricIdentifier = ParserUtils.requireAndRemoveIdentifier(this.stream);
128 				final Token lastToken = ParserUtils.requireAndRemoveBracketCloseToken(this.stream);
129 				final AttributeModifierSymmetric symmetricModifier =
130 						AttributeModifierSymmetric.create(nextToken, symmetricIdentifier, this.stream.peek());
131 				symmetricModifier.setLastToken(lastToken);
132 				return symmetricModifier;
133 			}
134 		}
135 		throw NoSemicolonException.create(nextToken);
136 	}
137 	
138 	/**
139 	 * Returns true if <code>modifiers</code> contains a modifier of the type of <code>modifier</code>, otherwise false.
140 	 * 
141 	 * @param modifiers
142 	 *            : Modifiers of {@link AttributeModifier}.
143 	 * @param modifier
144 	 *            : modifier to search for.
145 	 * @return Boolean
146 	 */
147 	private static boolean containsAttributeModifier(final Collection<AttributeModifier> modifiers, final Token modifier) {
148 		final Iterator<AttributeModifier> i = modifiers.iterator();
149 		while (i.hasNext()) {
150 			final AttributeModifier current = i.next();
151 			if (current.accept(new AttributModifierVisitor() {
152 				
153 				@Override
154 				public boolean handle(final AttributeModifierPrior prior) {
155 					return modifier.isPriorModifierToken();
156 				}
157 				
158 				@Override
159 				public boolean handle(final AttributeModifierTransient tranzient) {
160 					return modifier.isTransientToken();
161 				}
162 				
163 				@Override
164 				public boolean handle(final AttributeModifierFindable findable) {
165 					return modifier.isFindableToken();
166 				}
167 				
168 				@Override
169 				public boolean handle(final AttributeModifierMutable mutable) {
170 					return modifier.isMutableToken();
171 				}
172 				
173 				@Override
174 				public boolean handle(final AttributeModifierSymmetric symmetric) {
175 					return modifier.isSymmetricToken();
176 				}
177 			})) {
178 				return true;
179 			}
180 		}
181 		return false;
182 	}
183 }