package org.scribble.codegen.java.util; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; // An abstract type declaration builder public abstract class TypeBuilder extends JavaBuilder { protected String packname; // null for non- top-level type declaration protected final LinkedHashSet<String> imports = new LinkedHashSet<>(); protected final LinkedHashSet<String> mods = new LinkedHashSet<>(); protected final LinkedHashSet<String> ifaces = new LinkedHashSet<>(); protected final List<String> params = new LinkedList<>(); protected final List<FieldBuilder> fields = new LinkedList<>(); protected final List<MethodBuilder> methods = new LinkedList<>(); protected final List<TypeBuilder> topLevelTypes = new LinkedList<>(); protected final List<TypeBuilder> memberTypes = new LinkedList<>(); // No name par because so far useful to start constructing before setting the name public TypeBuilder() { } public TypeBuilder(String name) { super(name); } public void setPackage(String packname) { setterCheck(this.packname); this.packname = packname; } public void addImports(String... imports) { this.imports.addAll(Arrays.asList(imports)); } public void addModifiers(String... mods) { this.mods.addAll(Arrays.asList(mods)); } public void addInterfaces(String... ifaces) { this.ifaces.addAll(Arrays.asList(ifaces)); } public List<String> getInterfaces() { return new LinkedList<>(this.ifaces); } public void addParameters(String... params) { this.params.addAll(Arrays.asList(params)); } public List<String> getParameters() { return this.params; } public FieldBuilder newField(String name) { FieldBuilder fb = new FieldBuilder(); fb.setName(name); this.fields.add(fb); return fb; } public AbstractMethodBuilder newAbstractMethod() { AbstractMethodBuilder mb = new AbstractMethodBuilder(); this.methods.add(mb); return mb; } public final AbstractMethodBuilder newAbstractMethod(String name) { AbstractMethodBuilder mb = newAbstractMethod(); mb.setName(name); return mb; } // HACK: up to generic erasure public final void checkDuplicateMethods(MethodBuilder mb) { List<MethodBuilder> toRemove = new LinkedList<>(); X: for (MethodBuilder tmp : this.methods) { if (!tmp.equals(mb) && tmp.getReturn().equals(mb.getReturn())) { if (tmp.getParameters().size() == 0) { if (mb.getParameters().size() != 0) { continue X; } } else { Iterator<String> mbparams = mb.getParameters().iterator(); for (String tmpparam : tmp.getParameters()) { if (!mbparams.hasNext()) { continue X; } String mbparam = mbparams.next(); if (mbparam.contains("<")) { mbparam = mbparam.substring(0, mbparam.indexOf("<")); } else { mbparam = mbparam.substring(0, mbparam.indexOf(" ")); } if (tmpparam.contains("<")) { tmpparam = tmpparam.substring(0, tmpparam.indexOf("<")); } else { tmpparam = tmpparam.substring(0, tmpparam.indexOf(" ")); } if (!tmpparam.equals(mbparam)) { continue X; } } } toRemove.add(mb); } } this.methods.removeAll(toRemove); } public EnumBuilder newMemberEnum(String name) { EnumBuilder eb = new EnumBuilder(); eb.setName(name); this.memberTypes.add(eb); return eb; } public ClassBuilder newTopLevelClass() { ClassBuilder cb = new ClassBuilder(); this.topLevelTypes.add(cb); return cb; } // No validation here: javac is for that @Override public String build() { String clazz = ""; clazz = buildHeader(clazz); clazz = buildSignature(clazz); clazz = buildBody(clazz); clazz = buildTopLevelTypes(clazz); return clazz; } protected String buildBody(String clazz) { clazz += " {"; clazz = buildFields(clazz); clazz = buildMethods(clazz); clazz = buildMemberTypes(clazz); clazz += "\n}"; return clazz; } protected String buildHeader(String clazz) { if (this.packname != null) { clazz += "package " + packname + ";"; } if (!this.imports.isEmpty()) { clazz += "\n\nimport "; clazz += this.imports.stream().collect(Collectors.joining(";\nimport ")); clazz += ";"; } if (this.packname != null || !this.imports.isEmpty()) { clazz += "\n\n"; } return clazz; } protected abstract String buildSignature(String clazz); protected String buildFields(String clazz) { if (!this.fields.isEmpty()) { clazz += "\n"; clazz += this.fields.stream().map((fb) -> fb.build()).collect(Collectors.joining("\n")); } return clazz; } protected String buildMethods(String clazz) { if (!this.methods.isEmpty()) { clazz += "\n\n"; clazz += this.methods.stream().map((mb) -> mb.build()).collect(Collectors.joining("\n\n")); } return clazz; } protected String buildMemberTypes(String clazz) { if (!this.memberTypes.isEmpty()) { clazz += "\n\n"; clazz += this.memberTypes.stream().map((cb) -> cb.build()).collect(Collectors.joining("\n\n")); } return clazz; } protected String buildTopLevelTypes(String clazz) { if (!this.topLevelTypes.isEmpty()) { clazz += "\n\n"; clazz += this.topLevelTypes.stream().map((cb) -> cb.build()).collect(Collectors.joining("\n\n")); } return clazz; } }