org.snapscript.core.function.index.FunctionPathFinder Maven / Gradle / Ivy
package org.snapscript.core.function.index;
import static org.snapscript.core.type.Phase.DEFINE;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.snapscript.common.Progress;
import org.snapscript.core.EntityCache;
import org.snapscript.core.constraint.AnyConstraint;
import org.snapscript.core.constraint.Constraint;
import org.snapscript.core.convert.TypeInspector;
import org.snapscript.core.error.InternalStateException;
import org.snapscript.core.scope.Scope;
import org.snapscript.core.type.Phase;
import org.snapscript.core.type.Type;
public class FunctionPathFinder {
private final EntityCache> paths;
private final TypeInspector inspector;
private final Constraint any;
private final long wait;
public FunctionPathFinder() {
this(60000);
}
public FunctionPathFinder(long wait) {
this.paths = new EntityCache>();
this.inspector = new TypeInspector();
this.any = new AnyConstraint();
this.wait = wait;
}
public List findPath(Type type) {
List path = paths.fetch(type);
if(path == null) {
List result = new ArrayList();
findTypes(type, result);
paths.cache(type, result);
return result;
}
return path;
}
private void findTypes(Type type, List done) {
Progress progress = type.getProgress();
Scope scope = type.getScope();
Type base = any.getType(scope);
Class real = type.getType();
if(!progress.wait(DEFINE, wait)) {
throw new InternalStateException("Type '" + type +"' has not been defined");
}
findClasses(type, done);
if(real == null) {
findTraits(type, done);
}
done.add(base); // any is very last
}
private void findTraits(Type type, List done) {
List types = type.getTypes();
Iterator iterator = types.iterator();
if(iterator.hasNext()) {
Scope scope = type.getScope();
Constraint next = iterator.next(); // next in line, i.e base
while(iterator.hasNext()) {
Constraint trait = iterator.next();
Type match = trait.getType(scope);
if(!done.contains(match)) {
done.add(match);
}
}
Type match = next.getType(scope);
if(!done.contains(match)) {
findTraits(match, done);
}
}
}
private void findClasses(Type type, List done) {
List types = type.getTypes();
Iterator iterator = types.iterator();
Scope scope = type.getScope();
if(!inspector.isProxy(type) && !inspector.isAny(type)) {
done.add(type);
}
while(iterator.hasNext()) {
Constraint next = iterator.next();
Type match = next.getType(scope);
if(!done.contains(match)) {
findClasses(match, done);
}
}
}
}