org.snapscript.core.link.ImportProcessor Maven / Gradle / Ivy
package org.snapscript.core.link;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.snapscript.common.Cache;
import org.snapscript.common.LazyBuilder;
import org.snapscript.common.LazyCache;
import org.snapscript.core.Context;
import org.snapscript.core.Entity;
import org.snapscript.core.NameChecker;
import org.snapscript.core.NameFormatter;
import org.snapscript.core.error.InternalStateException;
import org.snapscript.core.module.FilePathConverter;
import org.snapscript.core.module.Module;
import org.snapscript.core.module.Path;
import org.snapscript.core.module.PathConverter;
import org.snapscript.core.type.Type;
import org.snapscript.core.type.TypeLoader;
public class ImportProcessor implements ImportManager {
private final Map generics;
private final Map aliases;
private final Set imports;
private final ImportMatcher matcher;
private final EntityFinder finder;
private final Module parent;
private final String from;
private final String local;
public ImportProcessor(Module parent, Executor executor, Path path, String from, String local) {
this.generics = new ConcurrentHashMap();
this.aliases = new ConcurrentHashMap();
this.imports = new CopyOnWriteArraySet();
this.matcher = new ImportMatcher(parent, executor, path, from);
this.finder = new EntityFinder(parent);
this.parent = parent;
this.local = local;
this.from = from;
}
@Override
public void addImport(String prefix) {
imports.add(prefix);
}
@Override
public void addImport(String type, String alias) {
aliases.put(alias, type);
}
@Override
public void addImport(Type type, String alias) {
generics.put(alias, type);
}
@Override
public void addImports(Module module) {
ImportManager manager = module.getManager();
if(manager != null) {
Set types = aliases.keySet();
for(String type : types) {
String alias = aliases.get(type);
if(alias != null) {
manager.addImport(type, alias);
}
}
for(String value : imports) {
manager.addImport(value);
}
}
}
public Type getType(String name) throws Exception {
Future future = getImport(name); // import tetris.game.*
if(future != null) {
Entity entity = future.get();
if(Type.class.isInstance(entity)) {
return (Type)entity;
}
}
return null;
}
public Module getModule(String name) throws Exception {
Future future = getImport(name); // import tetris.game.*
if(future != null) {
Entity entity = future.get();
if(Module.class.isInstance(entity)) {
return (Module)entity;
}
}
return null;
}
@Override
public Future getImport(String name) {
return finder.find(name);
}
private class EntityFinder implements LazyBuilder> {
private final Cache> cache;
private final EntityResolver resolver;
private final NameFormatter formatter;
private final NameChecker filter;
public EntityFinder(Module parent) {
this.cache = new LazyCache>(this);
this.resolver = new EntityResolver(parent);
this.formatter = new NameFormatter();
this.filter = new NameChecker(true);
}
public Future find(String name) {
return cache.fetch(name);
}
@Override
public Future create(String name) {
try {
String inner = formatter.formatInnerName(name);
String origin = formatter.formatLocalName(name);
if(!filter.isEntity(inner)) {
return null;
}
if(!filter.isEntity(origin)) {
return null;
}
if(origin.equals(local)) {
return new ImportFuture(parent);
}
return resolver.resolve(name);
} catch(Exception e){
throw new InternalStateException("Could not find '" + name + "' in '" + from + "'", e);
}
}
}
private class EntityResolver {
private final ImportEntityResolver resolver;
private final PathConverter converter;
private final NameFormatter formatter;
public EntityResolver(Module parent) {
this.resolver = new ImportEntityResolver(parent);
this.converter = new FilePathConverter();
this.formatter = new NameFormatter();
}
public Future resolve(String name) throws Exception {
String origin = formatter.formatLocalName(name);
Future entity = resolveGeneric(name);
if(entity == null) {
entity = resolveImport(name);
}
if(entity == null) {
entity = resolveImport(origin);
}
if(entity == null) {
entity = resolveDefault(name);
}
if(entity == null) {
entity = resolveLocal(name);
}
return entity;
}
private Future resolveGeneric(String name) throws Exception{
Entity entity = generics.get(name);
if(entity != null) {
return new ImportFuture(entity);
}
return null;
}
private Future resolveImport(String name) throws Exception{
String alias = aliases.get(name);
int index = name.indexOf(".");
if(alias != null) {
String suffix = formatter.formatShortName(name);
String prefix = converter.createModule(alias);
Entity entity = resolver.resolveEntity(alias);
if(entity == null) {
entity = resolver.resolveEntity(prefix, suffix);
}
if(entity != null) {
return new ImportFuture(entity);
}
}
if(index == -1) {
for(String module : imports) {
Entity entity = resolver.resolveEntity(module, name); // this is "tetris.game.*"
if(entity != null) {
return new ImportFuture(entity);
}
}
}
return null;
}
private Future resolveLocal(String name) throws Exception{
Context context = parent.getContext();
TypeLoader loader = context.getLoader();
String origin = formatter.formatLocalName(name);
int index = name.indexOf(".");
if(index == -1) {
Entity entity = loader.loadType(from, name);
if(entity == null) {
Future future = matcher.matchImport(imports, origin);
if(name.endsWith(origin)) {
return (Future)future;
}
entity = loader.loadType(from, name);
}
if(entity != null) {
return new ImportFuture(entity);
}
}
return null;
}
private Future resolveDefault(String name) throws Exception{
Context context = parent.getContext();
TypeLoader loader = context.getLoader();
Entity entity = loader.loadType(null, name); // null is "java.*"
if(entity != null) {
return new ImportFuture(entity);
}
return null;
}
}
}