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;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class JsonBuilder {
private Map<String, String> typeIndex = new HashMap<>();
......@@ -65,6 +66,7 @@ public class JsonBuilder {
private Set<String> aspects = new HashSet<>();
final Map<String, JsonArray> packages = new HashMap<>();
final Map<String, Collection<TypeDecl>> packageTypeMap = new HashMap<>();
final Map<TypeDecl, Collection<TypeDecl>> subtypeMap = new HashMap<>();
/** Ordering of the package object kinds. */
private static final String[] TYPE_KINDS = { "ast-class", "interface", "class" };
......@@ -144,7 +146,7 @@ public class JsonBuilder {
}
}
private JsonValue typeRef(TypeDecl type) {
private JsonObject typeRef(TypeDecl type) {
// TODO: handle wildcard types.
JsonObject obj = new JsonObject();
if (shouldDocument(type)) {
......@@ -201,6 +203,14 @@ public class JsonBuilder {
}
// 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 typename = type.baseTypeName();
if (typeIndex.containsKey(typename)) {
......@@ -336,10 +346,12 @@ public class JsonBuilder {
ClassDecl klass = (ClassDecl) type;
if (klass.hasSuperclass()) {
obj.add("superclass", typeRef(klass.superclass()));
addSubtype(klass.superclass(), type);
}
JsonArray ifaces = new JsonArray();
for (Access access: klass.getImplementsList()) {
ifaces.add(typeRef(access.type()));
addSubtype(access.type(), type);
}
if (!ifaces.isEmpty()) {
obj.add("superinterfaces", ifaces);
......@@ -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) {
if (type instanceof ClassDecl) {
......@@ -478,9 +503,16 @@ public class JsonBuilder {
if (groupMap.containsKey(kind)) {
JsonObject group = new JsonObject();
group.add("kind", Json.of(kind));
JsonArray members = groupMap.get(kind);
sortArrayBy(members, "name");
group.add("members", members);
JsonArray sortedMembers = new JsonArray();
KeyFun<JsonValue, String> keyFun = new KeyFun<JsonValue, String>() {
@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);
}
}
......@@ -489,7 +521,7 @@ public class JsonBuilder {
public JsonArray packageIndex() {
// TODO: split into separate arrays based on object kind.
JsonArray packageIndex = new JsonArray();
List<JsonObject> packageIndex = new ArrayList<>();
for (String packageName : packages.keySet()) {
// Group members by kind.
Map<String, JsonArray> groupMap = new HashMap<>();
......@@ -512,27 +544,62 @@ public class JsonBuilder {
entry.add("groups", groups);
packageIndex.add(entry);
}
sortArrayBy(packageIndex, "name");
return packageIndex;
JsonArray sorted = new JsonArray();
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) {
Map<String, JsonObject> members = new HashMap<>();
for (JsonValue value : array) {
JsonObject member = value.object();
members.put(member.get(key).stringValue(""), member);
static <T, K extends Comparable<? super K>> List<T> sortBy(
Iterable<T> iterable,
KeyFun<T, K> keyFun) {
Map<K, Collection<T>> members = new TreeMap<>();
for (T value : iterable) {
K sortKey = keyFun.apply(value);
Collection<T> items = members.get(sortKey);
if (items == null) {
items = new ArrayList<>();
members.put(sortKey, items);
}
items.add(value);
}
List<String> names = new ArrayList<>(members.keySet());
Collections.sort(names);
int index = 0;
for (String name : names) {
JsonObject member = members.get(name);
array.set(index, member);
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;
import org.extendj.ast.Problem;
import org.extendj.ast.Program;
import org.extendj.ast.TypeDecl;
import se.llbit.json.JsonArray;
import se.llbit.json.JsonObject;
import se.llbit.json.JsonValue;
import se.llbit.json.PrettyPrinter;
......@@ -110,7 +111,10 @@ public class RagDocBuilder extends Frontend {
for (Map.Entry<TypeDecl, JsonObject> entry : jsonBuilder.typemap.entrySet()) {
TypeDecl type = entry.getKey();
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";
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