package org.rascalmpl.eclipse.library.lang.java.jdt.m3.internal; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.function.BiConsumer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTRequestor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.rascalmpl.interpreter.IEvaluatorContext; import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory; import org.rascalmpl.library.lang.java.m3.internal.LimitedTypeStore; import org.rascalmpl.uri.URIUtil; import io.usethesource.vallang.IBool; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISetWriter; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IString; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; import io.usethesource.vallang.type.TypeStore; public class EclipseJavaCompiler extends org.rascalmpl.library.lang.java.m3.internal.EclipseJavaCompiler { public EclipseJavaCompiler(IValueFactory vf) { super(vf); } public ISet createAstsFromEclipseProject(ISourceLocation root, IBool collectBindings, IBool errorRecovery, IEvaluatorContext ctx) { LimitedTypeStore store = getM3Store(ctx); ISetWriter result = VF.setWriter(); Map<String, ISourceLocation> cache = new HashMap<>(); compileAllFiles(root, collectBindings.getValue(), errorRecovery.getValue(), (loc, ast) -> { result.insert(convertToAST(collectBindings, cache, loc, ast, store)); }); return result.done(); } public ISet createM3sFromEclipseProject(ISourceLocation root, IBool errorRecovery, IEvaluatorContext ctx) { LimitedTypeStore store = getM3Store(ctx); ISetWriter result = VF.setWriter(); Map<String, ISourceLocation> cache = new HashMap<>(); compileAllFiles(root, true, errorRecovery.getValue(), (loc, ast) -> { result.insert(convertToM3(store, cache, loc, ast)); }); return result.done(); } public IValue createAstFromEclipseFile(ISourceLocation file, IBool collectBindings, IBool errorRecovery, IEvaluatorContext ctx) { LimitedTypeStore store = getM3Store(ctx); CompilationUnit cu = compileOneFile(file, collectBindings.getValue(), errorRecovery.getValue()); Map<String, ISourceLocation> cache = new HashMap<>(); return convertToAST(collectBindings, cache, file, cu, store); } public IValue createM3FromEclipseFile(ISourceLocation file, IBool errorRecovery, IEvaluatorContext ctx) { LimitedTypeStore store = getM3Store(ctx); CompilationUnit cu = compileOneFile(file, true, errorRecovery.getValue()); Map<String, ISourceLocation> cache = new HashMap<>(); return convertToM3(store, cache, file, cu); } private void compileAllFiles(ISourceLocation root, boolean collectBindings, boolean errorRecovery, BiConsumer<ISourceLocation, CompilationUnit> consumeCompiled) { IJavaProject project = getProject(root); ASTParser parser = constructASTParser(collectBindings, project, errorRecovery); parser.createASTs(getFiles(project), new String[0], new ASTRequestor() { @Override public void acceptAST(ICompilationUnit source, CompilationUnit ast) { consumeCompiled.accept(getLocation(root, project, source), ast); } }, null); } private CompilationUnit compileOneFile(ISourceLocation file, boolean collectBindings, boolean errorRecovery) { IJavaProject project = getProject(file); IJavaElement path; try { path = project.findElement(new Path(file.getPath())); if (path == null) { throw RuntimeExceptionFactory.io(VF.string("Could not find" + file), null, null); } if (path.getElementType() != IJavaElement.COMPILATION_UNIT) { throw RuntimeExceptionFactory.io(VF.string("" + file + "is not a compilation unit"), null, null); } } catch (JavaModelException e) { throw RuntimeExceptionFactory.io(VF.string("Could not find " + file), null, null); } ASTParser parser = constructASTParser(collectBindings, project, errorRecovery); CompilationUnit[] result = new CompilationUnit[] { null }; parser.createASTs(getFiles(project), new String[0], new ASTRequestor() { @Override public void acceptAST(ICompilationUnit source, CompilationUnit ast) { if (result[0] != null) { throw new RuntimeException("Got more than one AST?"); } result[0] = ast; } }, null); return result[0]; } protected ISourceLocation getLocation(ISourceLocation root, IJavaProject project, ICompilationUnit source) { try { return URIUtil.changePath(root, source.getPath().makeRelativeTo(project.getPath()).toString()); } catch (URISyntaxException e) { return URIUtil.invalidLocation(); } } private ICompilationUnit[] getFiles(IJavaProject project) { ArrayList<ICompilationUnit> result = new ArrayList<>(); try { for (IPackageFragmentRoot root : project.getAllPackageFragmentRoots()) { if (root.getKind() == IPackageFragmentRoot.K_SOURCE) { Queue<IParent> subDirs = new LinkedList<>(); subDirs.add(root); IParent currentEntry; while ((currentEntry = subDirs.poll()) != null) { for (IJavaElement child: currentEntry.getChildren()) { switch (child.getElementType()) { case IJavaElement.PACKAGE_FRAGMENT: case IJavaElement.PACKAGE_FRAGMENT_ROOT: subDirs.add((IParent)child); break; case IJavaElement.COMPILATION_UNIT: result.add((ICompilationUnit) child); break; } } } } } } catch (JavaModelException e) { return null; } return result.toArray(new ICompilationUnit[result.size()]); } public IJavaProject getProject(ISourceLocation root) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(root.getAuthority()); if (project == null || !project.isOpen()) { throw RuntimeExceptionFactory.io(VF.string("project " + root.getAuthority() + " could not be opened."), null, null); } return JavaCore.create(project); } protected ASTParser constructASTParser(boolean resolveBindings, IJavaProject project, boolean errorRecovery) { IString javaVersion = VF.string(project.getOption(JavaCore.COMPILER_COMPLIANCE, true)); ASTParser result = super.constructASTParser(resolveBindings, errorRecovery, javaVersion, null, null); result.setProject(project); return result; } }