Skip to content

Package: ExceptionClassParser

ExceptionClassParser

nameinstructionbranchcomplexitylinemethod
ExceptionClassParser(TokenStream, Collection)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
checkClassEnd()
M: 2 C: 11
85%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 3
75%
M: 0 C: 1
100%
create(TokenStream, Collection)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
parse(Name, Token)
M: 62 C: 72
54%
M: 8 C: 2
20%
M: 5 C: 1
17%
M: 23 C: 25
52%
M: 0 C: 1
100%
parseClassElement(ClassType, Collection, Collection, Collection, String, ClassType, IdentifierToken)
M: 39 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
parseConstructor(Token, Collection, ClassType)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
parseSuperTypes()
M: 27 C: 20
43%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 7 C: 4
36%
M: 0 C: 1
100%
tryPossibleExceptions(TokenStream)
M: 26 C: 13
33%
M: 8 C: 2
20%
M: 5 C: 1
17%
M: 6 C: 4
40%
M: 0 C: 1
100%

Coverage

1: package de.fhdw.wtf.parser;
2:
3: import java.util.Collection;
4: import java.util.List;
5: import java.util.Vector;
6:
7: import de.fhdw.wtf.common.ast.Attribute;
8: import de.fhdw.wtf.common.ast.Constructor;
9: import de.fhdw.wtf.common.ast.Name;
10: import de.fhdw.wtf.common.ast.Operation;
11: import de.fhdw.wtf.common.ast.type.ByNameState;
12: import de.fhdw.wtf.common.ast.type.ClassModifier;
13: import de.fhdw.wtf.common.ast.type.ClassType;
14: import de.fhdw.wtf.common.ast.type.ExceptionClassType;
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.exception.parser.NoCurlyBracketOpenException;
19: import de.fhdw.wtf.common.exception.parser.NoEqualException;
20: import de.fhdw.wtf.common.exception.parser.NoPlusSymbolException;
21: import de.fhdw.wtf.common.exception.parser.NoSemicolonException;
22: import de.fhdw.wtf.common.stream.TokenStream;
23: import de.fhdw.wtf.common.token.IdentifierToken;
24: import de.fhdw.wtf.common.token.Token;
25:
26: /**
27: * Parser to parse a given {@link TokenStream}.
28: *
29: * * TODO -> Duplicate code. See RegularClassParser. As a first try just copied ClassParser to ExceptionClassParser and
30: * RegularClassParser. Think about how to split them.
31: */
32: public final class ExceptionClassParser {
33:         
34:         /**
35:          * Tokenstream.
36:          */
37:         private final TokenStream stream;
38:         
39:         /**
40:          * Collection for exceptions.
41:          */
42:         private final Collection<AbstractParserException> exceptions;
43:         
44:         /**
45:          * Constructor of {@link ExceptionClassParser}.
46:          *
47:          * @param stream
48:          * tokenstream
49:          * @param exceptions
50:          * collection for exceptions
51:          */
52:         private ExceptionClassParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
53:                 this.stream = stream;
54:                 this.exceptions = exceptions;
55:         }
56:         
57:         /**
58:          * Creates a {@link ExceptionClassParser}-Object.
59:          *
60:          * @param stream
61:          * tokenstream
62:          * @param exceptions
63:          * collection for exceptions
64:          * @return the {@link ExceptionClassParser}-Object.
65:          */
66:         protected static ExceptionClassParser create(final TokenStream stream,
67:                         final Collection<AbstractParserException> exceptions) {
68:                 return new ExceptionClassParser(stream, exceptions);
69:         }
70:         
71:         /**
72:          * Parses a Class with <code>name</code> as the class name from this.stream. This method expects the first Token in
73:          * the stream to be an EqualToken. This method calls an operation to parse the Attributes and ClassModifiers. If one
74:          * of the Tokens in the stream is unexpected, an AbstractParserException will be thrown.
75:          *
76:          * @param name
77:          * : Name of Class.
78:          * @param firstToken
79:          * : First token of class.
80:          * @throws AbstractParserException
81:          * AbstractParserException
82:          * @return ClassType
83:          */
84:         protected ClassType parse(final Name name, final Token firstToken) throws AbstractParserException {
85:                 try {
86:                         ParserUtils.requireAndRemoveEqualToken(this.stream);
87:                 } catch (final NoEqualException e) {
88:                         throw e;
89:                 }
90:                 
91:                 final Collection<Attribute> attributes = new Vector<>();
92:                 final Collection<ClassModifier> modifiers = new Vector<>();
93:                 final Collection<ClassType> subTypes = new Vector<>();
94:                 final Collection<Operation> operations = new Vector<>();
95:                 final List<Type> superTypes = new Vector<>();
96:                 final Collection<Constructor> constructors = new Vector<>();
97:                 final ClassType classResult =
98:                                 ExceptionClassType.create(
99:                                                 name,
100:                                                 modifiers,
101:                                                 attributes,
102:                                                 superTypes,
103:                                                 operations,
104:                                                 constructors,
105:                                                 firstToken,
106:                                                 subTypes);
107:                 try {
108:                         classResult.getSuperTypes().addAll(this.parseSuperTypes());
109:                         ParserUtils.requireAndRemoveCurlyBracketOpenToken(this.stream);
110:                 } catch (final NoCurlyBracketOpenException e) {
111:                         this.exceptions.add(e);
112:                         // Don't skip to next semicolon because you may find it behind the class so that
113:                         // you produce more exceptions as necessary.
114:                 }
115:•                while (this.stream.hasNext() && !this.checkClassEnd() && !(this.stream.peek().isEndToken())) {
116:                         final Token currentToken = this.stream.peek();
117:•                        if (currentToken.isIdentifierToken()) {
118:                                 try {
119:                                         final IdentifierToken token = ParserUtils.requireAndRemoveIdentifier(this.stream);
120:                                         this.parseClassElement(
121:                                                         classResult,
122:                                                         constructors,
123:                                                         attributes,
124:                                                         operations,
125:                                                         token.stringRepresentation(),
126:                                                         classResult,
127:                                                         token);
128:                                 } catch (final NoSemicolonException e) {
129:                                         throw e;
130:                                 } catch (final AbstractParserException e) {
131:                                         this.exceptions.add(e);
132:                                         ParserUtils.skipToSemicolonToken(this.stream);
133:                                         continue;
134:                                 }
135:•                        } else if (currentToken.isBracketOpenToken()) {
136:                                 this.parseConstructor(currentToken, constructors, classResult);
137:                         } else {
138:                                 ParserUtils.requireAndRemoveCurlyBracketCloseToken(this.stream);
139:                         }
140:                 }
141:                 modifiers.addAll(ClassModifierParser.create(this.stream, this.exceptions).parse(classResult));
142:                 classResult.setLastToken(this.stream.peek());
143:                 return classResult;
144:         }
145:         
146:         /**
147:          * Parses a constructor.
148:          *
149:          * @param firstToken
150:          * firstToken.
151:          * @param constructors
152:          * the list of constructors for classResult.
153:          * @param owner
154:          * the owner class of the constructor.
155:          * @throws AbstractParserException
156:          * if the syntax is not correct.
157:          */
158:         private void parseConstructor(final Token firstToken,
159:                         final Collection<Constructor> constructors,
160:                         final ClassType owner) throws AbstractParserException {
161:                 constructors.add(ConstructorParser.create(this.stream, this.exceptions).parse(firstToken, owner));
162:         }
163:         
164:         /**
165:          * Parses a series of tokens and returns the a list of {@link TypeProxy} . If the series of tokens does not match
166:          * the grammar an Exception will be thrown.
167:          *
168:          * @return super types
169:          * @throws AbstractParserException
170:          * {@link NoPlusSymbolException}: if there are some {@link IdentifierToken}s or an
171:          * {@link IdentifierToken} followed by an {@link de.fhdw.wtf.common.token.symbols.CurlyBracketOpenToken}
172:          * with no symbol between, than there is a PlusSymbol missing. {@link NoCurlyBracketOpenException}: If
173:          * it ist not a {@link NoPlusSymbolException} it must be a {@link NoCurlyBracketOpenException}.
174:          *
175:          */
176:         private Collection<TypeProxy> parseSuperTypes() throws AbstractParserException {
177:                 final Collection<TypeProxy> superTypes = new Vector<>();
178:                 
179:                 tryPossibleExceptions(this.stream.copy());
180:                 
181:•                while (this.stream.hasNext() && this.stream.peek().isIdentifierToken()) {
182:                         final NameParser nameParser = NameParser.createNameParser(this.stream);
183:                         final Name currentSuperTypeName = nameParser.parse();
184:                         
185:                         ParserUtils.requireAndRemovePlusSymbol(this.stream);
186:                         final ByNameState byName = ByNameState.create(currentSuperTypeName);
187:                         final TypeProxy typeProxy = TypeProxy.create(currentSuperTypeName.getFirstToken(), byName);
188:                         typeProxy.setLastToken(currentSuperTypeName.getLastToken());
189:                         superTypes.add(typeProxy);
190:                 }
191:                 return superTypes;
192:         }
193:         
194:         /**
195:          * Trys if there are any excpetions with missing + or {. In the case of missing { it is necessary to start the
196:          * parsing again from the first identifier. For example: Class:class=attribute:String;};
197:          *
198:          * @param copy
199:          * - a copy of the origin tokenStream
200:          * @throws AbstractParserException
201:          * {@link NoPlusSymbolException} and {@link NoCurlyBracketOpenException}.
202:          */
203:         private static void tryPossibleExceptions(final TokenStream copy) throws AbstractParserException {
204:                 final Token firstPosition = copy.peek();
205:                 
206:                 try {
207:•                        while (copy.hasNext() && copy.peek().isIdentifierToken()) {
208:                                 final NameParser nameParser = NameParser.createNameParser(copy);
209:                                 nameParser.parse();
210:                                 ParserUtils.requireAndRemovePlusSymbol(copy);
211:                         }
212:                 } catch (final NoPlusSymbolException e) {
213:•                        if (copy.hasNext() && (copy.peek().isIdentifierToken() || copy.peek().isCurlyBracketOpenToken())) {
214:                                 throw e;
215:                         } else {
216:                                 throw NoCurlyBracketOpenException.create(firstPosition);
217:                         }
218:                 }
219:         }
220:         
221:         /**
222:          * Parses a series of Tokens and creates attribute or operation. The name it is <code>name</code>. The result will
223:          * be add to <code>attributes</code> or <code>operations</code>. The first {@link Token} is <code>firstToken</code>.
224:          * be <code>attributeName</code>.
225:          *
226:          * @param classResult
227:          * the class that is being parsed at the moment.
228:          *
229:          * @param attributes
230:          * attributes
231:          * @param operations
232:          * operations
233:          * @param constructors
234:          * constructors
235:          * @param name
236:          * name of attribute or operation
237:          * @param firstToken
238:          * firstToken
239:          * @throws AbstractParserException
240:          * AbstractParserException
241:          */
242:         private void parseClassElement(final ClassType classResult,
243:                         final Collection<Constructor> constructors,
244:                         final Collection<Attribute> attributes,
245:                         final Collection<Operation> operations,
246:                         final String name,
247:                         final ClassType containingType,
248:                         final IdentifierToken firstToken) throws AbstractParserException {
249:                 ParserUtils.requireAndRemoveColonToken(this.stream);
250:                 final Token nextToken = this.stream.peek();
251:•                if (nextToken.isDoubleSquareBracketOpenToken()) {
252:                         this.stream.removeFirst();
253:                         operations
254:                                         .add(OperationParser.create(this.stream, this.exceptions).parse(name, containingType, firstToken));
255:                 } else {
256:                         attributes.add(AttributeParser.create(this.stream, this.exceptions).parse(name, firstToken));
257:                 }
258:                 
259:         }
260:         
261:         /**
262:          * Returns true if the next Token of this.stream is a CurlyBracketCloseToken, otherwise false.
263:          *
264:          * @return Boolean
265:          */
266:         private boolean checkClassEnd() {
267:•                if (!(this.stream.peek().isCurlyBracketCloseToken())) {
268:                         return false;
269:                 }
270:                 this.stream.removeFirst();
271:                 return true;
272:         }
273: }