View Javadoc
1   package de.fhdw.wtf.parser;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.List;
6   import java.util.Vector;
7   
8   import de.fhdw.wtf.common.ast.Constructor;
9   import de.fhdw.wtf.common.ast.ConstructorByTypeAndSignatureState;
10  import de.fhdw.wtf.common.ast.ConstructorReference;
11  import de.fhdw.wtf.common.ast.Name;
12  import de.fhdw.wtf.common.ast.type.ByNameState;
13  import de.fhdw.wtf.common.ast.type.ClassType;
14  import de.fhdw.wtf.common.ast.type.ProductType;
15  import de.fhdw.wtf.common.ast.type.Type;
16  import de.fhdw.wtf.common.ast.type.TypeProxy;
17  import de.fhdw.wtf.common.exception.parser.AbstractParserException;
18  import de.fhdw.wtf.common.stream.TokenStream;
19  import de.fhdw.wtf.common.token.Token;
20  import de.fhdw.wtf.common.token.symbols.BracketCloseToken;
21  import de.fhdw.wtf.common.token.symbols.SemicolonToken;
22  
23  /**
24   * Parser to parse the given TokenStream to {@link Constructor}s.
25   */
26  final class ConstructorParser {
27  	
28  	/**
29  	 * Token stream.
30  	 */
31  	private final TokenStream stream;
32  	
33  	/**
34  	 * Collection for exceptions.
35  	 */
36  	private final Collection<AbstractParserException> exceptions;
37  	
38  	/**
39  	 * Constructor of {@link ConstructorParser}.
40  	 * 
41  	 * @param stream
42  	 *            token stream
43  	 * @param exceptions
44  	 *            collection for exceptions
45  	 */
46  	private ConstructorParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
47  		this.stream = stream;
48  		this.exceptions = exceptions;
49  	}
50  	
51  	/**
52  	 * Creates a {@link ConstructorParser}-Object.
53  	 * 
54  	 * @param stream
55  	 *            token stream
56  	 * @param exceptions
57  	 *            collection for exceptions
58  	 * @return the {@link ConstructorParser}-Object.
59  	 */
60  	protected static ConstructorParser create(final TokenStream stream,
61  			final Collection<AbstractParserException> exceptions) {
62  		return new ConstructorParser(stream, exceptions);
63  	}
64  	
65  	/**
66  	 * Parses a series of Tokens and creates an Constructor.
67  	 * 
68  	 * @param firstToken
69  	 *            firstToken
70  	 * @param owner
71  	 *            the owner-class of the constructor
72  	 * @return Attribute
73  	 * @throws AbstractParserException
74  	 *             AbstractParserException
75  	 */
76  	protected Constructor parse(final Token firstToken, final ClassType owner) throws AbstractParserException {
77  		final Collection<ConstructorReference> superConstructors = new Vector<>();
78  		final Token firstTokenProduct = this.stream.peek();
79  		final ProductType params = ProductType.create(firstTokenProduct);
80  		this.parseParameters(params);
81  		this.parseConstructorReferences(superConstructors);
82  		this.stream.removeFirst();
83  		// To this time it is not possible in wtf to set the exceptions for the constructors, because it is not
84  		// implemented
85  		final Constructor newConstructor = Constructor.create(params, owner, superConstructors, firstToken);
86  		return newConstructor;
87  	}
88  	
89  	/**
90  	 * Parses all constructor references until the {@link SemicolonToken} and adds them to superConstructors.
91  	 * 
92  	 * @param superConstructors
93  	 *            the Collection to add the references to.
94  	 * @throws AbstractParserException
95  	 *             if the given tokens do not match the expected syntax.
96  	 */
97  	private void parseConstructorReferences(final Collection<ConstructorReference> superConstructors)
98  			throws AbstractParserException {
99  		if (!this.stream.peek().isSemicolonToken()) {
100 			ParserUtils.requireAndRemoveEqualToken(this.stream);
101 			while (this.stream.hasNext() && this.stream.peek().isIdentifierToken()) {
102 				final Name typeForConstructorName = NameParser.createNameParser(this.stream).parse();
103 				final ByNameState byName = ByNameState.create(typeForConstructorName);
104 				final List<Type> parameters = new ArrayList<>();
105 				this.parseParameters(parameters);
106 				
107 				final ConstructorByTypeAndSignatureState byTypeAndSignatureState =
108 						ConstructorByTypeAndSignatureState.create(
109 								TypeProxy.create(typeForConstructorName.getFirstToken(), byName),
110 								parameters);
111 				
112 				superConstructors.add(ConstructorReference.create(byTypeAndSignatureState));
113 				if (this.stream.peek().isPlusSymbolToken()) {
114 					ParserUtils.requireAndRemovePlusSymbol(this.stream);
115 				}
116 			}
117 		}
118 		ParserUtils.requireSemicolonToken(this.stream);
119 	}
120 	
121 	/**
122 	 * Parses all parametersTypes from a ConstructorReference until the {@link BracketCloseToken} and adds them to
123 	 * parameters.
124 	 * 
125 	 * @param parameters
126 	 *            the Collection to add the parameters to.
127 	 * @throws AbstractParserException
128 	 *             if the given tokens do not match the expected syntax.
129 	 */
130 	private void parseParameters(final List<Type> parameters) throws AbstractParserException {
131 		ParserUtils.requireAndRemoveBracketOpenToken(this.stream);
132 		while (this.stream.hasNext() && this.stream.peek().isIdentifierToken()) {
133 			parameters.add(TypeParser.create(this.stream, this.exceptions).parse());
134 			if (this.stream.peek().isCommaToken()) {
135 				this.stream.removeFirst();
136 			}
137 		}
138 		ParserUtils.requireAndRemoveBracketCloseToken(this.stream);
139 	}
140 	
141 	/**
142 	 * Parses all parameters until the {@link BracketCloseToken} and adds them to parameters.
143 	 * 
144 	 * @param parameters
145 	 *            the Collection to add the parameters to.
146 	 * @throws AbstractParserException
147 	 *             if the given tokens do not match the expected syntax.
148 	 */
149 	private void parseParameters(final ProductType parameters) throws AbstractParserException {
150 		ParserUtils.requireAndRemoveBracketOpenToken(this.stream);
151 		while (this.stream.hasNext() && this.stream.peek().isIdentifierToken()) {
152 			parameters.addElement(ParameterParser.create(this.stream, this.exceptions).parse());
153 			if (this.stream.peek().isCommaToken()) {
154 				this.stream.removeFirst();
155 			}
156 		}
157 		ParserUtils.requireAndRemoveBracketCloseToken(this.stream);
158 		parameters.setLastToken(this.stream.peek());
159 	}
160 }