Skip to content
Snippets Groups Projects
Commit db996077 authored by Jesper's avatar Jesper
Browse files

Add subtypes, improve member sorting

Duplicates are now preserved when sorting members.
parent d569c60c
No related branches found
No related tags found
No related merge requests found
...@@ -57,6 +57,7 @@ import java.util.Iterator; ...@@ -57,6 +57,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
public class JsonBuilder { public class JsonBuilder {
private Map<String, String> typeIndex = new HashMap<>(); private Map<String, String> typeIndex = new HashMap<>();
...@@ -65,6 +66,7 @@ public class JsonBuilder { ...@@ -65,6 +66,7 @@ public class JsonBuilder {
private Set<String> aspects = new HashSet<>(); private Set<String> aspects = new HashSet<>();
final Map<String, JsonArray> packages = new HashMap<>(); final Map<String, JsonArray> packages = new HashMap<>();
final Map<String, Collection<TypeDecl>> packageTypeMap = new HashMap<>(); final Map<String, Collection<TypeDecl>> packageTypeMap = new HashMap<>();
final Map<TypeDecl, Collection<TypeDecl>> subtypeMap = new HashMap<>();
/** Ordering of the package object kinds. */ /** Ordering of the package object kinds. */
private static final String[] TYPE_KINDS = { "ast-class", "interface", "class" }; private static final String[] TYPE_KINDS = { "ast-class", "interface", "class" };
...@@ -144,7 +146,7 @@ public class JsonBuilder { ...@@ -144,7 +146,7 @@ public class JsonBuilder {
} }
} }
private JsonValue typeRef(TypeDecl type) { private JsonObject typeRef(TypeDecl type) {
// TODO: handle wildcard types. // TODO: handle wildcard types.
JsonObject obj = new JsonObject(); JsonObject obj = new JsonObject();
if (shouldDocument(type)) { if (shouldDocument(type)) {
...@@ -201,6 +203,14 @@ public class JsonBuilder { ...@@ -201,6 +203,14 @@ public class JsonBuilder {
} }
// TODO: inner class names. // TODO: inner class names.
/**
* Generates a unique suffix that is used to distinguish duplicate typenames.
*
* @param type the type to generate a unique name suffix for.
* @return {@code "%"} if the given type has a unique typename, otherwise
* {@code "%ID"} where the ID part is a unique integer.
*/
String typeId(TypeDecl type) { String typeId(TypeDecl type) {
String typename = type.baseTypeName(); String typename = type.baseTypeName();
if (typeIndex.containsKey(typename)) { if (typeIndex.containsKey(typename)) {
...@@ -336,10 +346,12 @@ public class JsonBuilder { ...@@ -336,10 +346,12 @@ public class JsonBuilder {
ClassDecl klass = (ClassDecl) type; ClassDecl klass = (ClassDecl) type;
if (klass.hasSuperclass()) { if (klass.hasSuperclass()) {
obj.add("superclass", typeRef(klass.superclass())); obj.add("superclass", typeRef(klass.superclass()));
addSubtype(klass.superclass(), type);
} }
JsonArray ifaces = new JsonArray(); JsonArray ifaces = new JsonArray();
for (Access access: klass.getImplementsList()) { for (Access access: klass.getImplementsList()) {
ifaces.add(typeRef(access.type())); ifaces.add(typeRef(access.type()));
addSubtype(access.type(), type);
} }
if (!ifaces.isEmpty()) { if (!ifaces.isEmpty()) {
obj.add("superinterfaces", ifaces); obj.add("superinterfaces", ifaces);
...@@ -383,7 +395,20 @@ public class JsonBuilder { ...@@ -383,7 +395,20 @@ public class JsonBuilder {
} }
/** /**
* This adds inherited members from superclasses. * Registers subtype as being a subtype of type.
*/
private void addSubtype(TypeDecl type, TypeDecl subtype) {
type = type.original();
Collection<TypeDecl> subtypes = subtypeMap.get(type);
if (subtypes == null) {
subtypes = new HashSet<>();
subtypeMap.put(type, subtypes);
}
subtypes.add(subtype);
}
/**
* Adds inherited members from superclasses.
*/ */
private void addInheritedMembers(TypeDecl type, JsonObject obj) { private void addInheritedMembers(TypeDecl type, JsonObject obj) {
if (type instanceof ClassDecl) { if (type instanceof ClassDecl) {
...@@ -478,9 +503,16 @@ public class JsonBuilder { ...@@ -478,9 +503,16 @@ public class JsonBuilder {
if (groupMap.containsKey(kind)) { if (groupMap.containsKey(kind)) {
JsonObject group = new JsonObject(); JsonObject group = new JsonObject();
group.add("kind", Json.of(kind)); group.add("kind", Json.of(kind));
JsonArray members = groupMap.get(kind); JsonArray sortedMembers = new JsonArray();
sortArrayBy(members, "name"); KeyFun<JsonValue, String> keyFun = new KeyFun<JsonValue, String>() {
group.add("members", members); @Override public String apply(JsonValue value) {
return value.object().get("name").asString("");
}
};
for (JsonValue v : sortBy(groupMap.get(kind), keyFun)) {
sortedMembers.add(v);
}
group.add("members", sortedMembers);
groups.add(group); groups.add(group);
} }
} }
...@@ -489,7 +521,7 @@ public class JsonBuilder { ...@@ -489,7 +521,7 @@ public class JsonBuilder {
public JsonArray packageIndex() { public JsonArray packageIndex() {
// TODO: split into separate arrays based on object kind. // TODO: split into separate arrays based on object kind.
JsonArray packageIndex = new JsonArray(); List<JsonObject> packageIndex = new ArrayList<>();
for (String packageName : packages.keySet()) { for (String packageName : packages.keySet()) {
// Group members by kind. // Group members by kind.
Map<String, JsonArray> groupMap = new HashMap<>(); Map<String, JsonArray> groupMap = new HashMap<>();
...@@ -512,27 +544,62 @@ public class JsonBuilder { ...@@ -512,27 +544,62 @@ public class JsonBuilder {
entry.add("groups", groups); entry.add("groups", groups);
packageIndex.add(entry); packageIndex.add(entry);
} }
sortArrayBy(packageIndex, "name"); JsonArray sorted = new JsonArray();
return packageIndex; KeyFun<JsonObject, String> keyFun = new KeyFun<JsonObject, String>() {
@Override public String apply(JsonObject value) {
return value.object().get("name").asString("");
}
};
for (JsonValue v : sortBy(packageIndex, keyFun)) {
sorted.add(v);
}
return sorted;
}
public JsonArray subtypesJson(TypeDecl type) {
JsonArray subtypes = new JsonArray();
if (subtypeMap.containsKey(type)) {
KeyFun<TypeDecl, String> keyFun = new KeyFun<TypeDecl, String>() {
@Override public String apply(TypeDecl type) {
return type.name();
}
};
for (TypeDecl subtype : sortBy(subtypeMap.get(type), keyFun)) {
subtypes.add(typeRef(subtype));
}
}
return subtypes;
}
public interface KeyFun<T, R> {
R apply(T t);
} }
/** /**
* Sort object elements of JSON array by a particular key. * Returns a sorted JSON array based on the argument elements and a key function.
*
* <p>The result preserves duplicate elements and elements with identical keys.</p>
*/ */
static void sortArrayBy(JsonArray array, String key) { static <T, K extends Comparable<? super K>> List<T> sortBy(
Map<String, JsonObject> members = new HashMap<>(); Iterable<T> iterable,
for (JsonValue value : array) { KeyFun<T, K> keyFun) {
JsonObject member = value.object(); Map<K, Collection<T>> members = new TreeMap<>();
members.put(member.get(key).stringValue(""), member); for (T value : iterable) {
} K sortKey = keyFun.apply(value);
List<String> names = new ArrayList<>(members.keySet()); Collection<T> items = members.get(sortKey);
Collections.sort(names); if (items == null) {
int index = 0; items = new ArrayList<>();
for (String name : names) { members.put(sortKey, items);
JsonObject member = members.get(name); }
array.set(index, member); items.add(value);
index += 1; }
} List<K> keys = new ArrayList<>(members.keySet());
Collections.sort(keys);
ArrayList<T> result = new ArrayList<>(members.size());
for (Collection<T> values : members.values()) {
result.addAll(values);
}
return result;
} }
} }
...@@ -37,6 +37,7 @@ import org.extendj.ast.JavaParser; ...@@ -37,6 +37,7 @@ import org.extendj.ast.JavaParser;
import org.extendj.ast.Problem; import org.extendj.ast.Problem;
import org.extendj.ast.Program; import org.extendj.ast.Program;
import org.extendj.ast.TypeDecl; import org.extendj.ast.TypeDecl;
import se.llbit.json.JsonArray;
import se.llbit.json.JsonObject; import se.llbit.json.JsonObject;
import se.llbit.json.JsonValue; import se.llbit.json.JsonValue;
import se.llbit.json.PrettyPrinter; import se.llbit.json.PrettyPrinter;
...@@ -110,7 +111,10 @@ public class RagDocBuilder extends Frontend { ...@@ -110,7 +111,10 @@ public class RagDocBuilder extends Frontend {
for (Map.Entry<TypeDecl, JsonObject> entry : jsonBuilder.typemap.entrySet()) { for (Map.Entry<TypeDecl, JsonObject> entry : jsonBuilder.typemap.entrySet()) {
TypeDecl type = entry.getKey(); TypeDecl type = entry.getKey();
JsonObject typeJson = entry.getValue(); JsonObject typeJson = entry.getValue();
JsonBuilder.sortArrayBy(typeJson.get("members").array(), "name"); JsonArray subtypes = jsonBuilder.subtypesJson(type);
if (!subtypes.isEmpty()) {
typeJson.add("subtypes", jsonBuilder.subtypesJson(type));
}
String fileName = type.name() + jsonBuilder.typeId(type).substring(1) + ".json"; String fileName = type.name() + jsonBuilder.typeId(type).substring(1) + ".json";
outputJson(outputDir, fileName, typeJson); outputJson(outputDir, fileName, typeJson);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment