package org.rascalmpl.eclipse.editor; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.eclipse.core.resources.IProject; import org.rascalmpl.eclipse.Activator; import org.rascalmpl.eclipse.util.ProjectConfig; import org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.java2rascal.Java2Rascal; import org.rascalmpl.library.lang.rascal.boot.IKernel; import org.rascalmpl.library.util.PathConfig; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.INode; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; import io.usethesource.vallang.IWithKeywordParameters; import org.rascalmpl.values.ValueFactoryFactory; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; public class IDEServicesModelProvider { private final IValueFactory vf; private final IKernel kernel; private final Cache<ISourceLocation, IConstructor> useDefCache; private IDEServicesModelProvider() { try { vf = ValueFactoryFactory.getValueFactory(); kernel = Java2Rascal.Builder.bridge(vf, new PathConfig(), IKernel.class).build(); useDefCache = Caffeine.newBuilder().weakValues().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(32).build(); } catch (IOException e) { throw new RuntimeException(e); } } private static class InstanceHolder { static IDEServicesModelProvider sInstance = new IDEServicesModelProvider(); } public static IDEServicesModelProvider getInstance() { return InstanceHolder.sInstance; } @SuppressWarnings("unchecked") private <T extends IValue> T get(ISourceLocation file, PathConfig pcfg, String moduleName, String field, T def) { IConstructor summary = getSummary(file, pcfg, moduleName); if (summary != null) { IWithKeywordParameters<? extends IConstructor> kws = summary.asWithKeywordParameters(); if (kws.hasParameters()) { T val = (T) kws.getParameter(field); if (val != null) { return val; } } } return def; } public ISet getUseDef(ISourceLocation file, PathConfig pcfg, String moduleName) { return get(file, pcfg, moduleName, "useDef", vf.set()); } public IConstructor getSummary(ISourceLocation file, PathConfig pcfg, String moduleName) { IConstructor summary = useDefCache.getIfPresent(file); if (summary == null) { try { summary = kernel.makeSummary(vf.string(moduleName), pcfg.asConstructor(kernel)); if (summary.asWithKeywordParameters().hasParameters()) { // otherwise it is an empty model which we do not // want to cache. useDefCache.put(file, summary); } } catch (Throwable e) { Activator.log("failure to create summary for IDE features", e); } } return summary; } public INode getOutline(IConstructor module) { return kernel.outline(module); } public IConstructor getPathConfig(IProject project) { return new ProjectConfig(vf).getPathConfig(project).asConstructor(kernel); } public void clearUseDefCache(ISourceLocation file) { useDefCache.invalidate(file); } public void invalidateEverything() { useDefCache.invalidateAll(); } }