package kroppeb.stareval.function; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; public class FunctionResolver { private final Map>> functions; // TODO: instead of a suplier we could use an int->function to make varargs private final Map>>> dynamicFunctions; public FunctionResolver( Map>> functions, Map>>> dynamicFunctions) { this.functions = functions; this.dynamicFunctions = dynamicFunctions; } public List resolve(String name, Type returnType) { Map> normal = this.functions.get(name); Map>> dynamic = this.dynamicFunctions.get(name); List u = null; if (normal == null && dynamic == null) throw new RuntimeException("No such function: " + name); if (normal != null) u = normal.get(returnType); if (dynamic != null) { List> p = dynamic.get(returnType); if (p != null) { List uDynamic = p.stream().map(Supplier::get).collect(Collectors.toList()); if (u == null) { u = uDynamic; } else { List newU = new ArrayList<>(u.size() + uDynamic.size()); newU.addAll(u); newU.addAll(uDynamic); u = newU; } } } if (u == null) return Collections.emptyList(); return u; } public void logAllFunctions() { final Set names = new LinkedHashSet<>(); names.addAll(this.functions.keySet()); names.addAll(this.dynamicFunctions.keySet()); for (final String name : names) { final Map> overloads = new Object2ObjectLinkedOpenHashMap<>(); Map> normal = this.functions.get(name); if (normal != null) overloads.putAll(normal); Map>> dynamic = this.dynamicFunctions.get(name); if (dynamic != null) overloads.putAll( dynamic .entrySet() .stream() .collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue() .stream() .map(Supplier::get) .collect(Collectors.toList()) ) ) ); for (Map.Entry> returnTypeOverloads : overloads.entrySet()) { for (TypedFunction typedFunction : returnTypeOverloads.getValue()) { System.out.println(TypedFunction.format(typedFunction, name)); } System.out.println(); } System.out.println(); } } public static class Builder { private final Map> functions = new Object2ObjectLinkedOpenHashMap<>(); private final Map>>> dynamicFunctions = new Object2ObjectLinkedOpenHashMap<>(); public void add(String name, T function) { this.addFunction(name, function); } public void addDynamic(String name, Type returnType, Supplier function) { this.addDynamicFunction(name, returnType, function); } public void addDynamicFunction(String name, Type returnType, Supplier function) { this.dynamicFunctions .computeIfAbsent(name, (n) -> new Object2ObjectLinkedOpenHashMap<>()) .computeIfAbsent(returnType, (n) -> new ObjectArrayList<>()) .add(function); } public void addFunction(String name, TypedFunction function) { this.functions.computeIfAbsent(name, (n) -> new ObjectArrayList<>()).add(function); } public FunctionResolver build() { Map>> functions = new Object2ObjectLinkedOpenHashMap<>(); for (Map.Entry> entry : this.functions.entrySet()) { Map> typeMap = new Object2ObjectLinkedOpenHashMap<>(); for (TypedFunction function : entry.getValue()) { typeMap.computeIfAbsent(function.getReturnType(), i -> new ObjectArrayList<>()) .add(function); } functions.put(entry.getKey(), typeMap); } return new FunctionResolver(functions, this.dynamicFunctions); } } }