Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/langtools/tools/lib/builder/ClassBuilder.java
41152 views
1
/*
2
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
package builder;
25
26
import toolbox.ToolBox;
27
28
import java.io.IOException;
29
import java.nio.file.Files;
30
import java.nio.file.Path;
31
import java.nio.file.Paths;
32
import java.util.ArrayList;
33
import java.util.List;
34
import java.util.ListIterator;
35
import java.util.regex.Matcher;
36
import java.util.regex.Pattern;
37
import java.util.stream.Collectors;
38
import java.util.stream.Stream;
39
40
/**
41
* Builder for type declarations.
42
* Note: this implementation does not support everything and is not
43
* exhaustive.
44
*/
45
public class ClassBuilder extends AbstractBuilder {
46
47
private final ToolBox tb;
48
private final String fqn;
49
private final String clsname;
50
private final String typeParameter;
51
52
private String pkg;
53
private final List<String> imports;
54
55
private String extendsType;
56
private final List<String> implementsTypes;
57
private final List<MemberBuilder> members;
58
private final List<ClassBuilder> inners;
59
private final List<ClassBuilder> nested;
60
61
62
final static Pattern CLASS_RE = Pattern.compile("(.*)(<.*>)");
63
64
/**
65
* Creates a class builder.
66
* @param tb the toolbox reference
67
* @param name the name of the type
68
*/
69
public ClassBuilder(ToolBox tb, String name) {
70
super(new Modifiers(), name);
71
this.tb = tb;
72
73
Matcher m = CLASS_RE.matcher(name);
74
if (m.matches()) {
75
fqn = m.group(1);
76
typeParameter = m.group(2);
77
} else {
78
fqn = name;
79
typeParameter = null;
80
}
81
if (fqn.contains(".")) {
82
this.pkg = name.substring(0, fqn.lastIndexOf('.'));
83
clsname = fqn.substring(fqn.lastIndexOf('.') + 1);
84
} else {
85
clsname = fqn;
86
}
87
imports = new ArrayList<>();
88
implementsTypes = new ArrayList<>();
89
members = new ArrayList<>();
90
nested = new ArrayList<>();
91
inners = new ArrayList<>();
92
}
93
94
/**
95
* Adds an import(s).
96
* @param i the import type.
97
* @return this builder.
98
*/
99
public ClassBuilder addImports(String i) {
100
imports.add(i);
101
return this;
102
}
103
104
/**
105
* Sets the modifiers for this builder.
106
* @param modifiers the modifiers
107
* @return this builder
108
*/
109
public ClassBuilder setModifiers(String... modifiers) {
110
this.modifiers.setModifiers(modifiers);
111
return this;
112
}
113
114
/**
115
* Sets the enclosing type's name.
116
*
117
* @param className the enclosing type's name
118
*/
119
@Override
120
void setClassName(String className) {
121
cname = className;
122
}
123
124
/**
125
* Sets a comment for the element.
126
*
127
* @param comments for the element
128
* @return this builder.
129
*/
130
@Override
131
public ClassBuilder setComments(String... comments) {
132
super.setComments(comments);
133
return this;
134
}
135
136
/**
137
* Sets a comment for the element. Typically used to set
138
* the user's preferences whether an automatic comment is
139
* required or no API comment.
140
*
141
* @param kind of comment, automatic or no comment.
142
* @return this builder.
143
*/
144
@Override
145
public ClassBuilder setComments(Comment.Kind kind) {
146
super.setComments(kind);
147
return this;
148
}
149
150
/**
151
* Set the super-type of the type.
152
* @param name of the super type.
153
* @return this builder.
154
*/
155
public ClassBuilder setExtends(String name) {
156
extendsType = name;
157
return this;
158
}
159
160
/**
161
* Adds an implements declaration(s).
162
* @param names the interfaces
163
* @return this builder.
164
*/
165
public ClassBuilder addImplements(String... names) {
166
implementsTypes.addAll(List.of(names));
167
return this;
168
}
169
170
/**
171
* Adds a member(s) to the class declaration.
172
* @param mbs the member builder(s) representing member(s).
173
* @return this builder
174
*/
175
public ClassBuilder addMembers(MemberBuilder... mbs) {
176
for (MemberBuilder mb : mbs) {
177
members.add(mb);
178
mb.setClassName(fqn);
179
}
180
return this;
181
}
182
183
/**
184
* Adds nested-classes, to an outer class to an outer builder.
185
* @param cbs class builder(s) of the nested classes.
186
* @return this builder.
187
*/
188
public ClassBuilder addNestedClasses(ClassBuilder... cbs) {
189
Stream.of(cbs).forEach(cb -> {
190
nested.add(cb);
191
cb.setClassName(fqn);
192
});
193
return this;
194
}
195
196
/**
197
* Adds inner-classes, to an an outer class builder.
198
* @param cbs class builder(s) of the inner classes.
199
* @return this builder.
200
*/
201
public ClassBuilder addInnerClasses(ClassBuilder... cbs) {
202
Stream.of(cbs).forEach(cb -> {
203
inners.add(cb);
204
cb.setClassName(fqn);
205
});
206
return this;
207
}
208
209
@Override
210
public String toString() {
211
OutputWriter ow = new OutputWriter();
212
if (pkg != null)
213
ow.println("package " + pkg + ";");
214
imports.forEach(i -> ow.println("import " + i + ";"));
215
switch (comments.kind) {
216
case AUTO:
217
ow.println("/** Class " + fqn + " */");
218
break;
219
case USER:
220
ow.println("/** ");
221
comments.comments.forEach(c -> ow.println(" * " + c));
222
ow.println(" */");
223
break;
224
case NO_API_COMMENT:
225
ow.println("// NO_API_COMMENT");
226
break;
227
}
228
ow.print(modifiers.toString());
229
ow.print(clsname);
230
if (typeParameter != null) {
231
ow.print(typeParameter + " ");
232
} else {
233
ow.print(" ");
234
}
235
if (extendsType != null && !extendsType.isEmpty()) {
236
ow.print("extends " + extendsType + " ");
237
}
238
if (!implementsTypes.isEmpty()) {
239
ow.print("implements ");
240
241
ListIterator<String> iter = implementsTypes.listIterator();
242
while (iter.hasNext()) {
243
String s = iter.next() ;
244
ow.print(s);
245
if (iter.hasNext())
246
ow.print(", ");
247
}
248
}
249
ow.print("{");
250
if (!nested.isEmpty()) {
251
ow.println("");
252
nested.forEach(m -> ow.println(m.toString()));
253
}
254
255
if (!members.isEmpty()) {
256
ow.println("");
257
members.forEach(m -> ow.println(m.toString()));
258
}
259
260
ow.println("}");
261
if (!inners.isEmpty()) {
262
ow.println(" {");
263
inners.forEach(m -> ow.println(m.toString()));
264
ow.println("}");
265
}
266
return ow.toString();
267
}
268
269
/**
270
* Writes out the java source for a type element. Package directories
271
* will be created as needed as inferred by the type name.
272
* @param srcDir the top level source directory.
273
* @throws IOException if an error occurs.
274
*/
275
public void write(Path srcDir) throws IOException {
276
Files.createDirectories(srcDir);
277
Path outDir = srcDir;
278
if (pkg != null && !pkg.isEmpty()) {
279
String pdir = pkg.replace(".", "/");
280
outDir = Paths.get(srcDir.toString(), pdir);
281
Files.createDirectories(outDir);
282
}
283
Path filePath = Paths.get(outDir.toString(), clsname + ".java");
284
tb.writeFile(filePath, this.toString());
285
}
286
287
/**
288
* The member builder, this is the base class for all types of members.
289
*/
290
public static abstract class MemberBuilder extends AbstractBuilder {
291
public MemberBuilder(Modifiers modifiers, String name) {
292
super(modifiers, name);
293
}
294
295
/**
296
* Sets the enclosing type's name.
297
* @param className the enclosing type's name
298
*/
299
@Override
300
void setClassName(String className) {
301
cname = className;
302
}
303
304
/**
305
* Sets a comment for the element.
306
*
307
* @param comments for any element
308
* @return this builder.
309
*/
310
@Override
311
public MemberBuilder setComments(String... comments) {
312
super.setComments(comments);
313
return this;
314
}
315
316
/**
317
* Sets a comment for the element. Typically used to set user's
318
* preferences whether an automatic comment is required or no API
319
* comment.
320
*
321
* @param kind of comment, automatic or no comment.
322
* @return this builder.
323
*/
324
@Override
325
public MemberBuilder setComments(Comment.Kind kind) {
326
super.setComments(kind);
327
return this;
328
}
329
330
/**
331
* Sets a new modifier.
332
*
333
* @param modifiers
334
* @return this builder.
335
*/
336
@Override
337
public MemberBuilder setModifiers(String... modifiers) {
338
super.setModifiers(modifiers);
339
return this;
340
}
341
}
342
343
/**
344
* The field builder.
345
*/
346
public static class FieldBuilder extends MemberBuilder {
347
private String fieldType;
348
private String value;
349
350
private static final Pattern FIELD_RE = Pattern.compile("(.*)(\\s*=\\s*)(.*)(;)");
351
352
/**
353
* Constructs a field with the modifiers and name of the field.
354
* The builder by default is configured to auto generate the
355
* comments for the field.
356
* @param name of the field
357
*/
358
public FieldBuilder(String name) {
359
super(new Modifiers(), name);
360
this.comments = new Comment(Comment.Kind.AUTO);
361
}
362
363
/**
364
* Returns a field builder by parsing the string.
365
* ex: public static String myPlayingField;
366
* @param fieldString describing the field.
367
* @return a field builder.
368
*/
369
public static FieldBuilder parse(String fieldString) {
370
String prefix;
371
String value = null;
372
Matcher m = FIELD_RE.matcher(fieldString);
373
if (m.matches()) {
374
prefix = m.group(1).trim();
375
value = m.group(3).trim();
376
} else {
377
int end = fieldString.lastIndexOf(';') > 0
378
? fieldString.lastIndexOf(';')
379
: fieldString.length();
380
prefix = fieldString.substring(0, end).trim();
381
}
382
List<String> list = Stream.of(prefix.split(" "))
383
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
384
if (list.size() < 2) {
385
throw new IllegalArgumentException("incorrect field string: "
386
+ fieldString);
387
}
388
String name = list.get(list.size() - 1);
389
String fieldType = list.get(list.size() - 2);
390
391
FieldBuilder fb = new FieldBuilder(name);
392
fb.modifiers.setModifiers(list.subList(0, list.size() - 2));
393
fb.setFieldType(fieldType);
394
if (value != null)
395
fb.setValue(value);
396
397
return fb;
398
}
399
400
/**
401
* Sets the modifiers for this builder.
402
*
403
* @param mods
404
* @return this builder
405
*/
406
public FieldBuilder setModifiers(String mods) {
407
this.modifiers.setModifiers(mods);
408
return this;
409
}
410
411
/**
412
* Sets the type of the field.
413
* @param fieldType the name of the type.
414
* @return this field builder.
415
*/
416
public FieldBuilder setFieldType(String fieldType) {
417
this.fieldType = fieldType;
418
return this;
419
}
420
421
public FieldBuilder setValue(String value) {
422
this.value = value;
423
return this;
424
}
425
426
@Override
427
public String toString() {
428
String indent = " ";
429
OutputWriter ow = new OutputWriter();
430
switch (comments.kind) {
431
case AUTO:
432
ow.println(indent + "/** Field " +
433
super.name + " in " + super.cname + " */");
434
break;
435
case INHERIT_DOC: case USER:
436
ow.println(indent + "/** " +
437
comments.toString() + " */");
438
break;
439
case NO_API_COMMENT:
440
ow.println(indent + "// NO_API_COMMENT");
441
break;
442
}
443
ow.print(indent + super.modifiers.toString() + " ");
444
ow.print(fieldType + " ");
445
ow.print(super.name);
446
if (value != null) {
447
ow.print(" = " + value);
448
}
449
ow.println(";");
450
return ow.toString();
451
}
452
}
453
454
/**
455
* The method builder.
456
*/
457
public static class MethodBuilder extends MemberBuilder {
458
459
private final List<Pair> params;
460
461
private String returnType;
462
private List<String> body;
463
464
final static Pattern METHOD_RE = Pattern.compile("(.*)(\\()(.*)(\\))(.*)");
465
466
/**
467
* Constructs a method builder. The builder by default is configured
468
* to auto generate the comments for this method.
469
* @param name of the method.
470
*/
471
public MethodBuilder(String name) {
472
super(new Modifiers(), name);
473
comments = new Comment(Comment.Kind.AUTO);
474
params = new ArrayList<>();
475
body = null;
476
}
477
478
/**
479
* Returns a method builder by parsing a string which
480
* describes a method.
481
* @param methodString the method description.
482
* @return a method builder.
483
*/
484
public static MethodBuilder parse(String methodString) {
485
Matcher m = METHOD_RE.matcher(methodString);
486
if (!m.matches())
487
throw new IllegalArgumentException("string does not match: "
488
+ methodString);
489
String prefix = m.group(1);
490
String params = m.group(3);
491
String suffix = m.group(5).trim();
492
493
if (prefix.length() < 2) {
494
throw new IllegalArgumentException("incorrect method string: "
495
+ methodString);
496
}
497
498
String[] pa = prefix.split(" ");
499
List<String> list = List.of(pa);
500
String name = list.get(list.size() - 1);
501
String returnType = list.get(list.size() - 2);
502
503
MethodBuilder mb = new MethodBuilder(name);
504
mb.modifiers.setModifiers(list.subList(0, list.size() - 2));
505
mb.setReturn(returnType);
506
507
pa = params.split(",");
508
Stream.of(pa).forEach(p -> {
509
p = p.trim();
510
if (!p.isEmpty())
511
mb.addParameter(p);
512
});
513
if (!suffix.isEmpty() || suffix.length() > 1) {
514
mb.setBody(suffix);
515
}
516
return mb;
517
}
518
519
/**
520
* Sets the modifiers for this builder.
521
*
522
* @param modifiers
523
* @return this builder
524
*/
525
public MethodBuilder setModifiers(String modifiers) {
526
this.modifiers.setModifiers(modifiers);
527
return this;
528
}
529
530
@Override
531
public MethodBuilder setComments(String... comments) {
532
super.setComments(comments);
533
return this;
534
}
535
536
@Override
537
public MethodBuilder setComments(Comment.Kind kind) {
538
super.setComments(kind);
539
return this;
540
}
541
542
/**
543
* Sets a return type for a method.
544
* @param returnType the return type.
545
* @return this method builder.
546
*/
547
public MethodBuilder setReturn(String returnType) {
548
this.returnType = returnType;
549
return this;
550
}
551
552
/**
553
* Adds a parameter(s) to the method method builder.
554
* @param params a pair consisting of type and parameter name.
555
* @return this method builder.
556
*/
557
public MethodBuilder addParameters(Pair... params) {
558
this.params.addAll(List.of(params));
559
return this;
560
}
561
562
/**
563
* Adds a parameter to the method method builder.
564
* @param type the type of parameter.
565
* @param name the parameter name.
566
* @return this method builder.
567
*/
568
public MethodBuilder addParameter(String type, String name) {
569
this.params.add(new Pair(type, name));
570
return this;
571
}
572
573
/**
574
* Adds a parameter to the method builder, by parsing the string.
575
* @param s the parameter description such as "Double voltage"
576
* @return this method builder.
577
*/
578
public MethodBuilder addParameter(String s) {
579
String[] p = s.trim().split(" ");
580
return addParameter(p[0], p[p.length - 1]);
581
}
582
583
/**
584
* Sets the body of the method, described by the string.
585
* Such as "{", "double i = v/r;", "return i;", "}"
586
* @param body of the methods
587
* @return
588
*/
589
public MethodBuilder setBody(String... body) {
590
if (body == null) {
591
this.body = null;
592
} else {
593
this.body = new ArrayList<>();
594
this.body.addAll(List.of(body));
595
}
596
return this;
597
}
598
599
@Override
600
public String toString() {
601
OutputWriter ow = new OutputWriter();
602
String indent = " ";
603
switch (comments.kind) {
604
case AUTO:
605
ow.println(indent + "/** Method " + super.name + " in " + super.cname);
606
if (!params.isEmpty())
607
params.forEach(p -> ow.println(indent + " * @param " + p.second + " a param"));
608
if (returnType != null && !returnType.isEmpty() && !returnType.contains("void"))
609
ow.println(indent + " * @return returns something");
610
ow.println(indent + " */");
611
break;
612
case INHERIT_DOC: case USER:
613
ow.println(indent + "/** " + comments.toString() + " */");
614
break;
615
case NO_API_COMMENT:
616
ow.println(indent + "// NO_API_COMMENT");
617
break;
618
}
619
620
ow.print(indent + super.modifiers.toString() + " ");
621
ow.print(returnType + " ");
622
ow.print(super.name + "(");
623
if (!params.isEmpty()) {
624
ListIterator<Pair> iter = params.listIterator();
625
while (iter.hasNext()) {
626
Pair p = iter.next();
627
ow.print(p.first + " " + p.second);
628
if (iter.hasNext())
629
ow.print(", ");
630
}
631
}
632
ow.print(")");
633
if (body == null) {
634
ow.println(";");
635
} else {
636
body.forEach(ow::println);
637
}
638
return ow.toString();
639
}
640
}
641
642
//A sample, to test with an IDE.
643
// public static void main(String... args) throws IOException {
644
// ClassBuilder cb = new ClassBuilder(new ToolBox(), "foo.bar.Test<C extends A>");
645
// cb.addModifiers("public", "abstract", "static")
646
// .addImports("java.io").addImports("java.nio")
647
// .setComments("A comment")
648
// .addImplements("Serialization", "Something")
649
// .setExtends("java.lang.Object")
650
// .addMembers(
651
// FieldBuilder.parse("public int xxx;"),
652
// FieldBuilder.parse("public int yyy = 10;"),
653
// MethodBuilder.parse("public static void main(A a, B b, C c);")
654
// .setComments("CC"),
655
// MethodBuilder.parse("void foo(){//do something}")
656
//
657
// );
658
// ClassBuilder ic = new ClassBuilder(new ToolBox(), "IC");
659
// cb.addModifiers( "interface");
660
// cb.addNestedClasses(ic);
661
// System.out.println(cb.toString());
662
// cb.write(Paths.get("src-out"));
663
// }
664
}
665
666