-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
GeneratedJavaParserBase.java
369 lines (325 loc) · 12.7 KB
/
GeneratedJavaParserBase.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
package com.github.javaparser;
import com.github.javaparser.ast.ArrayCreationLevel;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.comments.CommentsCollection;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.type.ArrayType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.type.UnknownType;
import com.github.javaparser.utils.Pair;
import java.util.*;
import static com.github.javaparser.GeneratedJavaParserConstants.EOF;
import static com.github.javaparser.ast.type.ArrayType.unwrapArrayTypes;
import static com.github.javaparser.ast.type.ArrayType.wrapInArrayTypes;
import static com.github.javaparser.utils.Utils.assertNotNull;
/**
* Base class for {@link GeneratedJavaParser}
*/
abstract class GeneratedJavaParserBase {
//// Interface with the generated code
abstract GeneratedJavaParserTokenManager getTokenSource();
abstract void ReInit(Provider provider);
/* Returns the JavaParser specific token type of the last matched token */
abstract JavaToken token();
abstract Token getNextToken();
////
/* The problems encountered while parsing */
List<Problem> problems = new ArrayList<>();
/* Configuration flag whether we store tokens and tokenranges */
boolean storeTokens;
/* Resets the parser for reuse, gaining a little performance */
void reset(Provider provider) {
ReInit(provider);
problems = new ArrayList<>();
getTokenSource().reset();
}
/**
* Return the list of JavaParser specific tokens that have been encountered while parsing code using this parser.
*
* @return a list of tokens
*/
public List<JavaToken> getTokens() {
return getTokenSource().getTokens();
}
/* The collection of comments encountered */
CommentsCollection getCommentsCollection() {
return getTokenSource().getCommentsCollection();
}
/* Reports a problem to the user */
void addProblem(String message) {
// TODO tokenRange only takes the final token. Need all the tokens.
problems.add(new Problem(message, tokenRange(), null));
}
/* Returns a tokenRange that spans the last matched token */
TokenRange tokenRange() {
if (storeTokens) {
return new TokenRange(token(), token());
}
return null;
}
/**
* Return a TokenRange spanning from begin to end
*/
TokenRange range(JavaToken begin, JavaToken end) {
if (storeTokens) {
return new TokenRange(begin, end);
}
return null;
}
/**
* Return a TokenRange spanning from begin to end
*/
TokenRange range(Node begin, JavaToken end) {
if (storeTokens) {
return new TokenRange(begin.getTokenRange().get().getBegin(), end);
}
return null;
}
/**
* Return a TokenRange spanning from begin to end
*/
TokenRange range(JavaToken begin, Node end) {
if (storeTokens) {
return new TokenRange(begin, end.getTokenRange().get().getEnd());
}
return null;
}
/**
* Return a TokenRange spanning from begin to end
*/
TokenRange range(Node begin, Node end) {
if (storeTokens) {
return new TokenRange(begin.getTokenRange().get().getBegin(), end.getTokenRange().get().getEnd());
}
return null;
}
/**
* @return secondChoice if firstChoice is JavaToken.UNKNOWN, otherwise firstChoice
*/
JavaToken orIfInvalid(JavaToken firstChoice, JavaToken secondChoice) {
if (storeTokens) {
assertNotNull(firstChoice);
assertNotNull(secondChoice);
if (firstChoice.valid() || secondChoice.invalid()) {
return firstChoice;
}
return secondChoice;
}
return null;
}
/**
* @return the begin-token secondChoice if firstChoice is JavaToken.UNKNOWN, otherwise firstChoice
*/
JavaToken orIfInvalid(JavaToken firstChoice, Node secondChoice) {
if (storeTokens) {
return orIfInvalid(firstChoice, secondChoice.getTokenRange().get().getBegin());
}
return null;
}
/**
* Get the token that starts the NodeList l
*/
JavaToken nodeListBegin(NodeList<?> l) {
if (!storeTokens || l.isEmpty()) {
return JavaToken.INVALID;
}
return l.get(0).getTokenRange().get().getBegin();
}
/* Sets the kind of the last matched token to newKind */
void setTokenKind(int newKind) {
token().setKind(newKind);
}
/* Makes the parser keep a list of tokens */
void setStoreTokens(boolean storeTokens) {
this.storeTokens = storeTokens;
getTokenSource().setStoreTokens(storeTokens);
}
/* Called from within a catch block to skip forward to a known token,
and report the occurred exception as a problem. */
TokenRange recover(int recoveryTokenType, ParseException p) {
JavaToken begin = null;
if (p.currentToken != null) {
begin = token();
}
Token t;
do {
t = getNextToken();
} while (t.kind != recoveryTokenType && t.kind != EOF);
JavaToken end = token();
TokenRange tokenRange = null;
if (begin != null && end != null) {
tokenRange = range(begin, end);
}
problems.add(new Problem(makeMessageForParseException(p), tokenRange, p));
return tokenRange;
}
/**
* Quickly create a new NodeList
*/
<T extends Node> NodeList<T> emptyList() {
return new NodeList<>();
}
/**
* Add obj to list and return it. Create a new list if list is null
*/
<T extends Node> NodeList<T> add(NodeList<T> list, T obj) {
if (list == null) {
list = new NodeList<>();
}
list.add(obj);
return list;
}
/**
* Add obj to list only when list is not null
*/
<T extends Node> NodeList<T> addWhenNotNull(NodeList<T> list, T obj) {
if (obj == null) {
return list;
}
return add(list, obj);
}
/**
* Add obj to list at position pos
*/
<T extends Node> NodeList<T> prepend(NodeList<T> list, T obj) {
if (list == null) {
list = new NodeList<>();
}
list.addFirst(obj);
return list;
}
/**
* Add obj to list
*/
<T> List<T> add(List<T> list, T obj) {
if (list == null) {
list = new LinkedList<>();
}
list.add(obj);
return list;
}
/**
* Add modifier mod to modifiers
*/
void addModifier(EnumSet<Modifier> modifiers, Modifier mod) {
if (modifiers.contains(mod)) {
addProblem("Duplicated modifier");
}
modifiers.add(mod);
}
/**
* Propagate expansion of the range on the right to the parent. This is necessary when the right border of the child
* is determining the right border of the parent (i.e., the child is the last element of the parent). In this case
* when we "enlarge" the child we should enlarge also the parent.
*/
private void propagateRangeGrowthOnRight(Node node, Node endNode) {
if (storeTokens) {
node.getParentNode().ifPresent(nodeParent -> {
boolean isChildOnTheRightBorderOfParent = node.getTokenRange().get().getEnd().equals(nodeParent.getTokenRange().get().getEnd());
if (isChildOnTheRightBorderOfParent) {
propagateRangeGrowthOnRight(nodeParent, endNode);
}
});
node.setTokenRange(range(node, endNode));
}
}
/**
* Workaround for rather complex ambiguity that lambda's create
*/
Expression generateLambda(Expression ret, Statement lambdaBody) {
if (ret instanceof EnclosedExpr) {
Expression inner = ((EnclosedExpr) ret).getInner();
SimpleName id = ((NameExpr) inner).getName();
NodeList<Parameter> params = add(new NodeList<>(), new Parameter(ret.getTokenRange().orElse(null), EnumSet.noneOf(Modifier.class), new NodeList<>(), new UnknownType(), false, new NodeList<>(), id));
ret = new LambdaExpr(range(ret, lambdaBody), params, lambdaBody, true);
} else if (ret instanceof NameExpr) {
SimpleName id = ((NameExpr) ret).getName();
NodeList<Parameter> params = add(new NodeList<>(), new Parameter(ret.getTokenRange().orElse(null), EnumSet.noneOf(Modifier.class), new NodeList<>(), new UnknownType(), false, new NodeList<>(), id));
ret = new LambdaExpr(range(ret, lambdaBody), params, lambdaBody, false);
} else if (ret instanceof LambdaExpr) {
((LambdaExpr) ret).setBody(lambdaBody);
propagateRangeGrowthOnRight(ret, lambdaBody);
} else if (ret instanceof CastExpr) {
CastExpr castExpr = (CastExpr) ret;
Expression inner = generateLambda(castExpr.getExpression(), lambdaBody);
castExpr.setExpression(inner);
} else {
addProblem("Failed to parse lambda expression! Please create an issue at https://github.com/javaparser/javaparser/issues");
}
return ret;
}
/**
* Throws together an ArrayCreationExpr from a lot of pieces
*/
ArrayCreationExpr juggleArrayCreation(TokenRange range, List<TokenRange> levelRanges, Type type, NodeList<Expression> dimensions, List<NodeList<AnnotationExpr>> arrayAnnotations, ArrayInitializerExpr arrayInitializerExpr) {
NodeList<ArrayCreationLevel> levels = new NodeList<>();
for (int i = 0; i < arrayAnnotations.size(); i++) {
levels.add(new ArrayCreationLevel(levelRanges.get(i), dimensions.get(i), arrayAnnotations.get(i)));
}
return new ArrayCreationExpr(range, type, levels, arrayInitializerExpr);
}
/**
* Throws together a Type, taking care of all the array brackets
*/
Type juggleArrayType(Type partialType, List<ArrayType.ArrayBracketPair> additionalBrackets) {
Pair<Type, List<ArrayType.ArrayBracketPair>> partialParts = unwrapArrayTypes(partialType);
Type elementType = partialParts.a;
List<ArrayType.ArrayBracketPair> leftMostBrackets = partialParts.b;
return wrapInArrayTypes(elementType, leftMostBrackets, additionalBrackets).clone();
}
/**
* This is the code from ParseException.initialise, modified to be more horizontal.
*/
private String makeMessageForParseException(ParseException exception) {
final StringBuilder sb = new StringBuilder("Parse error. Found ");
final StringBuilder expected = new StringBuilder();
int maxExpectedTokenSequenceLength = 0;
TreeSet<String> sortedOptions = new TreeSet<>();
for (int i = 0; i < exception.expectedTokenSequences.length; i++) {
if (maxExpectedTokenSequenceLength < exception.expectedTokenSequences[i].length) {
maxExpectedTokenSequenceLength = exception.expectedTokenSequences[i].length;
}
for (int j = 0; j < exception.expectedTokenSequences[i].length; j++) {
sortedOptions.add(exception.tokenImage[exception.expectedTokenSequences[i][j]]);
}
}
for (String option : sortedOptions) {
expected.append(" ").append(option);
}
sb.append("");
Token token = exception.currentToken.next;
for (int i = 0; i < maxExpectedTokenSequenceLength; i++) {
String tokenText = token.image;
String escapedTokenText = ParseException.add_escapes(tokenText);
if (i != 0) {
sb.append(" ");
}
if (token.kind == 0) {
sb.append(exception.tokenImage[0]);
break;
}
escapedTokenText = "\"" + escapedTokenText + "\"";
String image = exception.tokenImage[token.kind];
if (image.equals(escapedTokenText)) {
sb.append(image);
} else {
sb.append(" ")
.append(escapedTokenText)
.append(" ")
.append(image);
}
token = token.next;
}
if (exception.expectedTokenSequences.length != 0) {
int numExpectedTokens = exception.expectedTokenSequences.length;
sb.append(", expected")
.append(numExpectedTokens == 1 ? "" : " one of ")
.append(expected.toString());
}
return sb.toString();
}
}