Skip to content

Method: GroupParser(TokenStream, Collection)

1: package de.fhdw.wtf.parser;
2:
3: import java.util.ArrayList;
4: import java.util.Collection;
5: import java.util.List;
6:
7: import de.fhdw.wtf.common.ast.Group;
8: import de.fhdw.wtf.common.ast.GroupElement;
9: import de.fhdw.wtf.common.ast.Name;
10: import de.fhdw.wtf.common.exception.parser.AbstractParserException;
11: import de.fhdw.wtf.common.exception.parser.NoSemicolonException;
12: import de.fhdw.wtf.common.stream.TokenStream;
13: import de.fhdw.wtf.common.token.IdentifierToken;
14: import de.fhdw.wtf.common.token.Token;
15:
16: /**
17: * Parser to parse a group from a given tokenstream.
18: */
19: final class GroupParser {
20:         /**
21:          * TokenStream.
22:          */
23:         private final TokenStream stream;
24:         
25:         /**
26:          * Collection of exceptions.
27:          */
28:         private final Collection<AbstractParserException> exceptions;
29:         
30:         /**
31:          * Constructor of {@link GroupParser}.
32:          *
33:          * @param stream
34:          * tokenStream
35:          * @param exceptions
36:          * collection of exceptions
37:          */
38:         private GroupParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
39:                 this.stream = stream;
40:                 this.exceptions = exceptions;
41:         }
42:         
43:         /**
44:          * FactoryMethod for {@link GroupParser}.
45:          *
46:          * @param stream
47:          * tokenStream
48:          * @param exceptions
49:          * collection of exceptions
50:          * @return The {@link GroupParser}-Object.
51:          */
52:         static GroupParser create(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
53:                 return new GroupParser(stream, exceptions);
54:         }
55:         
56:         /**
57:          * Parses a Group with <code>groupName</code> as the group name from this.stream. This method expects the first
58:          * Token in the stream to be an EqualToken and the second to be an SquareBracketOpenToken. This method calls an
59:          * operation to parse the Elements of the group. If one of the Tokens in the stream is unexpected, an
60:          * AbstractParserException will be thrown.
61:          *
62:          * @param groupName
63:          * groupName
64:          * @param firstToken
65:          * firstToken
66:          * @return parsed Group
67:          */
68:         Group parse(final Name groupName, final Token firstToken) {
69:                 final List<GroupElement> groups = new ArrayList<>();
70:                 final Group group = Group.create(groupName, groups, firstToken);
71:                 try {
72:                         ParserUtils.requireAndRemoveEqualToken(this.stream);
73:                         ParserUtils.requireAndRemoveSquareBracketOpenToken(this.stream);
74:                 } catch (final AbstractParserException e) {
75:                         if (this.stream.hasNext() && this.stream.peek().isSquareBracketOpenToken()) {
76:                                 this.stream.next();
77:                         }
78:                         this.exceptions.add(e);
79:                 }
80:                 while (this.stream.hasNext() && !(this.stream.peek().isEndToken()) && !this.checkGroupEnd()) {
81:                         try {
82:                                 final IdentifierToken idtoken = ParserUtils.requireAndRemoveIdentifier(this.stream);
83:                                 final Token nextToken = this.stream.peek();
84:                                 ParserUtils.requireAndRemoveColonToken(this.stream);
85:                                 ParserUtils.requireGroupElement(this.stream);
86:                                 final Name newName = groupName.addName(idtoken, nextToken);
87:                                 newName.setFirstToken(idtoken); // Don't reuse the group tokens!
88:                                                                                                 // -> safe if reusing the
89:                                                                                                 // tokens.
90:                                 groups.add(this.parseGroupElement(newName));
91:                         } catch (final AbstractParserException e) {
92:                                 this.exceptions.add(e);
93:                                 ParserUtils.skipToSemicolonToken(this.stream);
94:                                 // if the next token is an EndToken, we can stop here.
95:                                 // If we don't stop here, we always get a NoSemicolonException.
96:                                 if (this.stream.peek().isEndToken()) {
97:                                         return group;
98:                                 } else {
99:                                         continue;
100:                                 }
101:                         }
102:                 }
103:                 try {
104:                         ParserUtils.requireSemicolonToken(this.stream);
105:                         this.stream.next();
106:                         group.setLastToken(this.stream.peek());
107:                 } catch (final NoSemicolonException e) {
108:                         this.exceptions.add(e);
109:                 }
110:                 return group;
111:         }
112:         
113:         /**
114:          * This method parses a GroupElement into a syntax tree structure. Be careful to call this method only in the case
115:          * that the next token is a GroupElement.
116:          *
117:          * @param name
118:          * : Name of the GroupElement.
119:          * @return : GroupElement.
120:          * @throws AbstractParserException
121:          * If neither .parseClass or .parseGroup throws an exception.
122:          */
123:         private GroupElement parseGroupElement(final Name name) throws AbstractParserException {
124:                 final Token nextToken = this.stream.next();
125:                 if (nextToken.isClassToken()) {
126:                         return RegularClassParser.create(this.stream, this.exceptions).parse(name, name.getFirstToken());
127:                 } else if (nextToken.isExceptionToken()) {
128:                         return ExceptionClassParser.create(this.stream, this.exceptions).parse(name, name.getFirstToken());
129:                 } else {
130:                         return this.parse(name, name.getFirstToken());
131:                 }
132:         }
133:         
134:         /**
135:          * Returns true if the next Token of this.stream is a SquareBracketCloseToken, otherwise false.
136:          *
137:          * @return Boolean
138:          */
139:         private boolean checkGroupEnd() {
140:                 if (!this.stream.peek().isSquareBracketCloseToken()) {
141:                         return false;
142:                 }
143:                 this.stream.removeFirst();
144:                 return true;
145:         }
146: }